zl程序教程

您现在的位置是:首页 >  其他

当前栏目

NRF52840 DFU & APP使用noinit ram方法

ampApp方法 RAM 使用
2023-09-14 09:06:41 时间

编译环境Keil,NRF52840 S140协议栈为例使用noinit ram将APP的广播ID序列号存到非初时化ram区,DFU时取出内容id并广播出来,要求APP广播名为S140_XXXXXX,DFU广播名为DFU_XXXXXX,保存2者的id号要一致,如下步骤实现数据在软件复位的情况下进行数据保存不丢失

  • 应用程序广播名拼接
#define DEVICE_NAME                     "S140_"     
uint32_t test_id = 10086;
/**@brief Function for the GAP initialization.
 *
 * @details This function will set up all the necessary GAP (Generic Access Profile) parameters of
 *          the device. It also sets the permissions and appearance.
 */
static void gap_params_init(void)
{
    uint32_t                err_code;
    ble_gap_conn_params_t   gap_conn_params;
    ble_gap_conn_sec_mode_t sec_mode;

    BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode);
    char buf[32];
	  uint8_t name_len = sprintf(buf,"%s%06u",DEVICE_NAME,test_id);
		
    err_code = sd_ble_gap_device_name_set(&sec_mode,
                                          (const uint8_t *) buf,
                                          name_len);
    APP_ERROR_CHECK(err_code);

    memset(&gap_conn_params, 0, sizeof(gap_conn_params));

    gap_conn_params.min_conn_interval = MIN_CONN_INTERVAL;
    gap_conn_params.max_conn_interval = MAX_CONN_INTERVAL;
    gap_conn_params.slave_latency     = SLAVE_LATENCY;
    gap_conn_params.conn_sup_timeout  = CONN_SUP_TIMEOUT;

    err_code = sd_ble_gap_ppcp_set(&gap_conn_params);
    APP_ERROR_CHECK(err_code);
}

  • 定义noinit地址范围,在keil target下配置 在这里插入图片描述
  • 这里在RAM的末尾配置16字节noinit RAM,因为NRF52840_xxAA的RAM大小为256KB,那么
    IRAM1 Start + Size = IRAM2 Start
    IRAM2 Start + Size = 256 * 1024 = 0x40000,则
    IRAM2 Start = 0x20002AE8 + 0X3D508 = 0x2003FFF0
    IRAM2 Start 0x2003FFF0 + 0x10 = 0x40000,刚好是NRF52840_xxAA RAM的总大小值
  • 定义保存ID的变量类型
typedef struct
{
	uint8_t id[8];
	uint32_t flag;
}noinit_data_info_t;
  • 定义变量并指定到0x2003FFF0地址

#define __noinit__ __attribute__((at(0x2003FFF0)))   
__noinit__ noinit_data_info_t noinit_data;
  • 保存ID函数实现
/**
* @brieaf 保存ID
*/
/**
* @brieaf 保存ID
*/
void save_id_to_noinit_ram(void)
{
	memset(&noinit_data,0,sizeof(noinit_data));
	sprintf((char*)noinit_data.id,"%06u",test_id);
	noinit_data.flag = 0x55AAAA55;
}
  • 进入DFU前调用save_id_to_noinit_ram函数,这里仅接收到任意数据都会进入DFU
void save_id_to_noinit_ram(void);
/**@brief Function for handling the data from the Nordic UART Service.
 *
 * @details This function will process the data received from the Nordic UART BLE Service and send
 *          it to the UART module.
 *
 * @param[in] p_evt       Nordic UART Service event.
 */
/**@snippet [Handling the data received over BLE] */
static void nus_data_handler(ble_nus_evt_t * p_evt)
{

    if (p_evt->type == BLE_NUS_EVT_RX_DATA)
    {
		save_id_to_noinit_ram();
        sd_power_gpregret_clr(0,0xffffffff); 
		sd_power_gpregret_set(0,0xb1);
		NVIC_SystemReset();
    }

}

DFU工程配置RAM

在这里插入图片描述

  • 定义变量类型及变量同APP工程一致

typedef struct
{
	uint8_t id[8];
	uint32_t flag;
}noinit_data_info_t;


#define __noinit__ __attribute__((at(0x2003FFF0)))   
__noinit__ noinit_data_info_t noinit_data;
  • 获取ID函数
uint8_t *get_id_string(void)
{
	if(noinit_data.flag != 0x55AAAA55) //默认ID为1
	{
		noinit_data.id[0] = '0';
		noinit_data.id[1] = '0';
		noinit_data.id[2] = '0';
		noinit_data.id[3] = '0';
		noinit_data.id[4] = '0';
		noinit_data.id[5] = '1';
		noinit_data.id[6] = '\0';
	}
	return noinit_data.id;
}
  • sdk_config.h定义DFU_前缀名称
// <s> NRF_DFU_BLE_ADV_NAME - Default advertising name.
#ifndef NRF_DFU_BLE_ADV_NAME
#define NRF_DFU_BLE_ADV_NAME "DFU_"
#endif
  • 修改nrf_dfu_ble.c中gap_params_init函数中的内容
uint8_t *get_id_string(void);
/**@brief     Function for initializing GAP.
 *
 * @details   This function sets up all necessary GAP (Generic Access Profile) parameters of
 *            the device. It also sets the permissions and appearance.
 */
static uint32_t gap_params_init(void)
{
    uint32_t                err_code;
    ble_gap_conn_sec_mode_t sec_mode;
    uint8_t const *         device_name;
    uint32_t                name_len;

    BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode);

#if (!NRF_DFU_BLE_REQUIRES_BONDS)

    err_code = gap_address_change();
    VERIFY_SUCCESS(err_code);

    if ((m_flags & DFU_BLE_FLAG_USE_ADV_NAME) != 0)
    {
        NRF_LOG_DEBUG("Setting adv name: %s, length: %d", m_adv_name.name, m_adv_name.len);
        device_name = m_adv_name.name;
        name_len    = m_adv_name.len;
    }
    else
#endif
    {
        NRF_LOG_DEBUG("Using default advertising name");
      //#############################################################
        // 以下是修改的内容
			  uint8_t buf[32];
			  memset(buf,0,sizeof(buf));
			  name_len  = strlen(NRF_DFU_BLE_ADV_NAME);
		 	  uint8_t const *pName = (uint8_t const *)(NRF_DFU_BLE_ADV_NAME);
			 for(uint8_t i=0; i<name_len; i++)
			{
				buf[i] = pName[i];
			}
			pName = get_id_string();
			 for(uint8_t i=0; i<6; i++)
			{
				buf[name_len] = pName[i];
				name_len++;
			}
			
       device_name = (uint8_t const *)buf;
     //#################################################################   
    }

    err_code = sd_ble_gap_device_name_set(&sec_mode, device_name, name_len);
    VERIFY_SUCCESS(err_code);

    err_code = sd_ble_gap_ppcp_set(&m_gap_conn_params);
    return err_code;
}
  • 删除APP和DFU工程中的_build文件夹里的内容,编译2个工程,烧录运行,APP扫描蓝牙名称如下
    在这里插入图片描述
  • 连接并发送任意字符进入DFU,DFU文播DFU_010086,后缀ID和APP后缀成功保持一致了
    在这里插入图片描述
  • 加载升级包升级
    在这里插入图片描述

源码下载