打造一个通用性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

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

在这里插入图片描述
这个指南描述了什么是ESB(Enhanced ShockBurst)以及如何在nRF5系列中使用ESB.

ESB支持双向数据包通信,包括数据包缓冲,数据包确认和丢失数据包的自动重传的基本协议.ESB提供低功耗的射频传输功能

ESB 支持双向数据包通信的基本协议包括数据包缓冲,数据包确认和丢失数据包的自动重传。实现代码小且易于使用.

ESB协议嵌入在传统nRF24L系列的硬件中,而增强型ShockBurst模块(即ESB)使nRF5系列设备能够使用ESB协议与nRF5或nRF24L系列设备进行通信。

ESB具有自动数据包事务处理功能,可轻松实现可靠的双向数据链路, 在这当中,传输包(A transaction is a packet)是两个收发器之间的分组交换,一个收发器作为主接收PRX,一个收发器作为主发送PTX.

ESB特性:

  • 支持一个星型网络拓扑结构,典型的是一路主接收,多达八路的主发送。
  • 传统模式下支持1到32字节的动态payload(数据传输宽度)
  • NRF5系列之间支持1-252字节的静态的payload(数据传输宽度)
  • 每个PTX和PRX节点都支持双工数据发送接收
  • 数据包确认和自动数据包重传功能
  • 每个管道都有独立的发送和接收FIFO
  • 后向兼容NRF2401的增强型ESB。

资源:

ESB使用一组固定的资源,并要求对它们进行独占访问以确保正确操作。

  • 射频(NRF_RADIO)
  • 定时器:NRF_TIMER2,NRF_TIMER3:
  • PPI(可编程外围互联)通道7,8,9,10,11,12,13
  • 软件中断0

注意:没有MPU强制执行此独占访问,因此操纵这些资源会产生未定义的行为。(即最好避免操作这些资源)

另外:射频和定时器中断处理运行在0优先级(即最高优先级),ESB回调功能函数运行在1优先级。因此在应用程序中使用的其他中断应当运行在2-7优先级以确保正确操作。

/********************************************************************************
* @file    biz_esb.c
* @author  jianqiang.xue
* @version V1.0.0
* @date    2021-07-06
* @brief   [业务]2.4G管理 资料参考:https://blog.csdn.net/Behold1942/article/details/88236910
********************************************************************************/

/* Includes ------------------------------------------------------------------*/
#include <stdbool.h>
#include <string.h>
#include "nrf.h"
#include "nrf_esb.h"
#include "nrf_error.h"
#include "nrf_esb_error_codes.h"
#include "sdk_macros.h"
#include "queue.h"
/* Private Includes ----------------------------------------------------------*/
#include "business_function.h"
#include "business_gpio.h"
#include "log.h"
#include "app_main.h"
#include "biz_esb.h"
#include "os_api.h"
#include "bsp_rng.h"
#include "biz_fds.h"
/* Private Define ------------------------------------------------------------*/
/* External Variables --------------------------------------------------------*/
/* Private Variables ---------------------------------------------------------*/
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};

#pragma pack(4)
__attribute__((aligned(4))) uint8_t rf_freq_table[RF_FREQ_MAX_VAL] = {0x20, 0x21, 0x22, 0x23, 0x24};
__attribute__((aligned(4))) uint8_t rf_mac_addr[RF_MAC_MAX_VAL]    = {0x55, 0x56, 0x57, 0x58, 0x59};
#pragma pack()

bool g_esb_init_flag = false;
bool g_flash_write_24g_mac_flag = 0;
bool g_flash_write_24g_freq_flag = 0;

static uint8_t base_addr_0[4] = {0xE7, 0xE7, 0xE7, 0xE7};
static uint8_t base_addr_1[4] = {0xC2, 0xC2, 0xC2, 0xC2};
static uint8_t addr_prefix[8] = {0xE7, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8};

// 发送端
uint8_t rf_tx_freq_index     = 0;      // 当前射频通道号
bool rf_tx_connect_status    = false;  // false--未连接  ture--已连接
uint8_t rf_tx_heart_tick     = 0;      // 当前心跳次数
uint8_t rf_tx_connect_time   = 0;      // 当前连接时长

// 接收端
uint8_t rf_rx_freq_index     = 0;      // 当前射频通道号
bool rf_rx_connect_status    = false;  // false--未连接  ture--已连接
uint8_t rf_rx_heart_time     = 0;      // 当前连接时长

// 注册接收回调函数,给外部使用
typedef void(*esb_rx_event_callback)(uint8_t *data, uint16_t len);
static esb_rx_event_callback g_rx_dispose_callback;

// 消息队列
#define RF_TX_Q_ITEM_CNT                             30
#define RF_TX_Q_ITEM_SIZE                            (12)
/***************消息队列定义**************/
 // 用于rf_tx消息队列总缓存区
static uint8_t m_rf_tx_q_buff[RF_TX_Q_ITEM_CNT * RF_TX_Q_ITEM_SIZE] = {0};
queue_t m_rf_tx_q =
{
    .pbuff     = m_rf_tx_q_buff,
    .front     = 0,
    .rear      = 0,
    .item_cnt  = RF_TX_Q_ITEM_CNT,
    .item_size = RF_TX_Q_ITEM_SIZE
};
uint8_t g_rf_tx_data[RF_TX_Q_ITEM_SIZE]    = {0}; // 用于RF消息临时缓存区
/* Private Function Prototypes -----------------------------------------------*/

/*------------------------------------------------【公共函数】------------------------------------------------*/
/**
 * @brief  [ESB操作]ESB反初始化
 */
void esb_deinit(void)
{
    if (!g_esb_init_flag)
    {
        return;
    }
    g_esb_init_flag = false;
    nrf_esb_disable();
}

/**
 * @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_TX_SUCCESS:
            //LOG_D("---------------NRF_ESB_EVENT_TX_SUCCESS---------------");
            if (get_comm_connect_state() == SYS_CONNECT_TYPE_RF)
            {
                esb_clean_tx_heart_time();
                // 如果上次处于未连接,则清除运行时间记录
                if (esb_get_tx_connect_state() == false)
                {
                    esb_set_tx_connect_state(true);
                    main_send_signal(SIGNAL_REFRESH_RF_INDICATOR_LIGHT);
                }
            }
            break;

        case NRF_ESB_EVENT_TX_FAILED:
            // 发送失败,切换频道继续发送
            rf_tx_freq_index++;
            if (rf_tx_freq_index >= RF_FREQ_MAX_VAL)
            {
                // LOG_D("NRF_ESB_EVENT_TX_FAILED");
                rf_tx_freq_index = 0;
            }
            nrf_esb_set_rf_channel(rf_freq_table[rf_tx_freq_index]);
            nrf_esb_start_tx();
            break;

        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)
                {
                    esb_clean_rx_heart_time();
                    esb_set_rx_connect_state(true);
                    // LOG_D("data:%02x,%02x,%02x,%02x,%02x|%02x", rx_payload.data[0], rx_payload.data[1],
                    //        rx_payload.data[2], rx_payload.data[3], rx_payload.data[4], rx_payload.length);
                    // 跳转业务处理函数
                    if (g_rx_dispose_callback)
                    {
                        g_rx_dispose_callback(rx_payload.data, rx_payload.length);
                    }
                }
            }
            break;
    }
}

/**
 * @brief  [ESB操作][得到指针] 射频通道数组
 * @retval 返回射频通道数组指针,长度由RF_FREQ_MAX_VAL决定
 */
uint8_t *esb_get_rf_freq_table(void)
{
    return rf_freq_table;
}

/**
 * @brief  [ESB操作][得到指针] 得到新的MAC地址数组
 * @retval 返回MAC地址数组指针,长度由RF_MAC_MAX_VAL决定
 */
uint8_t *esb_get_new_rf_mac_addr(void)
{
    random_vector_generate(rf_mac_addr, RF_MAC_MAX_VAL);
    return rf_mac_addr;
}

/**
 * @brief  [ESB操作][得到指针] MAC地址数组
 * @retval 返回MAC地址数组指针,长度由RF_MAC_MAX_VAL决定
 */
uint8_t *esb_get_rf_mac_addr(void)
{
    return rf_mac_addr;
}

/**
 * @brief  [ESB操作] MAC重置,取随机值
 */
void esb_rf_mac_init(void)
{
    uint8_t *mac_addr_temp = esb_get_rf_mac_addr();
    if (mac_addr_temp[0] == 0x55 &&
        mac_addr_temp[1] == 0x56 &&
        mac_addr_temp[2] == 0x57 &&
        mac_addr_temp[3] == 0x58 &&
        mac_addr_temp[4] == 0x59)
    {
        random_vector_generate(mac_addr_temp, RF_MAC_MAX_VAL);
        g_flash_write_24g_mac_flag = true;
        LOG_D("<DEBUG> NEW_MAC:%02x %02x %02x %02x %02x\r\n", esb_get_rf_mac_addr()[0], esb_get_rf_mac_addr()[1],
              esb_get_rf_mac_addr()[2], esb_get_rf_mac_addr()[3], esb_get_rf_mac_addr()[4]);
    }
}

/*------------------------------------------------【发送端】------------------------------------------------*/
/**
 * @brief  [ESB操作][发送端] ESB初始化
 * @retval 状态
 */
uint32_t esb_tx_init(void)
{
    if (g_esb_init_flag)
    {
        return 0;
    }
    g_esb_init_flag = true;
    uint32_t err_code;

    addr_prefix[2] = rf_mac_addr[0];
    base_addr_1[0] = rf_mac_addr[1];
    base_addr_1[1] = rf_mac_addr[2];
    base_addr_1[2] = rf_mac_addr[3];
    base_addr_1[3] = rf_mac_addr[4];

    nrf_esb_config_t nrf_esb_config   = NRF_ESB_DEFAULT_CONFIG;
    nrf_esb_config.protocol           = NRF_ESB_PROTOCOL_ESB_DPL;
    nrf_esb_config.retransmit_delay   = 250;
    nrf_esb_config.retransmit_count   = 3;
    nrf_esb_config.bitrate            = NRF_ESB_BITRATE_2MBPS;
    nrf_esb_config.event_handler      = nrf_esb_event_handler;
    nrf_esb_config.mode               = NRF_ESB_MODE_PTX;
    nrf_esb_config.selective_auto_ack = false;
    nrf_esb_config.crc                = NRF_ESB_CRC_16BIT;
    nrf_esb_config.tx_output_power    = NRF_ESB_TX_POWER_4DBM;
    nrf_esb_config.payload_length     = 32;

    err_code = nrf_esb_init(&nrf_esb_config);

    VERIFY_SUCCESS(err_code);

    err_code = nrf_esb_set_base_address_0(base_addr_0);
    VERIFY_SUCCESS(err_code);

    err_code = nrf_esb_set_base_address_1(base_addr_1);
    VERIFY_SUCCESS(err_code);

    err_code = nrf_esb_set_prefixes(addr_prefix, NRF_ESB_PIPE_COUNT);
    VERIFY_SUCCESS(err_code);

    tx_payload.pipe = 2;
    
    return err_code;
}

/**
 * @brief  [ESB操作][发送端][得到状态] 2.4G连接状态
 * @retval false--未连接 ture--已连接
 */
bool esb_get_tx_connect_state(void)
{
    return rf_tx_connect_status;
}

/**
 * @brief  [ESB操作][发送端][设置状态] 2.4G连接状态
 * @param  state: false--未连接 ture--已连接
 */
void esb_set_tx_connect_state(bool state)
{
    rf_tx_connect_status = state;
}

/**
 * @brief  [ESB操作][发送端][复位变量] 清除[发送心跳]次数和连接时间
 */
void esb_clean_tx_heart_time(void)
{
    rf_tx_heart_tick   = 0;
    rf_tx_connect_time = 0;
}

/**
 * @brief  [ESB操作][发送端][操作变量] 心跳次数递增1
 */
void esb_heart_tx_tick_add(void)
{
    rf_tx_heart_tick++;
}

/**
 * @brief  [ESB操作][发送端][得到变量值] 心跳次数
 * @retval 心跳次数
 */
uint8_t esb_get_heart_tx_tick(void)
{
    return rf_tx_heart_tick;
}

/**
 * @brief  [ESB操作][发送端][发送数据] 发送一包数据(异步)
 * @note   异步发送
 * @param  *pdata: 待发送的数据指针
 * @param  len: 数据长度
 * @retval 发送状态
 */
uint32_t esb_tx_send(uint8_t *pdata, uint8_t len)
{
    tx_payload.length = len;
    memcpy(tx_payload.data, pdata, len);
    return nrf_esb_write_payload(&tx_payload);;
}

const uint8_t g_heart_array = 0;
/**
 * @brief  [ESB操作][发送端] 发送心跳包
 */
void esb_send_heart_pack(void)
{
    //*************[ESB 2.4G操作] 实现心跳包**********************
    esb_heart_tx_tick_add();
    if (esb_get_heart_tx_tick() > 3)
    {
        send_rf_data((uint8_t *)&g_heart_array, 1);
        rf_tx_connect_time++;
        if (rf_tx_connect_time > 3)
        {
            esb_clean_tx_heart_time();
            if (esb_get_tx_connect_state() == true)
            {
                esb_set_tx_connect_state(false);
                main_send_signal(SIGNAL_REFRESH_RF_INDICATOR_LIGHT);
            }
        }
    }
}

/**
 * @brief  发送数据给rf通道(消息入队,非实时发送)
 * @param  *data: 欲发送内容
 * @param  len: 内容长度(字节大小)
 */
void send_rf_data(uint8_t *data, uint16_t len)
{
    if (!queue_en(&m_rf_tx_q, data, len))
    {
        LOG_D("<DEBUG> [send_rf_data] queue_en fail\r\n");
    }
}

/**
 * @brief  处理消息队列中的消息,通过rf发送(放在空闲线程使用)
 */
bool rf_data_dispose(void)
{
    if (!queue_de(&m_rf_tx_q, g_rf_tx_data))
        return false;
    esb_tx_send(g_rf_tx_data, RF_TX_Q_ITEM_SIZE);
    return true;
}

void esb_set_rf_and_start_tx(void)
{
    nrf_esb_set_rf_channel(rf_freq_table[rf_tx_freq_index]);
    nrf_esb_start_tx();
}

/*------------------------------------------------【接收端】------------------------------------------------*/

/**
 * @brief  [ESB操作][接收端] ESB初始化
 * @retval 状态
 */
uint32_t esb_rx_init(void)
{
    if (g_esb_init_flag)
    {
        return 0;
    }
    g_esb_init_flag = true;
    uint32_t err_code;

    addr_prefix[2] = rf_mac_addr[0];
    base_addr_1[0] = rf_mac_addr[1];
    base_addr_1[1] = rf_mac_addr[2];
    base_addr_1[2] = rf_mac_addr[3];
    base_addr_1[3] = rf_mac_addr[4];

    nrf_esb_config_t nrf_esb_config   = NRF_ESB_DEFAULT_CONFIG;
    nrf_esb_config.protocol           = NRF_ESB_PROTOCOL_ESB_DPL;
    nrf_esb_config.bitrate            = NRF_ESB_BITRATE_2MBPS;
    nrf_esb_config.event_handler      = nrf_esb_event_handler;
    nrf_esb_config.mode               = NRF_ESB_MODE_PRX;
    nrf_esb_config.selective_auto_ack = false;
    nrf_esb_config.crc                = NRF_ESB_CRC_16BIT;
    nrf_esb_config.tx_output_power    = NRF_ESB_TX_POWER_4DBM;
    nrf_esb_config.payload_length     = 32;

    err_code = nrf_esb_init(&nrf_esb_config);
    VERIFY_SUCCESS(err_code);

    err_code = nrf_esb_set_base_address_0(base_addr_0);
    VERIFY_SUCCESS(err_code);

    err_code = nrf_esb_set_base_address_1(base_addr_1);
    VERIFY_SUCCESS(err_code);

    err_code = nrf_esb_set_prefixes(addr_prefix, NRF_ESB_PIPE_COUNT);
    VERIFY_SUCCESS(err_code);

    return err_code;
}

/**
 * @brief  [ESB操作][接收端][设置状态] 2.4G连接状态
 * @param  state: false--未连接 ture--已连接
 */
void esb_set_rx_connect_state(bool state)
{
    rf_rx_connect_status = state;
}

/**
 * @brief  [ESB操作][接收端][得到状态] 2.4G连接状态
 * @retval false--未连接 ture--已连接
 */
bool esb_get_rx_connect_state(void)
{
    return rf_rx_connect_status;
}

/**
 * @brief  [ESB操作][接收端][复位变量] 清除[发送心跳]次数和连接时间
 */
void esb_clean_rx_heart_time(void)
{
    rf_rx_heart_time   = 0;
}

/**
 * @brief  [ESB操作][接收端][操作变量] 心跳次数递增1
 */
void esb_heart_rx_tick_add(void)
{
    rf_rx_heart_time++;
}

/**
 * @brief  [ESB操作][接收端][得到变量值] 心跳次数
 * @retval 心跳次数
 */
uint8_t esb_get_heart_rx_tick(void)
{
    return rf_rx_heart_time;
}

/**
 * @brief  [ESB操作][接收端] 接收超时则切换通道
 */
void esb_receipt_heart_pack(void)
{
    esb_heart_rx_tick_add();
    if (esb_get_heart_rx_tick() > 4)
    {
        esb_clean_rx_heart_time();
        rf_rx_freq_index++;
        if (rf_rx_freq_index >= RF_FREQ_MAX_VAL)
        {
            rf_rx_freq_index = 0;
        }
        nrf_esb_set_rf_channel(rf_freq_table[rf_rx_freq_index]);
        nrf_esb_start_rx();
        if (esb_get_rx_connect_state() == true)
        {
            esb_set_rx_connect_state(false);
        }
    }
}

void esb_set_rf_and_start_rx(void)
{
    nrf_esb_set_rf_channel(rf_freq_table[rf_rx_freq_index]);
    nrf_esb_start_rx();
}

/**
 * @brief  [ESB操作][接收端] ESB注册数据接收函数
 * @param  *event: 绑定的函数指针
 * @retval false--错误 ture--正确
 */
bool biz_esb_rx_dispose_reg_callback(void *event)
{
    if (g_rx_dispose_callback != NULL)
    {
        return false;
    }
    else
    {
        g_rx_dispose_callback = (esb_rx_event_callback)event;
    }
    return true;
}

/********************************************************************************
* @file    biz_esb.h
* @author  jianqiang.xue
* @version V1.0.0
* @date    2021-07-06
* @brief   [业务]2.4G管理
********************************************************************************/

#ifndef __BIZ_ESB_H
#define __BIZ_ESB_H

/* Public Include ------------------------------------------------------------*/
#include <stdint.h>
#include <stdbool.h>
/* Public Define -------------------------------------------------------------*/
/* External Variables --------------------------------------------------------*/
extern bool g_flash_write_24g_mac_flag;
extern bool g_flash_write_24g_freq_flag;

/* Public Function Prototypes ------------------------------------------------*/
uint32_t esb_tx_init(void);
uint32_t esb_rx_init(void);
void esb_deinit(void);

void esb_rf_mac_init(void);
uint32_t esb_tx_send(uint8_t *pdata, uint8_t len);

uint8_t *esb_get_rf_freq_table(void);
uint8_t *esb_get_rf_mac_addr(void);
uint8_t *esb_get_new_rf_mac_addr(void);

void send_rf_data(uint8_t *data, uint16_t len);
bool rf_data_dispose(void);

// 发送端 功能函数
void esb_send_heart_pack(void);
void esb_clean_tx_heart_time(void);
uint8_t esb_get_heart_tx_tick(void);
void esb_heart_tx_tick_add(void);

bool esb_get_tx_connect_state(void);
void esb_set_tx_connect_state(bool state);

void esb_set_rf_and_start_tx(void);


// 接收端 功能函数
void esb_receipt_heart_pack(void);
void esb_clean_rx_heart_time(void);
uint8_t esb_get_heart_rx_tick(void);
void esb_heart_rx_tick_add(void);

bool esb_get_rx_connect_state(void);
void esb_set_rx_connect_state(bool state);

void esb_set_rf_and_start_rx(void);

bool biz_esb_rx_dispose_reg_callback(void *event);

#endif

伪代码,演示使用:

/**
  * @brief  [软定时器回调事件] 用于进入低功耗【前期】处理  基准100ms
  * @note   让系统进入低功耗模式
  */
static void timer_low_power(void const *argument)
{
    if (get_comm_connect_state() == SYS_CONNECT_TYPE_RF)
    {
        g_sys_run_times += TIMER_LOW_POWER_PERIOD;
    }
    else
    {
        g_sys_run_times = 0;
    }
    g_free_times ++;
#if BS_24G_SUPPORT
    if (get_sys_state() == SYS_STATE_POWER_ON)
    {
        if (get_comm_connect_state() == SYS_CONNECT_TYPE_RF)
        {
            main_send_signal(SIGNAL_RF_SEND_HEART_PACK);
        }
    }
#endif
}

//主线程信号量
        if (event.value.signals & SIGNAL_RF_SEND_HEART_PACK)
        {
            esb_send_heart_pack();
        }

/**
 * @brief  线程空闲处理函数
 */
static void idle_state_handle(void)
{
    static uint16_t tick = 1;
    static uint16_t g_free_tick = 1;
    tick++;
    g_free_tick++;
    if (tick % 1000 == 0)
    {
        app_task_led();
        if (get_comm_connect_state() == SYS_CONNECT_TYPE_RF)
        {
#if BS_24G_SUPPORT
            if (rf_data_dispose())
            {
                LOG_D("<DEBUG> [RF] send ok!!!\r\n");
                g_free_tick = 0;
                return;
            }
#endif
        }
        if (g_free_tick > 3000 && flash_write_sys_cfg())
        {
            g_free_tick = 0;
            return;
        }
        else
        {
#if !DEBUG_MODE
            if (g_free_tick > 10000)
            {
                sys_sleep();
            }
#endif
        }
}
posted on 2022-08-13 11:00  xuejianqiang  阅读(129)  评论(0编辑  收藏  举报
打造一个通用性MCU架构,支持CX32/AT32/NRF51/NRF52等。 OS支持RTX4/RTX5/FreeRtos。 采用VsCode+GCC组合,VsCode+KEIL5,超强开发方式。 QQ群:524408033