一. 简介
前面文章的学习,已经实现了 读写SPI设备中数据的功能。文章如下:
Linux下SPI设备驱动实验:验证读写SPI设备中数据的函数功能-CSDN博客
本文来使用内核提供的读写SPI设备中的数据的API函数,来实现读写SPI设备中数据。
二. Linux下SPI设备驱动实验:使用内核提供的读写SPI设备中的数据的函数
1. 内核提供的读写SPI设备中的数据的函数
所使用内核源码为NXP官方提供。读写SPI设备中的数据的函数所在内核源码路径为:
/linux-imx-rel_imx_4.1.15_2.1.0_ga/include/linux/spi/spi.h
(1) 读取SPI设备中数据的函数
spi_read函数
int spi_read(struct spi_device *spi, void *buf, size_t len)
spi_write_then_read函数
/* this copies txbuf and rxbuf data; for small transfers only! */
int spi_write_then_read(struct spi_device *spi, const void *txbuf, unsigned n_tx,
void *rxbuf, unsigned n_rx);
(2) 向SPI设备中写数据的函数
int spi_write(struct spi_device *spi, const void *buf, size_t len)
2. 使用内核提供的读写SPI设备中的数据的函数
这里的代码与前一篇文章相比,不同的是 读写SPI设备中数据的函数实现。
读写SPI设备中数据的函数实现如下(spi_icm20608.c文件中):
static int spi_write_regs(struct icm20608_Dev* dev, u8 reg_addr, void* buf, int len)
{
int ret = 0;
unsigned char value = 0;
struct spi_device* spi_dev = (struct spi_device*)dev->private_data;
value = reg_addr & ~0x80; //最高为位清0(写标志位)
//发送要写入的寄存器地址
ret = spi_write(spi_dev, &value, 1);
if(ret)
printk("spi_write_regs: spi_write reg_addr error\n");
//发送要写入SPI设备中的数据
ret = spi_write(spi_dev, buf, len);
if(ret)
printk("spi_write_regs: spi_write data error\n");
return ret;
}
static int spi_read_regs(struct icm20608_Dev* dev, u8 reg_addr, void* buf, int len)
{
int ret = 0;
unsigned char value = 0;
struct spi_device* spi_dev = (struct spi_device*)dev->private_data;
value = reg_addr | 0x80; //最高为置1(读标志位)
#if 0 //发送要读取的寄存器的地址
ret = spi_write(spi_dev, &value, 1);
if(ret < 0)
printk("spi_read_regs: spi_write reg_addr error\n");
//接收SPI设备中的数据
ret = spi_read(spi_dev, buf, len);
if(ret)
printk("spi_read_regs: spi_read data error\n");
#endif
spi_write_then_read(spi_dev, &value, 1, buf, len);
return ret;
}
/*ICM20608设备初始化(即SPI设备初始化)*/
static int icm20608_register_init(struct icm20608_Dev* dev)
{
unsigned char value = 0;
spi_write_reg_onebyte(&icm20608_dev, ICM20_PWR_MGMT_1, 0x80); /*复位,复位后为0x40,睡眠模式 */
mdelay(50);
spi_write_reg_onebyte(&icm20608_dev, ICM20_PWR_MGMT_1, 0x01); /*关闭睡眠,自动选择时钟 */
mdelay(50);
value = spi_read_reg_onebyte(&icm20608_dev,ICM20_WHO_AM_I);
printk("ICM20_WHO_AM_I: 0x%02X\r\n", value);
if((value != ICM20608G_ID) && (value != ICM20608D_ID))
{
return 1;
}
value = spi_read_reg_onebyte(&icm20608_dev,ICM20_PWR_MGMT_1);
printk("ICM20_PWR_MGMT_1: 0x%02X\r\n", value);
return 0;
}
可以看出,读SPI设备中数据的实现函数中,有一段屏蔽的代码段,如下代码段:
ret = spi_write(spi_dev, &value, 1);
if(ret < 0)
printk("spi_read_regs: spi_write reg_addr error\n");
//接收SPI设备中的数据
ret = spi_read(spi_dev, buf, len);
if(ret)
printk("spi_read_regs: spi_read data error\n");
这里先写了SPI设备的寄存器地址,然后从SPI设备中读取数据。
经过测试,这段代码最后 SPI读取数据是不对的,也就是存在问题。正点原子的左神说是,可能的原因是 在发送寄存器地址前片选信号是拉低的,之后片选信号拉高了,然后在从SPI深圳中读取数据前,片选信号再拉低。这样导致时序混乱。
所以,这里从SPI设备中读取数据调用了 spi_write_then_read函数,不过根据该函数的注释信息,说这个函数只适用于小数量的数据传输!
三. 测试
将 编译的驱动进行编译后,将新生成的驱动模块拷贝到开发板系统中,加载驱动模块如下:
可以看出,寄存器ICM20_PWR_MGMT_1在 ICM20608初始化函数中最后写入了0x01,这里读出来也是 0x01,确定读写SPI设备函数运行正常。
卸载模块:
卸载驱动模块时, remove函数也运行了,也不存在错误的信息。