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