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,只有发送端设置noackfalse才会回复。

思考

看源码真有用!当遇到问题实在解决不了的话,就查看sdk源码,能够了解每一个字段的含义,说不定就像我一样找到了问题。

多个NRF52832高频通信时生成字节长度为0的接收事件问题解决相关推荐

  1. C# 串口接收1次数据会进入2次串口接收事件serialPort1_DataReceived,第2次进入时串口缓冲区为空

    在C#中使用串口接收数据时发现,在完整的接收完一次数据后,还会再次进入串口接收事件. 在网上搜索资料发现其他开发者也有遇到该问题: [1]  c#串口事件接受一次数据莫名其妙会触发两次   原文链接: ...

  2. Java实现HMacMD5加密,用于淘宝客JS 组件 API 调用时生成 sign 的签名

    原文:Java实现HMacMD5加密,用于淘宝客JS 组件 API 调用时生成 sign 的签名 源代码下载地址:http://www.zuidaima.com/share/1550463397874 ...

  3. javaScript模板字符串、严格模式、编码字节长度

    一.模板字符串 var str=`hello`模板字符串 模板语法`${变量}` ${简单运算} <script>// +号连接字符function test2(){var a=10var ...

  4. NodeJS生成字节码

    NodeJS生成字节码 相关问题: 1.nodejs源码保护 2.nodejs源码加密 3.nodejs提升运行速度 前言 传统的后端运行环境,如 Java..NET,其源代码是经过编译才部署到服务器 ...

  5. html中设置文本框长度,Html的文本框怎样限制录入文本框的字节长度

    匿名用户 1级 2013-07-20 回答 试试这个: limit.jsview plaincopy to clipboardprint? function limit(){ var txtNote; ...

  6. JAVA返回指定字符串的长度,Java截取指定字节长度的字符串

    在实际的项目中,我们后台的数据库是根据指定编码(如GBK)保存数据的,为防止操作数据库时,因字段值长度超过数据库定义的长度,须在JAVA甚至JS层面做长度的校验控制,如数据库定义的长度是varchar ...

  7. java String长度与varchar长度匹配理解(字符和字节长度理解)

    java String长度与varchar长度匹配理解(字符和字节长度理解) string中的length()长度,返回的是char的数量,每个char可以存储世界上任何类型的文字和字符,一个char ...

  8. php获取字符串商都_php strlen获取字符串字节长度和mb_strlen获取字符串个数长度的区别(strlen获取中文长度)...

    strlen获取字符串字节长度和mb_strlen获取字符串个数长度的区别,如果字符串是数字或者英文字母组成的话,它们2个的结果上体现不出区别,可是如果字符串是汉字组成的话它们2个的结果差异很大 重点 ...

  9. Mysql varchar 字节长度

    1.我们经常 mysql创建 varchar(20)  name这个 20长度 究竟是表示的字符数还是字节数?根编码字符集又有没有关系? 首先 mysql 5.X 以上的版本的 定义中 表示的字符长度 ...

最新文章

  1. c库的rand/random随机数产生函数性能差?
  2. javascript调试_如何提高JavaScript调试技能
  3. 十大问题诠释冯国华缘何入主金蝶
  4. 奔跑吧2015,个推一月活动走起
  5. 4-Qt6控制台项目信号与槽
  6. SqlServer中怎样从Excel中导入数据
  7. 类属性-类属性的定义及使用
  8. 一个大型虚拟项目包含位于不同地点的许多干系人_项目管理与人生
  9. 处理wordpress上传中文名附件乱码问题
  10. c fun函数求n个整数的平均值_c语言题目(求阶乘)
  11. 网页图片显示分辨率与实际分辨率不一样
  12. hping3安装及使用
  13. PC机组成——主板、芯片组与BIOS
  14. centos安装aria2c_CentOS安装aria2 + yaaw实现离线下载
  15. PhxRPC源码简析
  16. 衡水二中2021清华北大高考成绩查询,衡水二中成为“清华大学2020年优质生源中学”...
  17. 这样定义通用人工智能
  18. java 事务 回滚
  19. 【火灾检测】森林火灾检测系统(带面板)【含GUI Matlab源码 1921期】
  20. 程序员必修内功,收集了上千本各类编程书籍【免费获取】

热门文章

  1. 读《输赢》与《圈子圈套》有感
  2. gam估计模型的链接
  3. 哈希函数在密码学中的应用
  4. 想在领英开发客户,却发现举步维艰,如何解锁领英开发客户新模式
  5. 光电收发管RPR220介绍
  6. 系统架构案例分析——(1)Web开发技术综述
  7. 计算机无法发现网络共享打印机,打印机网络共享,但是局域网内电脑无法连接。...
  8. 小丸工具箱下载和安装后我的压制报错日志
  9. 云服务器搭建ThinkPHP框架图文教程
  10. python 对excel的交互工具的使用