多个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:01234567890123456789012345678901234567890123456789
 0> 
 0> RX EVENT pipe:0 cnt:5619 noack:1 pid:1 rssi:29 data:01234567890123456789012345678901234567890123456789
 0> 
 0> RX EVENT pipe:0 cnt:5620 noack:1 pid:1 rssi:29 data:01234567890123456789012345678901234567890123456789
 0> 
 0> RX EVENT pipe:0 cnt:5621 noack:1 pid:1 rssi:29 data:01234567890123456789012345678901234567890123456789
 0> 
 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:01234567890123456789012345678901234567890123456789
 0> 
 0> RX EVENT pipe:0 cnt:5631 noack:1 pid:1 rssi:29 data:01234567890123456789012345678901234567890123456789
 0> 
 0> RX EVENT pipe:0 cnt:5632 noack:1 pid:1 rssi:29 data:01234567890123456789012345678901234567890123456789
 0> 
 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源码,能够了解每一个字段的含义,说不定就像我一样找到了问题。

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值