打造一个通用性MCU架构,支持CX32/AT32/NRF51/NRF52等。 OS支持RTX4/RTX5/FreeRtos。 采用VsCode+GCC组合,VsCode+KEIL5,超强开发方式。 QQ群:524408033

LiSun

打造一个通用性MCU架构,支持CX32/AT32/NRF51/NRF52等。 OS支持RTX4/RTX5/FreeRtos。 采用VsCode+GCC组合,VsCode+KEIL5,超强开发方式。 QQ群:524408033

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

一、架构说明

模式描述优势
主从一体1. 多通道通信 2. 动态调频1对7
框架功能1. RTX5 2.功能分层架构清晰,集成部分功能方便开发
附带功能BootLoader(uart)/电源管理/灯光管理/按键管理-

在这里插入图片描述
在这里插入图片描述

【注意】 CMSIS版本不能低于5.8.0,否则程序将不正常运行。    ARM.CMSIS.5.8.0.pack
        5.8.0更新了 [GCC LinkerDescription,GCC 汇编程序启动] [为工具链 ARM、GCC 添加了 ARMv8-M 堆栈密封(到链接器、启动)]

[项目结构]
+---Master_Slave(alone)
|    +---app
|    |   +---app_led                   [LED线程任务]
|    |   +---led_gpio                  [LED_GPIO操作]
|    |   +---app_adc                   [将ADC值进行计算]
|    |   +---app_soft_voltameter       [软电量计算法]
|    |   \---app_key                   [按键扫描]
|    +---bsp
|    |   \---nrf52                     [BSP层公共接口函数]
|    +---chip
|    |   +---nRF_Drivers               [芯片驱动函数]
|    |   +---nRF_Libraries             [芯片支持函数]
|    |   \---nRF5_SDK_17.0.2_d674dde   [芯片SDK版本]
|    +---lib
|    |   \---queue                     [消息队列]
|    +---os
|    |   \---rtx5                      [OS层公共接口函数]
|    +---platform
|    |   +---log                       [日记函数]
|    |   \---SEGGER_RTT                [RTT库]
|    +---sys
|    |   \---nrf52                     [SYS层公共接口函数]
|    +---main_HandWriteBoard           [项目业务层]
|    │      sdk_config.h               (NRF功能配置)
|    │      business_gpio.h            (引脚定义)
|    │      business_function.h        (功能定义/业务宏)
|    │      app_main.c                 (主业务功能)
|    │      biz_led.c                  (灯光功能:电量灯/射频灯)
|    │      biz_key.c                  (按钮功能:电源键)
|    │      biz_power.c                (电源管理:充放电状态/电池信息/电源开关)
|    │      biz_uart.c                 (串口数据接收:决定串口通道对应的协议)
|    │      biz_flash.c                (Flash信息存储和读取)
|    +---public                        [项目公共层]
|    │      biz_esb.c                  (2.4G功能函数:发送端/接收端)
|    │      biz_fds.c                  (重新封装fds函数)
|    │      biz_low_power.c            (空闲检测逻辑)


[FLASH结构]
nRF52810 192 KB Flash, 24 KB RAM
          0x30000       0x6000

使用boot时:keil需要在Options-c/c++-Define  添加宏定义 MBR_PRESENT

boot文件:public_code\nrf52810_boot_uart.hex

  名称        地址                           大小(字节)
|----------------------------------------------------------
MBR:         0x0000                         0x1000       (mbr_nrf52_2.4.1_mbr.hex)
APP:        0x1000                         0x30000 - boot_size - RSV1_SIZE - RSV2_SIZE - mbr_size = 0x27000
Boot:        0x28000                        0x6000
RSV1:        0x2E000                        0x1000       (settings.hex)--Bootloader setting
RSV2:        0x2F000                        0x1000       (settings.hex)--MBR parameters
END:         0x30000

|-----------------------------------------------------------

boot+app addr: 0x0

fds addr:0x27000 - 0x0C00 = 0x26400
fds_size: 3 * 0x0400 = 0x0C00


二、ESB工作原理

  1. RADIO 数据包配置
    在这里插入图片描述
    PREAMBLE: 前导码或者说帧头,一个字节长度(除了2M/s 蓝牙模式),前导码自动配置的,用户不用设置。
    ADDRESS: 广播地址由基地址(base)+前缀地址(prefix )两部分组成。基地址长度:2-4字节,其长度可以通过寄存器PCNF1的BALEN位配置。
    在这里插入图片描述
    支持星状网络拓扑实现一拖多的双向链路是nrf52的一个特点,nrf52一个接收端能最多支持8个发送端。
    8个逻辑通道(pipe)拥有单独特定的传输物理地址,所以保证了数据不会错乱。8个逻辑地址是如何和物理地址对应呢,如下图逻辑地址的定义,第一章我们说了物理地址由base+prefix组成,所以通道0的地址是BASE0+prefix[0],其他的地址是BASE1+prefix[1]~[7]。然后发送端发送自己逻辑地址,接收端接收判断收到数据包逻辑通道。
static nrf_esb_payload_t tx_payload = NRF_ESB_CREATE_PAYLOAD(0, 0x01, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00);
static nrf_esb_payload_t rx_payload = {0};

// 下面四个数组可以通过uart或者其他方式来修改频率和地址
static uint8_t base_addr_0[4] = {0x20, 0x21, 0x05, 0x19};
static uint8_t base_addr_1[4] = {0x95, 0x81, 0x69, 0x6f};
static uint8_t addr_prefix[8] = {0x78, 0x75, 0x65, 0x6a, 0x69, 0x61, 0x6e, 0x71};
__attribute__((aligned(4))) uint8_t rf_freq_table[RF_FREQ_MAX_VAL] = {0x6c, 0x69, 0x73, 0x75, 0x6e};

1. 通道地址分配如下(主机和从机base_addr_0、base_addr_1、addr_prefix必须一致才能8组设备通信)
通道0base_addr_0(4字节) + addr_prefix[0]
通道1base_addr_1(4字节) + addr_prefix[1]
通道2base_addr_1(4字节) + addr_prefix[2]
通道3base_addr_1(4字节) + addr_prefix[3]
通道4base_addr_1(4字节) + addr_prefix[4]
通道5base_addr_1(4字节) + addr_prefix[5]
通道6base_addr_1(4字节) + addr_prefix[6]
通道7base_addr_1(4字节) + addr_prefix[7]

2. 每个设备必须编号0-7,且每个通道只能用特定编号通道发送。(例如:设备5,对通道5发送数据,则设备0-4,6-7,都能收到通道5发来的消息)

4. 自定义通信协议
    字节0            字节1       字节2        字节3 -- (n-1)             字节n
  要发送的通道(0-7)  命令值      数据长度        数据内容         校验合(数据内容累加,取低八位)
  1. 占用资源:
    Radio (NRF_RADIO)
    Timer: NRF_TIMER2 //这里用到了发送数据的时候等待应答以及延时重发过程
    PPI channels 10, 11, 12, and 13 //与NRF_TIMER2联合用到发送数据的时候等待应答以及延时重发Software interrupt 0

  2. 如何判断数据来自来个通道?

/**@brief Enhanced ShockBurst payload.
 * @details 所述有效载荷用于传输和确认带有有效载荷的接收数据包。  
*/
typedef struct
{
    uint8_t length;                                 //报文长度(最大值为@ref NRF_ESB_MAX_PAYLOAD_LENGTH)。
    uint8_t pipe;                                   //当前消息通道号
    int8_t  rssi;                                   //收到的报文为RSSI。
    uint8_t noack;                                  //指示此包将不被确认的标志。 当启用选择性自动应答时,该标志被忽略。  
    uint8_t pid;                                    //在通信期间分配的PID。
    uint8_t data[NRF_ESB_MAX_PAYLOAD_LENGTH];       //数据数组(可以是发送数据,也可以是接收数据)
} nrf_esb_payload_t;
----------------------------------
/**
 * @brief  [ESB回调事件] 接收通知收发事件,并处理事件
 * @param  *p_event: esb事件类型
 */
void nrf_esb_event_handler(nrf_esb_evt_t const *p_event)
{
    switch (p_event->evt_id)
    {
        case NRF_ESB_EVENT_RX_RECEIVED:
            if (nrf_esb_read_rx_payload(&rx_payload) == NRF_SUCCESS)
            {
                if (get_comm_connect_state() == SYS_CONNECT_TYPE_RF)
                {
                	LOG_D("ESB_CH_RX:%d\r\n", rx_payload.pipe);
                    esb_clean_rx_heart_time();
                    esb_set_rx_connect_state(true);
                    // 跳转业务处理函数
                    if (g_rx_dispose_callback)
                    {
                        g_rx_dispose_callback(rx_payload.data, rx_payload.length);
                    }
                }
            }
            break;
    }
}
  1. 如何给对应通道发送数据?
/**
 * @brief  [ESB操作][发送端][发送数据] 发送一包数据(异步)
 * @note   异步发送
 * @param  *pdata: 待发送的数据指针
 * @param  len: 数据长度
 * @retval 发送状态
 */
uint32_t esb_tx_send(uint8_t ch, uint8_t *pdata, uint8_t len)
{
    tx_payload.pipe = ch;
    tx_payload.length = len;
    memcpy(tx_payload.data, pdata, len);
    return nrf_esb_write_payload(&tx_payload);
}

/**
 * @brief  处理消息队列中的消息,通过rf发送(放在空闲线程使用)
 */
bool rf_data_dispose(void)
{
    if (!queue_de(&m_rf_tx_q, g_rf_tx_data))
    {
        return false;
    }
    esb_set_rf_and_start_tx();
    esb_tx_send(g_rf_tx_data[0], g_rf_tx_data, g_rf_tx_data[2]);
    return true;
}
  1. 数据包识别与鉴定
    tx发送数据包的时候通过crc和pid进行验证。这里说一下数据包前面的识别码。
    动态数据长度发送协议:用户的数据打包过程中在底层是从m_tx_payload_buffer[2]开始的,m_tx_payload_buffer[0]用来存储字节长度,m_tx_payload_buffer[1]后两位用来存pid和应答标识,pid用来区分包是否为重发的包,如果不是重传的包存入RX缓存,如果是重发的包丢掉。

三、 管道和地址

几个约定:

pipe:管道

Preamble:前导码

Base address :基地址

Prefix:字首

节点上的每个逻辑地址称为管道。每个管道映射一个空中地址以发送或接收数据。
空中地址由2-4个字节的长的基地址和一个字节的的字首(prefix)地址组成,nRF5无线电使用0和1的交替序列作为分组的前导码(preamble)。因此,对于要正确接收的数据包,基地址的最高有效字节不能是0和1的交替序列,也就是说,基地址的最高有效字节不能是0x55或0xAA。
管道0具有其自己唯一的基址(基址0),而管道1-7使用相同的基址(基址1)。 8个管道中的每一个管道都具有唯一的一个字节的字首(prefix)地址。
在广播中,首先发送每个地址字节的最高有效位。 2-4字节长的基地址的最高有效字节是第一个发送的地址字节,而字首的那一个字节是 最后发送的。
地址不能包含0x00前缀和格式为0x00XXXXXX(长度4)/ 0x0000XXXX(长度5)的地址。 这样的零地址将导致返回错误代码NRF_ERROR_INVALID_PARAM。

注意:ESB中的字节排序和nRF5无线电外设不一样,因为地址字节在ESB中重新排列以匹配nRF24L无线电

PTX FIFO处理

在PTX模式下启用ESB时,上传到TX FIFO的任何数据包将在下次机会传输

当PTX从PRX成功接收到ACK时,PTX假定有效载荷已成功接收并添加到PRX的RX FIFO。 成功传输的数据包将从TX FIFO中删除,以便可以传输FIFO中的下一个数据包。

如果PTX接收的ACK包含有效载荷,则该有效载荷将被添加到PTX的RX FIFO。

PRX FIFO处理

当在PTX模式中使能ESB中时,PTX将会监视所有已启用的管道(地址)的传入数据包

如果接收到之前未添加到PRX的RX FIFO的新数据包,并且RX FIFO具有该数据包的可用空间,则将数据包添加到RX FIFO并发送ACK返回给PTX,如果PRX的TX FIFO包含任何数据包,则TX FIFO中的下一个可维护数据包作为有效负载附加在ACK数据包中。 请注意,在收到数据包之前,必须已将此TX数据包上载到TX FIFO。

Event处理

当频率上有一个事件时,ESB模块会分析其原因,且如果有必要的话,会将该事件排入应用程序,这个事件指示的可能时成功或者失败的操作或者在RX FIFO中有新的数据可以获得。

事件是作为一个flag排队的,且在第一次触发软件中断时被读出。因此,在发送给应用程序的每个事件可能包含多个频率的中断。例如NRF_ESB_EVENT_TX_SUCCESS 和NRF_ESB_EVENT_TX_FAILED事件可能分别指示着多个成功或者失败,NRF_ESB_EVENT_RX_RECEIVED事件表示RX FIFO中至少有一个新数据包;事件处理程序应确保在适当情况下完全清空RX FIFO

posted on 2022-08-13 11:00  xuejianqiang  阅读(491)  评论(0编辑  收藏  举报
打造一个通用性MCU架构,支持CX32/AT32/NRF51/NRF52等。 OS支持RTX4/RTX5/FreeRtos。 采用VsCode+GCC组合,VsCode+KEIL5,超强开发方式。 QQ群:524408033