ARM40-A5D27应用程序——SPI的用户态驱动(2)
2020.4.16
SPI的用户态驱动有两种方式,read/write 或者 ioctl().
read/write方式在同一时间只能read或write。如果要同时read和write,则需要用ioctl(Input Output Control).
本文是一个ioctl的例子。
一、例1
(1)SPI应用程序的C语言源码
文件名为 test_ad7193_mode.c,代码见附录(1)。
(2)交叉编译
arm-none-linux-gnueabi-gcc -o test_ad7193_mode test_ad7193_mode.c
(3)执行程序与测试
将交叉编译得到的test_ad7193_mode文件拷贝到ARM40-A5D27板中,执行程序:
./test_ad7193_mode
打印为:
root@A5D27:/home# ./test_ad7193_mode
AD7193_ID=0xa2
AD7193_STATUS=0x0
AD7193_MODE=0x8 0x0 0x60
AD7193_CONFIGURATION=0x0 0x1 0x16
对AD7193的手册对比:
参考文章:
Documentation/spi/spidev_test.c
《Linux Device Drivers Development: Develop customized drivers for embedded Linux》
《ARM40-A527应用程序——SPI的用户态驱动(1)》
荟聚计划:共商 共建 共享 Grant
附:
(1)test_ad7193_mode.c 的代码
#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>
static const char *device = "/dev/spidev0.0";
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
static int pabort(const char *s)
{
perror(s);
return -1;
}
static int spi_device_setup(int fd)
{
int mode, speed, a, b, i;
int bits = 8;
// set spi mode: mode 3
mode = SPI_MODE_3;
a = ioctl(fd, SPI_IOC_WR_MODE32, &mode); /* write mode */
b = ioctl(fd, SPI_IOC_RD_MODE32, &mode); /* read mode */
if ((a < 0) || (b < 0)) {
pabort("can't set spi mode\n");
}
// Clock max speed in Hz
speed = 1 * 1000 * 1000; /* 1 MHz */
a = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed); /* write speed */
b = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed); /* read speed */
if ((a < 0) || (b < 0)) {
pabort("Fail to set max speed hz\n");
}
/*
* setting SPI to MSB first
* Here, 0 means "not to use LSB first"
* In order to use LSB first, argument should be > 0
*/
i = 0;
a = ioctl(fd, SPI_IOC_WR_LSB_FIRST, &i);
b = ioctl(fd, SPI_IOC_RD_LSB_FIRST, &i);
if ((a < 0) || (b < 0)) {
pabort("Fail to set MSB first\n");
}
// setting SPI to 8 bits per word
bits = 8;
a = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
b = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
if ((a < 0) || (b < 0)) {
pabort("Fail to set bits per word\n");
}
}
int ad7193_reset(int fd)
{
int ret;
char tx[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
struct spi_ioc_transfer tr = {
.tx_buf = (unsigned long)tx,
.len = ARRAY_SIZE(tx),
};
ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
usleep(200*1000); // >70ms
return ret;
}
int ad7193_read_ID(int fd, void *rxbuf)
{
int ret;
char tx = 0x60; // read ID
struct spi_ioc_transfer tr[] = {
{
.tx_buf = (unsigned long)&tx,
.len = 1,
}, {
.rx_buf = (unsigned long)rxbuf,
.len = 1,
},
};
ret = ioctl(fd, SPI_IOC_MESSAGE(2), &tr);
return ret;
}
int ad7193_read_STATUS(int fd, void *rxbuf)
{
int ret;
char tx = 0x40; // read STATUS
struct spi_ioc_transfer tr[] = {
{
.tx_buf = (unsigned long)&tx,
.len = 1,
}, {
.rx_buf = (unsigned long)rxbuf,
.len = 1,
},
};
ret = ioctl(fd, SPI_IOC_MESSAGE(2), &tr);
return ret;
}
int ad7193_read_MODE(int fd, void *rxbuf)
{
int ret;
char tx = 0x48; // read MODE
struct spi_ioc_transfer tr[] = {
{
.tx_buf = (unsigned long)&tx,
.len = 1,
}, {
.rx_buf = (unsigned long)rxbuf,
.len = 3,
},
};
ret = ioctl(fd, SPI_IOC_MESSAGE(2), &tr);
return ret;
}
int ad7193_read_CONFIGURATION(int fd, void *rxbuf)
{
int ret;
char tx = 0x50; // read CONFIGURATION
struct spi_ioc_transfer tr[] = {
{
.tx_buf = (unsigned long)&tx,
.len = 1,
}, {
.rx_buf = (unsigned long)rxbuf,
.len = 3,
},
};
ret = ioctl(fd, SPI_IOC_MESSAGE(2), &tr);
return ret;
}
int main(int argc, char *argv[])
{
int ret = 0;
int fd;
char ad7193_reg[3];
fd = open(device, O_RDWR);
if (fd < 0)
pabort("can't open device");
ret = spi_device_setup(fd);
if(ret)
goto end;
ad7193_reset(fd);
ad7193_read_ID(fd, ad7193_reg);
printf("AD7193_ID=0x%x\n", ad7193_reg[0]);
ad7193_read_STATUS(fd, ad7193_reg);
printf("AD7193_STATUS=0x%x\n", ad7193_reg[0]);
ad7193_read_MODE(fd, ad7193_reg);
printf("AD7193_MODE=0x%x 0x%x 0x%x\n", ad7193_reg[0], ad7193_reg[1], ad7193_reg[2]);
ad7193_read_CONFIGURATION(fd, ad7193_reg);
printf("AD7193_CONFIGURATION=0x%x 0x%x 0x%x\n", ad7193_reg[0], ad7193_reg[1], ad7193_reg[2]);
end:
close(fd);
return 0;
}