beaglebone black的spi模块使用问题

beaglebone black的spi模块使用问题,c,linux-kernel,embedded,beagleboneblack,spi,C,Linux Kernel,Embedded,Beagleboneblack,Spi,我有以下奇怪的问题。 我已设置BBB以激活spi1模块。该模块连接到F-RAM芯片(FM25CL64B)。我已经完成了所有必要的配置。存在/dev/spidev1.0,我编写了一个小程序,通过打开/dev/spidev1.0并使用ioctl和SPI_IOC_MESSAGE宏命令来写入和读取芯片 使用该程序,我成功地将32字节的文本写入F-RAM芯片。阅读似乎也很成功。。。我怎么知道他们都成功了?我使用了一个激活了SPI解码器的逻辑分析仪来实际查看所有四条SPI线路上的情况。通过监视所有SPI线路

我有以下奇怪的问题。 我已设置BBB以激活spi1模块。该模块连接到F-RAM芯片(FM25CL64B)。我已经完成了所有必要的配置。存在/dev/spidev1.0,我编写了一个小程序,通过打开/dev/spidev1.0并使用ioctl和SPI_IOC_MESSAGE宏命令来写入和读取芯片


使用该程序,我成功地将32字节的文本写入F-RAM芯片。阅读似乎也很成功。。。我怎么知道他们都成功了?我使用了一个激活了SPI解码器的逻辑分析仪来实际查看所有四条SPI线路上的情况。通过监视所有SPI线路,我可以看到写入和读取操作以正确的时间生成正确的信号,并且所有信号都是同步的。CS在事务处理期间启用芯片,CLK对8位字(如配置)中的每个字节进行时钟计时,数据线显示正确的值,这要感谢SPI解码器,它在MOSI和MISO线的每个8位信号序列的正上方显示字节值

问题是,尽管我可以看到在读取操作期间通过MISO线发送了正确的信息,但我提供给ioctl的缓冲区(iSPIR、SPI_IOC_MESSAGE(2)、xfer)是用零填充的

我故意用其他值初始化该缓冲区,以便查看ioctl是否写入它。确实如此。零

现在,在读取操作期间,我可以看到通过MISO线发送的所有字节,这一事实证明,写入操作不仅在分析器中看起来正确,而且在上一次写入操作期间实际写入了预期的数据

我在dts文件(我可以根据需要重建和重新安装)中多次检查MISO线路是否配置正确。我检查了它的引脚是否正确,以及是否配置为输入。一切似乎都配置正确

我以root用户身份运行该程序,以防出现权限问题-没有区别

我还实现了GPIO模式下的spi通信。即spi模块被禁用,所有线路配置为GPIO。CE、CLK、MOSI配置为OTUPUT,MISO配置为输入。这样我就可以用软件实现整个通信,这样我就可以完全控制线路。这样做,这一次,我能够成功地用F-RAM芯片的正确数据填充缓冲区。也就是说,从F-RAM芯片一直到我的用户空间缓冲区,顺序读取操作正常。我能够将数据打印到控制台中。然而,这种方法太慢了。我还发现,当有一个模块可供使用时,使用SPI com的纯软件实现效率很低

为了编写示例程序,我使用了在线提供的spi_test.c开源示例。 我还构建并运行了spi_test.c本身,没有任何修改,结果是一样的

以下是我的程序列表(相关代码片段):


提前多谢!:)

我发现我的设置有什么问题。但是,尽管整个过程现在已经开始运作,但我应用的解决方案提出的问题比答案多

所以我在beaglebone wiki上的一篇文章()中找到了这个解决方案

在那里,我注意到,在设备树覆盖中,他们将CLK设置为输入。读了整篇文章,没有发现为什么BBBs端的时钟必须是一个输入。即使是主人。。。本文仅解释如何构建和安装新的DTBO以激活SPI1模块

所以,即使这对我来说没有任何意义,我想尝试将DTBO文件表单输出中的CLK行更改为输入,看看会发生什么,也不会有什么坏处。。。成功了!:O

现在,为什么设置会像这样工作呢。BBB应该是SPI主机,所以它的时钟线应该是一个输出,以便驱动这种同步通信。这意味着FM25CL64B芯片必须充当SPI从机。我刚刚检查了数据表,是的,芯片端的时钟是一个输入。因此,BBB上的CLK必须是一个输出。这就是我在BBB上配置CLK引脚的方式。作为输出。但它不起作用


这就是为什么我如此困惑。所以即使时钟线的两端都是输入,它也能工作?!查看逻辑分析仪的输出,我可以清楚地看到CLK线路的驱动是正确的。但是如果主设备和从设备都在这条线路上有输入,那么就不应该有任何东西产生这些脉冲了?!没有其他连接到该行的内容。…

“CLK以8位字(按配置)对每个字节进行时钟设置”并没有那么简单。除了波特率,SPI还有两个其他时钟设置:时钟极性(通常称为CPOL)和时钟相位(通常称为CPHA)。这些必须符合从机的要求,否则会出现“时钟偏移”,时钟只运行了一半,这反过来意味着SPI将在大部分时间工作,但偶尔会出现奇怪的间歇性错误。这是一个非常常见的问题,在逻辑分析仪上不容易发现。很抱歉没有提到这一点。CPHA和CPOL也已正确配置。正如您在initSpiredMode中看到的代码一样,我在那里设置了rd_mode=SPI_mode_0。它负责CPHA和CPOL。芯片本身可以在模式0和模式3下自动工作,无需配置。毕竟,如果不是这样,我就无法将数据写入芯片,然后再将其读回和类似于
rx_buf
,但这不是问题的原因,只是最佳实践。您对arrFRamData缓冲区的十六进制转储有一个注释。,如果这是您观察到数据全部为零的唯一方式,您要求我们相信您的调试代码是正确的。很可能是这样,但你应该把它包括在内,以防问题是有缺陷的检查,而不是检查
// SPI config ...

int InitSPIReadMode(const char* pstrDeviceF)
{
        int file;
        __u8  wr_mode = SPI_MODE_0, rd_mode = SPI_MODE_0, lsb = 0, bits = 8;
        __u32 speed = CLOCK_FREQ_HZ; // 500kHz

        if((file = open(pstrDeviceF, O_RDWR)) < 0)
        {
                printf("Failed to open the bus.");
                /* ERROR HANDLING; you can check errno to see what went wrong */
                exit(1);
        }
        if(ioctl(file, SPI_IOC_RD_MODE, &rd_mode) < 0)
        {
                printf("SPI rd_mode\n");
                return -1;
        }
        if(ioctl(file, SPI_IOC_RD_LSB_FIRST, &lsb) < 0)
        {
                printf("SPI rd_lsb_fist\n");
                return -1;
        }
        if(ioctl(file, SPI_IOC_RD_BITS_PER_WORD, &bits) < 0)
        {
                printf("SPI bits_per_word\n");
                return -1;
        }
        if(ioctl(file, SPI_IOC_RD_MAX_SPEED_HZ, &speed) < 0)
        {
                printf("SPI max_speed_hz\n");
                return -1;
        }
        printf("%s: spi wr-mode=%d, spi rd-mode=%d, %d bits per word, %s, %d Hz max\n", pstrDeviceF, wr_mode, rd_mode, bits, lsb ? "(lsb first) " : "(msb first)", speed);

        xfer[0].cs_change = 0; /* Keep CS activated */
        xfer[0].delay_usecs = 0; //delay in us
        xfer[0].speed_hz = CLOCK_FREQ_HZ; //speed
        xfer[0].bits_per_word = 8; // bites per word 8

        xfer[1].cs_change = 0; /* Keep CS activated */
        xfer[1].delay_usecs = 0;
        xfer[1].speed_hz = CLOCK_FREQ_HZ;
        xfer[1].bits_per_word = 8;

        return file;
}

                int iSPIR = InitSPIReadMode("/dev/spidev1.0"); //open("/dev/spidev1.0", O_RDWR | O_SYNC);

                char arrInstruct[3] = { OPCO_READ, 0x00, 0x00 };
                char arrFRamData[512];

                for(int pos = 0; pos < 512; pos++) arrFRamData[pos] = pos;

                xfer[0].tx_buf = (unsigned long)arrInstruct;
                xfer[0].len = 3;

                xfer[1].rx_buf = (unsigned long)arrFRamData;
                xfer[1].len = 32;

                if(ioctl(iSPIR, SPI_IOC_MESSAGE(2), xfer) < 0) printf("ioctl write error %s.\n", strerror(errno));

// hex dumping of the arrFRamData buffer.
struct spi_ioc_transfer xfer[2];