多个NRF52832高频通信时生成字节长度为0的接收事件问题解决
1.现象
如题,在调试多个52832高频率通信时,每隔一段时间会有载荷长度为0的 NRF_ESB_EVENT_RX_RECEIVED
事件发生,52832接收处理部分代码如下:
void rfEventHandler(nrf_esb_evt_t const * p_event)
{uint8_t i;switch (p_event->evt_id){case NRF_ESB_EVENT_TX_SUCCESS:SEGGER_RTT_printf(0,"TX SUCCESS EVENT\r\n");break;case NRF_ESB_EVENT_TX_FAILED:(void) nrf_esb_flush_tx();(void) nrf_esb_start_tx();NVIC_SystemReset();SEGGER_RTT_printf(0,"TX FAILED EVENT\r\n");break;case NRF_ESB_EVENT_RX_RECEIVED://SEGGER_RTT_printf(0,"RX RECEIVED EVENT\r\n");if (nrf_esb_read_rx_payload(&rx_payload) == NRF_SUCCESS){ SEGGER_RTT_printf(0,"RX EVENT pipe:%d cnt:%d noack:%d pid:%d rssi:%d data:%s\r\n",rx_payload.pipe,rcvCnt++,rx_payload.noack,rx_payload.pid,rx_payload.rssi,rx_payload.data); //通道检测,判断数据有效性,switch(rx_payload.pipe){case 0:SEGGER_RTT_printf(0,"receive PIPE 0 data\r\n");//0通道的直接转发,有效性由stm32来处理break;case 1:case 2:SEGGER_RTT_printf(0,"receive PIPE 1 or 2 data\r\n");//传感器数据 数据有效性检查if(sensorDataDispose() == 0){return; //无效直接返回,不处理}break;}//转发有效数据到串口for(i=0; i<rx_payload.length; i++){rf_rx_buf[i]=rx_payload.data[i];}rf_rx_len=rx_payload.length;for(i=0; i<rf_rx_len; i++){app_uart_put(rf_rx_buf[i]);}rf_rx_len=0;nrf_esb_flush_rx(); }break;}
}
发送模块每隔50ms发送50个字节
接收模块在j-link打印出异常日志如下:
0> RX EVENT pipe:0 cnt:5618 noack:1 pid:1 rssi:29 data:012345678901234567890123456789012345678901234567890> 0> RX EVENT pipe:0 cnt:5619 noack:1 pid:1 rssi:29 data:012345678901234567890123456789012345678901234567890> 0> RX EVENT pipe:0 cnt:5620 noack:1 pid:1 rssi:29 data:012345678901234567890123456789012345678901234567890> 0> RX EVENT pipe:0 cnt:5621 noack:1 pid:1 rssi:29 data:012345678901234567890123456789012345678901234567890> 0> RX EVENT pipe:0 cnt:5622 noack:1 pid:1 rssi:50 data:0> RX EVENT pipe:0 cnt:5623 noack:1 pid:1 rssi:49 data:0> RX EVENT pipe:0 cnt:5624 noack:1 pid:1 rssi:50 data:0> RX EVENT pipe:0 cnt:5625 noack:1 pid:1 rssi:49 data:0> RX EVENT pipe:0 cnt:5626 noack:1 pid:1 rssi:49 data:0> RX EVENT pipe:0 cnt:5627 noack:1 pid:1 rssi:50 data:0> RX EVENT pipe:0 cnt:5628 noack:1 pid:1 rssi:50 data:0> RX EVENT pipe:0 cnt:5629 noack:1 pid:1 rssi:50 data:0> RX EVENT pipe:0 cnt:5630 noack:1 pid:1 rssi:29 data:012345678901234567890123456789012345678901234567890> 0> RX EVENT pipe:0 cnt:5631 noack:1 pid:1 rssi:29 data:012345678901234567890123456789012345678901234567890> 0> RX EVENT pipe:0 cnt:5632 noack:1 pid:1 rssi:29 data:012345678901234567890123456789012345678901234567890> 0> RX EVENT pipe:0 cnt:5633 noack:1 pid:1 rssi:29 data:01234567890123456789012345678901234567890123456789
其中data:
后为空的即为上述字节长度为0的接收事件。
2.问题排查
2.1对比实验
取其中两个模块,作为一收一发,pipe0地址设置成与其他不同,测试通信发现没有上述问题。
增加一个模块,设置地址与前两个相同,三个模块上电,一发两收,问题复现,
再增加1到3个模块,1发收到,问题复现,且随着模块增加,问题出现频率上升。
初步确定是多模块通信出现问题,继续下一步排查。
2.2 查看代码
重新查看写的程序,发现在发送时将载荷成员变量设置为false,也就是需要ack,猜想是否多个模块回复ack导致的问题,于是把noack设置为true
原来的设置,直接看图
修改之后的设置:
tx_payload.noack = true;
发现现象依然存在,按道理说不应该呀,百思不得其解。
2.3 硬件干扰排查
同事建议考虑下硬件问题,是否为信号干扰。但是我想在两个模块能正常通信的前提下,可以排除硬件问题,随后为了以防万一,还为无线模块增加了铝箔屏蔽,漏出天线,如下图
编写简单串口转无线,无线转串口程序,进行试验,统计丢包率,排查是否为干扰。数据记录如下:
两个模块 每次50个字节 (都包裹屏蔽铝箔)
发送 200460
接收 200380
丢包率 0.03%
三个模块 每次50个字节 (其中有1个没有包裹屏蔽铝箔)
发送 221364
接收 221554
丢包率 不丢反而多出来了,多出来比率为 0.08%
四个模块 每次50个字节 (其中有2个没有包裹屏蔽铝箔)
发送 215332
接收 217653
丢包率 不丢反而多出来了,多出来比率为 1.07%
三个模块 每次50个字节 (都包裹屏蔽铝箔)
发送 218868
接收 219023
丢包率 不丢反而多出来了,多出来比率为 0.07%
想不通的是,大于2个模块居然会有接收数据包大于发送数据包的现象,想不通。。。
至此已耗时3天,领导已不太满意进度,让我实在不行先放放这个问题。
我感觉不搞明白,不太舒服,于是晚上加班继续查找原因。
由于应用层程序已经确认过多次,没有问题,于是查看底层SDK程序,梳理无线中断到应用层接收的流程与逻辑(具体流程下一篇博文写出)。
3.仿真跟踪
取一个模块不断发送,3个模块同时接收,然后在接收模块仿真跟踪接收程序,发现上边虽然更改了需要ack,但是接收端仍然在回复ack,
射频接收中断中,判断是否需要ack是由两个条件来判断的,
if ((m_config_local.selective_auto_ack == false) || ((m_rx_payload_buffer[1] & 0x01) == 1)){ack = true;}if (ack){......发ack}{......不发ac’}
或条件之后((m_rx_payload_buffer[1] & 0x01) == 1))
中m_rx_payload_buffer[1] 是接收的发送时设置的noack
字段,我在发送时将其设置为true
,所以,没有问题。
而前者(m_config_local.selective_auto_ack == false)
中selective_auto_ack
字段在无线初始化时设置其为false会导致无论发送段noack
是否为真,接收端都会回复ack。也就是说我在发送端修改的noack
没有生效,所有通信仍然在自动ack。
于是在初始化时将selective_auto_ack
设置为true
,
/**************************************************************************************
函数功能: 无线发送初始化
入 参:
返回结果:
作 者:
时 间: 2021年2月26日10:22:15
**************************************************************************************/
uint32_t initRfTx( void )
{uint32_t err_code;
// uint8_t base_addr_0[4] = {0xE7, 0xE7, 0xE7, 0xE7};
// uint8_t base_addr_1[4] = {0xC2, 0xC2, 0xC2, 0xC2};
// uint8_t addr_prefix[8] = {0xE7, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8 };nrf_esb_config_t nrf_esb_config = NRF_ESB_DEFAULT_CONFIG;nrf_esb_config.payload_length = 0x40; //更改为64字节nrf_esb_config.protocol = NRF_ESB_PROTOCOL_ESB_DPL;nrf_esb_config.retransmit_delay = 600;nrf_esb_config.bitrate = NRF_ESB_BITRATE_2MBPS;nrf_esb_config.event_handler = rfEventHandler;nrf_esb_config.mode = NRF_ESB_MODE_PTX;nrf_esb_config.selective_auto_ack = false;err_code = nrf_esb_init(&nrf_esb_config);VERIFY_SUCCESS(err_code);err_code = nrf_esb_set_base_address_0(flashConfigData.obj.baseAddr0);VERIFY_SUCCESS(err_code);err_code = nrf_esb_set_base_address_1(flashConfigData.obj.baseAddr1);VERIFY_SUCCESS(err_code);err_code = nrf_esb_set_prefixes(flashConfigData.obj.addrPrefix, NRF_ESB_PIPE_COUNT);VERIFY_SUCCESS(err_code);return err_code;
}
继续利用之前编写的串口透传做实验,结果如下:
修改 nrf_esb_config.selective_auto_ack = true;后
四个模块 每次50个字节 (其中有3个包裹屏蔽铝箔)
发送 323804
接收 323804
没有丢包,完美
问题解决。
回到SDK中 对selective_auto_ack
注释,
bool selective_auto_ack; //!< Enable or disable selective auto acknowledgement. When this feature is disabled, all packets will be acknowledged ignoring the noack field.
我感觉翻译过来的意思是:使能或失能自动恢复,当失能的话,所有的数据包将回复noack字段 自动回复。
也就是说该字段设置为false
时,无论在发送端noack
真还是假,接收端都会自动回复!
开始在查看初始化程序时我就注意到了这个字段,但是依靠selective_auto_ack
的字面含义,我理解为只有设置为真,才会自动回复,所以造成了这个问题。哪能想到他是反逻辑,真是乌龙!!!
最后我将接受段的这个字段设置为true
,这样在接收端收到的数据默认不回复ack,只有发送端设置noack
为false
才会回复。
思考
看源码真有用!当遇到问题实在解决不了的话,就查看sdk源码,能够了解每一个字段的含义,说不定就像我一样找到了问题。
多个NRF52832高频通信时生成字节长度为0的接收事件问题解决相关推荐
- C# 串口接收1次数据会进入2次串口接收事件serialPort1_DataReceived,第2次进入时串口缓冲区为空
在C#中使用串口接收数据时发现,在完整的接收完一次数据后,还会再次进入串口接收事件. 在网上搜索资料发现其他开发者也有遇到该问题: [1] c#串口事件接受一次数据莫名其妙会触发两次 原文链接: ...
- Java实现HMacMD5加密,用于淘宝客JS 组件 API 调用时生成 sign 的签名
原文:Java实现HMacMD5加密,用于淘宝客JS 组件 API 调用时生成 sign 的签名 源代码下载地址:http://www.zuidaima.com/share/1550463397874 ...
- javaScript模板字符串、严格模式、编码字节长度
一.模板字符串 var str=`hello`模板字符串 模板语法`${变量}` ${简单运算} <script>// +号连接字符function test2(){var a=10var ...
- NodeJS生成字节码
NodeJS生成字节码 相关问题: 1.nodejs源码保护 2.nodejs源码加密 3.nodejs提升运行速度 前言 传统的后端运行环境,如 Java..NET,其源代码是经过编译才部署到服务器 ...
- html中设置文本框长度,Html的文本框怎样限制录入文本框的字节长度
匿名用户 1级 2013-07-20 回答 试试这个: limit.jsview plaincopy to clipboardprint? function limit(){ var txtNote; ...
- JAVA返回指定字符串的长度,Java截取指定字节长度的字符串
在实际的项目中,我们后台的数据库是根据指定编码(如GBK)保存数据的,为防止操作数据库时,因字段值长度超过数据库定义的长度,须在JAVA甚至JS层面做长度的校验控制,如数据库定义的长度是varchar ...
- java String长度与varchar长度匹配理解(字符和字节长度理解)
java String长度与varchar长度匹配理解(字符和字节长度理解) string中的length()长度,返回的是char的数量,每个char可以存储世界上任何类型的文字和字符,一个char ...
- php获取字符串商都_php strlen获取字符串字节长度和mb_strlen获取字符串个数长度的区别(strlen获取中文长度)...
strlen获取字符串字节长度和mb_strlen获取字符串个数长度的区别,如果字符串是数字或者英文字母组成的话,它们2个的结果上体现不出区别,可是如果字符串是汉字组成的话它们2个的结果差异很大 重点 ...
- Mysql varchar 字节长度
1.我们经常 mysql创建 varchar(20) name这个 20长度 究竟是表示的字符数还是字节数?根编码字符集又有没有关系? 首先 mysql 5.X 以上的版本的 定义中 表示的字符长度 ...
最新文章
- c库的rand/random随机数产生函数性能差?
- javascript调试_如何提高JavaScript调试技能
- 十大问题诠释冯国华缘何入主金蝶
- 奔跑吧2015,个推一月活动走起
- 4-Qt6控制台项目信号与槽
- SqlServer中怎样从Excel中导入数据
- 类属性-类属性的定义及使用
- 一个大型虚拟项目包含位于不同地点的许多干系人_项目管理与人生
- 处理wordpress上传中文名附件乱码问题
- c fun函数求n个整数的平均值_c语言题目(求阶乘)
- 网页图片显示分辨率与实际分辨率不一样
- hping3安装及使用
- PC机组成——主板、芯片组与BIOS
- centos安装aria2c_CentOS安装aria2 + yaaw实现离线下载
- PhxRPC源码简析
- 衡水二中2021清华北大高考成绩查询,衡水二中成为“清华大学2020年优质生源中学”...
- 这样定义通用人工智能
- java 事务 回滚
- 【火灾检测】森林火灾检测系统(带面板)【含GUI Matlab源码 1921期】
- 程序员必修内功,收集了上千本各类编程书籍【免费获取】