接收到的数据在遇到第一个字节等于零后清零
Received Data Zeroed Out After Encountering First Byte Equal to Zero
- 总结问题:
我在 linux 中为 NRF24L01+ 收发器编写了一个用户空间 SPI 驱动程序。我的目标是将文件发送到服务器。 jetson nano 是发送者,raspberry pi 3b+ 是接收者。 spi 和 nano 都是 运行 Linux.
我可以始终如一地发送数据包和接收确认。
但是,问题是每当我发送 0x ff ee dd 00 cc bb aa
等数据包时,接收方只收到数据包 0x ff ee dd 00 00 00 00
。所以发生的事情是,只要遇到的第一个字节为零,数据包的其余部分就会变为零。这会导致我发送的文件损坏。
我能够使用具有类似模式的字符数组重现此错误。当我打印出我在发送器和接收器上发送的文件内容时,我注意到了这种趋势。
- 我尝试过的:
我试过更改我的 SPI 读取功能。我认为正在发生的事情是筹码 select 线被提早翻转了。这没有用,我得到了相同的结果。
我在从发送器调用 ioctl()
函数之前打印了数据包,数据包保持完好无损。
我打印了 ioctl()
函数的 return 值,以查看我接收和发送了多少字节。我从发送器发送 31 个字节,从接收器接收 32 个字节。所以看起来我的读取和发送没有失败。
如果我有逻辑分析仪,我的下一步将是检查发送器上的 SPI 引脚,但遗憾的是我没有。
我在收发器上添加了一个 10uF 去耦电容器,这加快了通信速度。
- 显示一些代码:
接收方:
/**
* Reads the payload when data pipe
* is available.
*
* spi_dev_fd: file descriptor for spi device.
* */
int nrf_rx_read(int spi_dev_fd, char * payload, int * pipe, int * bytes)
{
int pipe_temp, rtn;
// TODO: Add timeout.
do
{
rtn = nrf_rx_pipe_available(spi_dev_fd, &pipe_temp);
}while(rtn != 0);
if(rtn == 0)
{
char status;
if(bytes != NULL)
{
char size;
spi_read_msg(spi_dev_fd, R_RX_PL_WID, &status, &size, 1);
*bytes = (int) size;
}
spi_read_msg(spi_dev_fd, R_RX_PAYLOAD , &status, payload, (int) NUM_PAYLOAD_BYTES);
*pipe = pipe_temp;
char msg;
msg = RX_DR;
spi_send_msg(spi_dev_fd, W_REGISTER | STATUS, &msg, 1);
return 0;
}
return 1;
}
bool nrf_rx_pipe_available(int spi_dev_fd, int * pipe)
{
char addr = NOP;
char status;
spi_read_msg(spi_dev_fd, addr, &status, NULL, 0);
if((status & RX_DR) > 0)
{
*pipe = (status >> RX_P_NO) & 0x07;
if(*pipe > 5)
{
return 1;
}
return 0;
}
return 1;
}
int spi_read_msg(int spi_dev_fd, char addr, char * status, char * copy_to, int len)
{
char data_buffer;
char recv_buffer[len + 1];
struct spi_ioc_transfer xfer;
memset(&xfer, 0, sizeof(xfer));
memset(&recv_buffer, 0, sizeof(recv_buffer));
data_buffer = addr;
xfer.tx_buf = (unsigned long) &data_buffer;
xfer.rx_buf = (unsigned long) recv_buffer;
xfer.len = len + 2;
xfer.bits_per_word = 8;
xfer.speed_hz = 1000000;
xfer.cs_change = 0;
xfer.rx_nbits = len * 8;
xfer.tx_nbits = 8;
int res = ioctl(spi_dev_fd, SPI_IOC_MESSAGE(1), xfer);
if(res > 0)
{
status[0] = recv_buffer[0];
if(copy_to != NULL)
{
string temp = string(recv_buffer);
temp = temp.substr(1);
strncpy(copy_to, temp.c_str(), len);
}
// debug code
for(int i = 0; i < len; ++i)
{
printf("copy_to: %x \n ", copy_to[i]);
}
// end debug code.
}
return res;
}
发射端:
/**
* Function to load a payload and send a packet.
*
*
* spi_dev_fd: file descriptor for spi device.
* */
int nrf_tx_send_packet(int spi_dev_fd, char * payload, int len)
{
int rtn;
// Put low so we can add the payload.
gpio_set_value((unsigned int) GPIO_CE, (unsigned int) GPIO_LVL_LOW);
// Set a new payload.
nrf_tx_new_payload(spi_dev_fd, payload, len);
// Start tx transmission.
gpio_set_value((unsigned int) GPIO_CE, (unsigned int) GPIO_LVL_HIGH);
do
{
rtn = nrf_tx_pending_send(spi_dev_fd);
if(rtn == 2)
{
char clr = MAX_RT;
spi_send_msg(spi_dev_fd, W_REGISTER | STATUS, &clr, 1);
}
}while(rtn != 1);
// Go back to standby mode
gpio_set_value((unsigned int) GPIO_CE, (unsigned int) GPIO_LVL_LOW); // Setting chip enable to 0.
char reg = W_REGISTER | STATUS;
char val = RX_DR | TX_DS | MAX_RT;
spi_send_msg(spi_dev_fd, reg, &val, 1);
return 0;
}
int spi_send_msg(int spi_dev_fd, char addr, char * data, int len)
{
char data_buffer[len + 1];
char recv_buffer;
struct spi_ioc_transfer xfer;
memset(&xfer, 0, sizeof(xfer));
memset(&recv_buffer, 0, sizeof(recv_buffer));
data_buffer[0] = addr;
for(int i = 1; i < len + 1; ++i)
{
data_buffer[i] = data[i-1];
printf("databuffer[i]: %x \n", data_buffer[i]);
}
xfer.tx_buf = (unsigned long) data_buffer;
xfer.rx_buf = (unsigned long) NULL;
xfer.len = len + 1;
xfer.bits_per_word = 8;
xfer.speed_hz = 1000000;
xfer.cs_change = 0;
//xfer.rx_nbits = 8;
xfer.rx_nbits = 0;
xfer.tx_nbits = (8 * len) + 8;
int res = ioctl(spi_dev_fd, SPI_IOC_MESSAGE(1), xfer);
printf("res: %i \n", res);
return res;
}
我试着添加了所有相关代码,如果有点多请见谅。主要看的是发送和接收函数。它们都按预期工作,直到我遇到清零字节。
如果我遗漏了任何可以帮助某人的信息,请告诉我,我可以添加。然而,我认为发送和接收功能是最重要的。我能够设置和读取收发器的寄存器。
我现在可以发送文件了!
已在 spi_read_msg()
函数中完成修复。
问题是我将接收到的缓冲区转换为字符串,这导致在遇到字节 0x00
时数据被修剪。这也等同于空终止符。
收件人代码:
int spi_read_msg(int spi_dev_fd, char addr, char * status, char * copy_to, int len)
{
char data_buffer;
char recv_buffer[len + 1];
struct spi_ioc_transfer xfer;
memset(&xfer, 0, sizeof(xfer));
memset(&recv_buffer, 0, sizeof(recv_buffer));
data_buffer = addr;
xfer.tx_buf = (unsigned long) &data_buffer;
xfer.rx_buf = (unsigned long) recv_buffer;
xfer.len = len + 2;
xfer.bits_per_word = 8;
xfer.speed_hz = 1000000;
xfer.cs_change = 0;
xfer.rx_nbits = len * 8;
xfer.tx_nbits = 8;
int res = ioctl(spi_dev_fd, SPI_IOC_MESSAGE(1), xfer);
if(res > 0)
{
status[0] = recv_buffer[0];
if(copy_to != NULL)
{
for(int i = 0; i < len; ++i)
{
copy_to[i] = recv_buffer[i + 1];
}
}
}
return res;
}
- 总结问题:
我在 linux 中为 NRF24L01+ 收发器编写了一个用户空间 SPI 驱动程序。我的目标是将文件发送到服务器。 jetson nano 是发送者,raspberry pi 3b+ 是接收者。 spi 和 nano 都是 运行 Linux.
我可以始终如一地发送数据包和接收确认。
但是,问题是每当我发送 0x ff ee dd 00 cc bb aa
等数据包时,接收方只收到数据包 0x ff ee dd 00 00 00 00
。所以发生的事情是,只要遇到的第一个字节为零,数据包的其余部分就会变为零。这会导致我发送的文件损坏。
我能够使用具有类似模式的字符数组重现此错误。当我打印出我在发送器和接收器上发送的文件内容时,我注意到了这种趋势。
- 我尝试过的:
我试过更改我的 SPI 读取功能。我认为正在发生的事情是筹码 select 线被提早翻转了。这没有用,我得到了相同的结果。
我在从发送器调用 ioctl()
函数之前打印了数据包,数据包保持完好无损。
我打印了 ioctl()
函数的 return 值,以查看我接收和发送了多少字节。我从发送器发送 31 个字节,从接收器接收 32 个字节。所以看起来我的读取和发送没有失败。
如果我有逻辑分析仪,我的下一步将是检查发送器上的 SPI 引脚,但遗憾的是我没有。
我在收发器上添加了一个 10uF 去耦电容器,这加快了通信速度。
- 显示一些代码:
接收方:
/**
* Reads the payload when data pipe
* is available.
*
* spi_dev_fd: file descriptor for spi device.
* */
int nrf_rx_read(int spi_dev_fd, char * payload, int * pipe, int * bytes)
{
int pipe_temp, rtn;
// TODO: Add timeout.
do
{
rtn = nrf_rx_pipe_available(spi_dev_fd, &pipe_temp);
}while(rtn != 0);
if(rtn == 0)
{
char status;
if(bytes != NULL)
{
char size;
spi_read_msg(spi_dev_fd, R_RX_PL_WID, &status, &size, 1);
*bytes = (int) size;
}
spi_read_msg(spi_dev_fd, R_RX_PAYLOAD , &status, payload, (int) NUM_PAYLOAD_BYTES);
*pipe = pipe_temp;
char msg;
msg = RX_DR;
spi_send_msg(spi_dev_fd, W_REGISTER | STATUS, &msg, 1);
return 0;
}
return 1;
}
bool nrf_rx_pipe_available(int spi_dev_fd, int * pipe)
{
char addr = NOP;
char status;
spi_read_msg(spi_dev_fd, addr, &status, NULL, 0);
if((status & RX_DR) > 0)
{
*pipe = (status >> RX_P_NO) & 0x07;
if(*pipe > 5)
{
return 1;
}
return 0;
}
return 1;
}
int spi_read_msg(int spi_dev_fd, char addr, char * status, char * copy_to, int len)
{
char data_buffer;
char recv_buffer[len + 1];
struct spi_ioc_transfer xfer;
memset(&xfer, 0, sizeof(xfer));
memset(&recv_buffer, 0, sizeof(recv_buffer));
data_buffer = addr;
xfer.tx_buf = (unsigned long) &data_buffer;
xfer.rx_buf = (unsigned long) recv_buffer;
xfer.len = len + 2;
xfer.bits_per_word = 8;
xfer.speed_hz = 1000000;
xfer.cs_change = 0;
xfer.rx_nbits = len * 8;
xfer.tx_nbits = 8;
int res = ioctl(spi_dev_fd, SPI_IOC_MESSAGE(1), xfer);
if(res > 0)
{
status[0] = recv_buffer[0];
if(copy_to != NULL)
{
string temp = string(recv_buffer);
temp = temp.substr(1);
strncpy(copy_to, temp.c_str(), len);
}
// debug code
for(int i = 0; i < len; ++i)
{
printf("copy_to: %x \n ", copy_to[i]);
}
// end debug code.
}
return res;
}
发射端:
/**
* Function to load a payload and send a packet.
*
*
* spi_dev_fd: file descriptor for spi device.
* */
int nrf_tx_send_packet(int spi_dev_fd, char * payload, int len)
{
int rtn;
// Put low so we can add the payload.
gpio_set_value((unsigned int) GPIO_CE, (unsigned int) GPIO_LVL_LOW);
// Set a new payload.
nrf_tx_new_payload(spi_dev_fd, payload, len);
// Start tx transmission.
gpio_set_value((unsigned int) GPIO_CE, (unsigned int) GPIO_LVL_HIGH);
do
{
rtn = nrf_tx_pending_send(spi_dev_fd);
if(rtn == 2)
{
char clr = MAX_RT;
spi_send_msg(spi_dev_fd, W_REGISTER | STATUS, &clr, 1);
}
}while(rtn != 1);
// Go back to standby mode
gpio_set_value((unsigned int) GPIO_CE, (unsigned int) GPIO_LVL_LOW); // Setting chip enable to 0.
char reg = W_REGISTER | STATUS;
char val = RX_DR | TX_DS | MAX_RT;
spi_send_msg(spi_dev_fd, reg, &val, 1);
return 0;
}
int spi_send_msg(int spi_dev_fd, char addr, char * data, int len)
{
char data_buffer[len + 1];
char recv_buffer;
struct spi_ioc_transfer xfer;
memset(&xfer, 0, sizeof(xfer));
memset(&recv_buffer, 0, sizeof(recv_buffer));
data_buffer[0] = addr;
for(int i = 1; i < len + 1; ++i)
{
data_buffer[i] = data[i-1];
printf("databuffer[i]: %x \n", data_buffer[i]);
}
xfer.tx_buf = (unsigned long) data_buffer;
xfer.rx_buf = (unsigned long) NULL;
xfer.len = len + 1;
xfer.bits_per_word = 8;
xfer.speed_hz = 1000000;
xfer.cs_change = 0;
//xfer.rx_nbits = 8;
xfer.rx_nbits = 0;
xfer.tx_nbits = (8 * len) + 8;
int res = ioctl(spi_dev_fd, SPI_IOC_MESSAGE(1), xfer);
printf("res: %i \n", res);
return res;
}
我试着添加了所有相关代码,如果有点多请见谅。主要看的是发送和接收函数。它们都按预期工作,直到我遇到清零字节。
如果我遗漏了任何可以帮助某人的信息,请告诉我,我可以添加。然而,我认为发送和接收功能是最重要的。我能够设置和读取收发器的寄存器。
我现在可以发送文件了!
已在 spi_read_msg()
函数中完成修复。
问题是我将接收到的缓冲区转换为字符串,这导致在遇到字节 0x00
时数据被修剪。这也等同于空终止符。
收件人代码:
int spi_read_msg(int spi_dev_fd, char addr, char * status, char * copy_to, int len)
{
char data_buffer;
char recv_buffer[len + 1];
struct spi_ioc_transfer xfer;
memset(&xfer, 0, sizeof(xfer));
memset(&recv_buffer, 0, sizeof(recv_buffer));
data_buffer = addr;
xfer.tx_buf = (unsigned long) &data_buffer;
xfer.rx_buf = (unsigned long) recv_buffer;
xfer.len = len + 2;
xfer.bits_per_word = 8;
xfer.speed_hz = 1000000;
xfer.cs_change = 0;
xfer.rx_nbits = len * 8;
xfer.tx_nbits = 8;
int res = ioctl(spi_dev_fd, SPI_IOC_MESSAGE(1), xfer);
if(res > 0)
{
status[0] = recv_buffer[0];
if(copy_to != NULL)
{
for(int i = 0; i < len; ++i)
{
copy_to[i] = recv_buffer[i + 1];
}
}
}
return res;
}