SPI linux驱动程序

时间:2017-01-29 16:40:32

标签: linux linux-kernel linux-device-driver raspberry-pi2 spi

我正在尝试学习如何编写基本的SPI驱动程序,下面是我编写的探测函数。

我在这里要做的是设置fram(datasheet)的spi设备,并使用spi_sync_transfer() api description从芯片中获取制造商的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;
}

1 个答案:

答案 0 :(得分:1)

在此示例中未声明

spi_element。您应该显示它以及如何填充该数组的所有元素。但是从那里的代码中我发现了一些错误。

您需要设置len的{​​{1}}参数。您已将TX或RX缓冲区分配给spi_transferch16,但无论如何都不设置缓冲区的长度。

您应该清除rx16中未使用的所有字段。

如果将长度设置为4,则根据数据表不会发送正确的命令。 RDID需要一个一个字节命令,之后将跟随四个字节的输出数据。您正在第一次传输中写入字节命令,然后读取四个字节的数据。第一次传输中的tx_buf应该只是一个字节。

最后指定为spi_transfer的最后一个参数的传输次数不正确。在这种情况下,它应该是2,因为您已定义了两个,spi_sync_transfer()spi_element[0]。如果为此消息的目的声明了spi_element并且您想要发送数组中的所有传输,则可以使用spi_element[1]

将此视为更好地填写ARRAY_SIZE()的方法。它将处理未使用的字段,以易于查看的方式定义传输,并在剩余代码中自动考虑更改缓冲区大小或传输次数。

spi_transfers

由于您有示波器,请务必检查此操作是否在单个芯片选择脉冲下发生。我找到了一个以上的Linux SPI驱动程序,它有一个错误,当它不应该选择脉冲芯片时。在某些情况下,从TX切换到RX(如上所述)将触发CS脉冲。在其他情况下,为每个字(此处为8位)生成CS脉冲。

您应该更改的另一件事是使用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)); dev_info(&spi->dev, "device version %d", id)'来打印邮件。这将以标准方式插入设备名称,而不是硬编码的非标准和不一致的“[FRAME DRIVER] ::”文本。并根据需要设置消息的级别。

另外,请考虑在驱动程序中支持设备树以读取设备属性。然后,您可以执行更改此设备的SPI总线频率而无需重建内核驱动程序。