我正在努力学习如何编写一个基本的SPI驱动程序,下面是我编写的探测函数。
我在这里要做的是为fram(数据表)安装spi设备,并使用spi_sync_transfer()api描述从芯片中获取制造商的id。
当我执行这段代码时,我可以使用逻辑分析器在SPI总线上看到数据,但是我无法使用rx缓冲区读取它。我是不是漏掉了什么?有人能帮我吗?
static int fram_probe(struct spi_device *spi)
{
int err;
unsigned char ch16[] = {0x9F,0x00,0x00,0x00};// 0x9F => 10011111
unsigned char rx16[] = {0x00,0x00,0x00,0x00};
printk("[FRAM DRIVER] fram_probe called \n");
spi->max_speed_hz = 1000000;
spi->bits_per_word = 8;
spi->mode = (3);
err = spi_setup(spi);
if (err < 0) {
printk("[FRAM DRIVER::fram_probe spi_setup failed!\n");
return err;
}
printk("[FRAM DRIVER] spi_setup ok, cs: %d\n", spi->chip_select);
spi_element[0].tx_buf = ch16;
spi_element[1].rx_buf = rx16;
err = spi_sync_transfer(spi, spi_element, ARRAY_SIZE(spi_element)/2);
printk("rx16=%x %x %x %x\n",rx16[0],rx16[1],rx16[2],rx16[3]);
if (err < 0) {
printk("[FRAM DRIVER]::fram_probe spi_sync_transfer failed!\n");
return err;
}
return 0;
}发布于 2017-01-29 19:18:58
本例中没有声明spi_element。您应该展示这一点,以及如何填充数组中的所有元素。但从代码中我看到了一些错误。
您需要设置len参数的spi_transfer。您已经将TX或RX缓冲区分配给了ch16或rx16,但在这两种情况下都没有设置缓冲区的长度。
您应该将spi_transfer中未使用的所有字段归零。
如果将长度设置为4,则不会根据数据表发送正确的命令。RDID期望有一个字节的命令,然后是四个字节的输出数据。您正在第一次传输中编写一个四字节的命令,然后读取四个字节的数据。第一次传输中的tx_buf应该是一个字节。
最后,指定为spi_sync_transfer()的最后一个参数的传输数是不正确的。在本例中应该是2,因为您已经定义了两个,spi_element[0]和spi_element[1]。如果为此消息的目的声明了ARRAY_SIZE(),并且希望发送数组中的所有传输,则可以使用spi_element。
将此视为更好地填写spi_transfers的一种方法。它将负责对未使用的字段进行零化,以一种易于看到的方式定义传输,并在剩余代码中自动计算缓冲区大小或传输数量。
const char ch16[] = { 0x8f };
char rx16[4];
struct spi_transfer rdid[] = {
{ .tx_buf = ch16, .len = sizeof(ch16) },
{ .rx_buf = rx16, .len = sizeof(rx16) },
};
spi_transfer(spi, rdid, ARRAY_SIZE(rdid));由于您有一个范围,请确保此操作发生在单个芯片选择脉冲下。我发现不止一个Linux驱动程序有一个错误,当它不应该的时候,脉冲芯片会选择它。在某些情况下,从TX切换到RX (如上面所做的)将触发CS脉冲。在其他情况下,为数据的每一个字(此处8位)产生CS脉冲。
您应该更改的另一件事是使用dev_info(&spi->dev, "device version %d", id)'和dev_err()打印消息。这将以标准方式插入设备名称,而不是硬编码、非标准和不一致的“框架驱动程序:”文本。并酌情设置消息的级别。
此外,考虑在驱动程序中支持设备树来读取设备属性。然后,您可以为该设备更改SPI总线频率,而无需重新构建内核驱动程序。
https://stackoverflow.com/questions/41923285
复制相似问题