使用 beaglebone black spi 模块的问题
Problem utilizing spi module of beaglebone black
我有以下奇怪的问题。
我已经设置了 BBB 来激活 spi1 模块。该模块连接到 F-RAM 芯片 (FM25CL64B)。我已经完成了所有必要的配置。 /dev/spidev1.0 存在,我编写了一个小程序来写入和读取芯片,方法是打开 /dev/spidev1.0 并使用 ioctl 和 SPI_IOC_MESSAGE 宏命令。
使用该程序,我成功地将 32 字节的文本写入 F-RAM 芯片。阅读似乎也成功了……我怎么知道他们都成功了?我使用了一个激活了 SPI 解码器的逻辑分析仪来实际查看所有四个 SPI 线路上发生了什么。监控所有 SPI 线,我可以看到写入和读取操作以正确的时序生成正确的信号,并且所有信号都是同步的。 CS 在 t运行 动作期间启用芯片,CLK 以 8 位字的形式为每个字节计时(如配置),数据线显示正确的值,我可以看到,这要归功于显示字节的 SPI 解码器MOSI 和 MISO 线的每个 8 位信号序列正上方的值。
问题是,即使我可以看到在读取操作期间通过 MISO 行发送了正确的信息,我提供给 ioctl(iSPIR, SPI_IOC_MESSAGE(2), xfer) 的缓冲区已满带零。
我特意用其他值初始化了那个缓冲区,所以我可以看看 ioctl 是否写入了它。确实如此。零点。
现在,我可以看到在读取操作期间通过 MISO 线路发送的所有字节这一事实证明,写入操作不仅在分析器中看起来正确,而且实际上在之前的写入操作中写入了预期的数据。
我多次检查了 dts 文件中的 MISO 行是否配置正确(我可以根据需要重建和重新安装)。我检查了它是否是正确的引脚,以及它是否配置为输入。一切似乎都已正确配置。
我 运行 以 root 身份运行程序以防出现权限问题 - 没有区别。
我也实现了GPIO方式的spi通信。 IE。 spi 模块被禁用,所有线路配置为 GPIO。 CE、CLK、MOSI 配置为输出,MISO 配置为输入。这样我就可以在软件中实现整个通信,这样我就可以完全控制线路。这样做,这一次,我能够用来自 F-RAM 芯片的正确数据成功填充缓冲区。 IE。顺序读取操作从 F-RAM 芯片一直到我的用户 space 缓冲区都很顺利。我能够将数据打印到控制台中。但是,这工作太慢了。另外,我发现当有模块可用时,使用 SPI com 的纯软件实现效率很低。
为了编写示例程序,我使用了在线提供的 spi_test.c 开源示例。
我还构建了 运行 spi_test.c 本身,没有修改,结果相同。
这是我的程序清单(相关片段):
// 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;
}
在主要功能中:(因为逻辑分析仪显示此代码正确发送命令、地址并随后记录 32 字节数据)
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.
xfer 是一个全局变量,定义为:
struct spi_ioc_transfer xfer[2];
提前致谢! :)
我发现我的设置有什么问题。但即使现在一切正常,我应用的解决方案提出的问题多于答案。
所以我在 beaglebone wiki 上的一篇文章 (https://elinux.org/BeagleBone_Black_Enable_SPIDEV) 中找到了这个解决方案。
我注意到,在设备树覆盖图中,他们将 CLK 设置为输入。阅读整篇文章并没有发现为什么 BBB 端的 CLOCK 必须是输入。虽说是高手。。。文章只讲解如何搭建和安装新的DTBO以激活SPI1模块。
所以,尽管这对我来说没有任何意义,但我尝试将我的 DTBO 文件表单输出中的 CLK 行更改为输入以查看会发生什么并没有什么坏处......而且它起作用了! :O
现在,为什么这样的设置如此奇怪。 BBB 应该是 SPI 主机,因此它的时钟线应该是输出以驱动此同步通信。这意味着 FM25CL64B 芯片必须充当 SPI 从机。我刚刚检查了数据表,是的,芯片端的 CLK 是一个输入。所以 BBB 上的 CLK 一定是输出。这就是我在 BBB 上配置 CLK 引脚的方式。作为输出。而且它没有用。
这就是我百思不得其解的原因。所以即使 CLK 线的两端都是输入它也能工作?!查看逻辑分析仪的输出,我可以清楚地看到 CLK 线被正确驱动。但如果主人和奴隶都在那条线上输入,就不应该有任何东西产生这些冲动?!该线路没有其他连接....
我有以下奇怪的问题。 我已经设置了 BBB 来激活 spi1 模块。该模块连接到 F-RAM 芯片 (FM25CL64B)。我已经完成了所有必要的配置。 /dev/spidev1.0 存在,我编写了一个小程序来写入和读取芯片,方法是打开 /dev/spidev1.0 并使用 ioctl 和 SPI_IOC_MESSAGE 宏命令。
使用该程序,我成功地将 32 字节的文本写入 F-RAM 芯片。阅读似乎也成功了……我怎么知道他们都成功了?我使用了一个激活了 SPI 解码器的逻辑分析仪来实际查看所有四个 SPI 线路上发生了什么。监控所有 SPI 线,我可以看到写入和读取操作以正确的时序生成正确的信号,并且所有信号都是同步的。 CS 在 t运行 动作期间启用芯片,CLK 以 8 位字的形式为每个字节计时(如配置),数据线显示正确的值,我可以看到,这要归功于显示字节的 SPI 解码器MOSI 和 MISO 线的每个 8 位信号序列正上方的值。
问题是,即使我可以看到在读取操作期间通过 MISO 行发送了正确的信息,我提供给 ioctl(iSPIR, SPI_IOC_MESSAGE(2), xfer) 的缓冲区已满带零。
我特意用其他值初始化了那个缓冲区,所以我可以看看 ioctl 是否写入了它。确实如此。零点。
现在,我可以看到在读取操作期间通过 MISO 线路发送的所有字节这一事实证明,写入操作不仅在分析器中看起来正确,而且实际上在之前的写入操作中写入了预期的数据。
我多次检查了 dts 文件中的 MISO 行是否配置正确(我可以根据需要重建和重新安装)。我检查了它是否是正确的引脚,以及它是否配置为输入。一切似乎都已正确配置。
我 运行 以 root 身份运行程序以防出现权限问题 - 没有区别。
我也实现了GPIO方式的spi通信。 IE。 spi 模块被禁用,所有线路配置为 GPIO。 CE、CLK、MOSI 配置为输出,MISO 配置为输入。这样我就可以在软件中实现整个通信,这样我就可以完全控制线路。这样做,这一次,我能够用来自 F-RAM 芯片的正确数据成功填充缓冲区。 IE。顺序读取操作从 F-RAM 芯片一直到我的用户 space 缓冲区都很顺利。我能够将数据打印到控制台中。但是,这工作太慢了。另外,我发现当有模块可用时,使用 SPI com 的纯软件实现效率很低。
为了编写示例程序,我使用了在线提供的 spi_test.c 开源示例。 我还构建了 运行 spi_test.c 本身,没有修改,结果相同。
这是我的程序清单(相关片段):
// 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;
}
在主要功能中:(因为逻辑分析仪显示此代码正确发送命令、地址并随后记录 32 字节数据)
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.
xfer 是一个全局变量,定义为:
struct spi_ioc_transfer xfer[2];
提前致谢! :)
我发现我的设置有什么问题。但即使现在一切正常,我应用的解决方案提出的问题多于答案。
所以我在 beaglebone wiki 上的一篇文章 (https://elinux.org/BeagleBone_Black_Enable_SPIDEV) 中找到了这个解决方案。
我注意到,在设备树覆盖图中,他们将 CLK 设置为输入。阅读整篇文章并没有发现为什么 BBB 端的 CLOCK 必须是输入。虽说是高手。。。文章只讲解如何搭建和安装新的DTBO以激活SPI1模块。
所以,尽管这对我来说没有任何意义,但我尝试将我的 DTBO 文件表单输出中的 CLK 行更改为输入以查看会发生什么并没有什么坏处......而且它起作用了! :O
现在,为什么这样的设置如此奇怪。 BBB 应该是 SPI 主机,因此它的时钟线应该是输出以驱动此同步通信。这意味着 FM25CL64B 芯片必须充当 SPI 从机。我刚刚检查了数据表,是的,芯片端的 CLK 是一个输入。所以 BBB 上的 CLK 一定是输出。这就是我在 BBB 上配置 CLK 引脚的方式。作为输出。而且它没有用。
这就是我百思不得其解的原因。所以即使 CLK 线的两端都是输入它也能工作?!查看逻辑分析仪的输出,我可以清楚地看到 CLK 线被正确驱动。但如果主人和奴隶都在那条线上输入,就不应该有任何东西产生这些冲动?!该线路没有其他连接....