问题原因:

bootloader的程序区域是0X78000~0X7E000

但是在bootloader程序中定义了0X0FF8与0XFFC位置处的数据,此数据与BLE协议栈冲突,BLE协议栈的flash范围是0~0X25FFF,所以烧录协议栈后不能用JLINK仿真

具体在bootloader中的代码为:

/** @brief Location (in the flash memory) of the bootloader address. */
#define MBR_BOOTLOADER_ADDR      (0xFF8)
/** @brief Location (in UICR) of the bootloader address. */
#define MBR_UICR_BOOTLOADER_ADDR (&(NRF_UICR->NRFFW[0]))
/** @brief Location (in the flash memory) of the address of the MBR parameter page. */
#define MBR_PARAM_PAGE_ADDR      (0xFFC)
 
    uint32_t const m_uicr_mbr_params_page_address
        __attribute__((at(NRF_UICR_MBR_PARAMS_PAGE_ADDRESS))) = NRF_MBR_PARAMS_PAGE_ADDRESS;
 
    uint32_t  m_uicr_bootloader_start_address __attribute__((at(NRF_UICR_BOOTLOADER_START_ADDRESS)))
                                                    = BOOTLOADER_START_ADDR;
 
代码中使用__attribute__强制定义了数据在flash中的存储位置,所以烧录不成功
bootloader的hex文件部分内容:

修改bootloader:

1、为了能用JLINK烧录APP后能从升级程序正常跳转到APP程序,修改bootloader,屏蔽APP_CRC校验功能改为检查APP首地址是否为0X20000000

//    else if (!boot_validate(&s_dfu_settings.boot_validation_app, nrf_dfu_bank0_start_addr(), s_dfu_settings.bank_0.image_size, do_crc))//DEBUG_D
//    {
//        NRF_LOG_WARNING("Boot validation failed. App is invalid.");
//        return false;
//    }
 else if(((*(volatile uint32_t*)0x26000)&0x2FFE0000) != 0x20000000) //DEBUG_D
 {
  NRF_LOG_WARNING("Boot validation failed. App is invalid.");
  return false;
 }

修改bank0区的验证条件if (s_dfu_settings.bank_0.bank_code != NRF_DFU_BANK_VALID_APP)为:

if (s_dfu_settings.bank_0.bank_code != NRF_DFU_BANK_VALID_APP && s_dfu_settings.bank_0.image_size != 0 && s_dfu_settings.bank_0.image_crc != 0)

2、为了能够使用JLINK调试bootloader'程序,需要做如下修该:

修改bootloader中
// uint32_t const m_uicr_mbr_params_page_address
// __attribute__((at(NRF_UICR_MBR_PARAMS_PAGE_ADDRESS))) = NRF_MBR_PARAMS_PAGE_ADDRESS;为
uint32_t m_uicr_mbr_params_page_address = NRF_MBR_PARAMS_PAGE_ADDRESS;

// uint32_t m_uicr_bootloader_start_address __attribute__((at(NRF_UICR_BOOTLOADER_START_ADDRESS))) = BOOTLOADER_START_ADDR;为
uint32_t m_uicr_bootloader_start_address = BOOTLOADER_START_ADDR;
取消使用__attribute__对flash存储位置的强制定义,因为数据被定义在flash位置0XFF8与0XFFC区,与SD协议栈重合,导致bootloader代码烧录不进去,不能在线调试

3、为了能够使用双备份升级以及升级过程中蓝牙突然断开导致的升级中断,之前的APP能够继续使用,作如下修改:

    if (NRF_DFU_SETTINGS_COMPATIBILITY_MODE && !NRF_DFU_IN_APP && (s_dfu_settings.settings_version == 1))
    {
        NRF_LOG_INFO("Old settings page detected. Upgrading info.");
        // Old version. Translate.
        memcpy(&s_dfu_settings.peer_data, (uint8_t *)&s_dfu_settings + DFU_SETTINGS_BOND_DATA_OFFSET_V1, NRF_DFU_PEER_DATA_LEN);
        memcpy(&s_dfu_settings.adv_name,  (uint8_t *)&s_dfu_settings + DFU_SETTINGS_ADV_NAME_OFFSET_V1,  NRF_DFU_ADV_NAME_LEN);
        // Initialize with defaults.
        s_dfu_settings.boot_validation_softdevice.type = NO_VALIDATION;
        s_dfu_settings.boot_validation_app.type        = VALIDATE_CRC;
        s_dfu_settings.boot_validation_bootloader.type = NO_VALIDATION;
        memcpy(s_dfu_settings.boot_validation_app.bytes, &s_dfu_settings.bank_0.image_crc, sizeof(uint32_t));
        s_dfu_settings.settings_version = NRF_DFU_SETTINGS_VERSION;
    }
 
//升级程序中需要加入的代码
 #define BANK1_BAKEUP_START_ADDR  0X53000 //备份程序起始地址
 #define BNAK0_APP_START_ADDR  0X26000 //应用程序起始地址
 s_dfu_settings.bank_0.image_crc = 0;
 s_dfu_settings.bank_0.image_size = BANK1_BAKEUP_START_ADDR - BNAK0_APP_START_ADDR;
 s_dfu_settings.write_offset = 0;
 
    err_code = nrf_dfu_settings_write_and_backup(NULL);
    if (err_code != NRF_SUCCESS)
    {
        NRF_LOG_ERROR("nrf_dfu_settings_write_and_backup() failed with error: %x", err_code);
        return NRF_ERROR_INTERNAL;
    }
4、在boot跳转到APP的函数中屏蔽掉对APP的代码保护,因为APP到备份区之间有一片flash用存储掉电保持的数据,如果不屏蔽代码保护会导致写flash出错,血的教训啊,具体修改如下:
void nrf_bootloader_app_start_final(uint32_t vector_table_addr)
{
    ret_code_t ret_val;
    // Protect MBR & bootloader code and params pages.
    if (NRF_BOOTLOADER_READ_PROTECT)
    {
        ret_val = nrf_bootloader_flash_protect(0, MBR_SIZE, NRF_BOOTLOADER_READ_PROTECT);
    }
    // Size of the flash area to protect.
    uint32_t area_size;
    area_size = BOOTLOADER_SIZE + NRF_MBR_PARAMS_PAGE_SIZE;
    ret_val = nrf_bootloader_flash_protect(BOOTLOADER_START_ADDR,
                                           area_size,
                                           NRF_BOOTLOADER_READ_PROTECT);
    if (!NRF_BOOTLOADER_READ_PROTECT && (ret_val != NRF_SUCCESS))
    {
        NRF_LOG_ERROR("Could not protect bootloader and settings pages, 0x%x.", ret_val);
    }
//屏蔽对APP程序区的代码保护
//    ret_val = nrf_bootloader_flash_protect(0,
//                                           nrf_dfu_bank0_start_addr() + s_dfu_settings.bank_0.image_size,
//                                           false);
    if (!NRF_BOOTLOADER_READ_PROTECT && (ret_val != NRF_SUCCESS))
    {
        NRF_LOG_ERROR("Could not protect SoftDevice and application, 0x%x.", ret_val);
    }
    // Run application
    app_start(vector_table_addr);
}

APP跳转到bootloader方法:

进入bootloader条件:

1、APP校验不通过(if (!app_is_valid(crc_on_valid_app_required())))

2、升级按键按下(if (NRF_BL_DFU_ENTER_METHOD_BUTTON && (nrf_gpio_pin_read(NRF_BL_DFU_ENTER_METHOD_BUTTON_PIN) == 0)))

3、复位引脚按下(if (NRF_BL_DFU_ENTER_METHOD_PINRESET && (NRF_POWER->RESETREAS & POWER_RESETREAS_RESETPIN_Msk)))

4、NRF_POWER_GPREGRET寄存器置1(if (NRF_BL_DFU_ENTER_METHOD_GPREGRET && (nrf_power_gpregret_get() & BOOTLOADER_DFU_START)))

NRF_POWER_GPREGRET寄存器是一个保持寄存器,在软复位的情况下自动保持,外部复位时清除。

5、使能无按钮模式且enter_buttonless_dfu置1(if (NRF_BL_DFU_ENTER_METHOD_BUTTONLESS && (s_dfu_settings.enter_buttonless_dfu == 1)))

应用程序使用第四种方法进入BOOT,当需要从应用程序跳转到bootloader时,可以参考Buttonless中处理的方式来做:

uint32_t ble_dfu_buttonless_bootloader_start_finalize(void)
{
    uint32_t err_code;
    NRF_LOG_DEBUG("In ble_dfu_buttonless_bootloader_start_finalize\r\n");
    err_code = sd_power_gpregret_clr(0, 0xffffffff);
    VERIFY_SUCCESS(err_code);
    err_code = sd_power_gpregret_set(0, BOOTLOADER_DFU_START);
    VERIFY_SUCCESS(err_code);
    // Indicate that the Secure DFU bootloader will be entered
    m_dfu.evt_handler(BLE_DFU_EVT_BOOTLOADER_ENTER);
    // Signal that DFU mode is to be enter to the power management module
    nrf_pwr_mgmt_shutdown(NRF_PWR_MGMT_SHUTDOWN_GOTO_DFU);
    return NRF_SUCCESS;
}
简化后的代码为:
void EnterDFU(void)
{
  #define BOOTLOADER_DFU_GPREGRET_MASK            (0xB0)         
  #define BOOTLOADER_DFU_START_BIT_MASK           (0x01)     
  #define BOOTLOADER_DFU_START        (BOOTLOADER_DFU_GPREGRET_MASK | BOOTLOADER_DFU_START_BIT_MASK)
  sd_power_gpregret_clr(0,0xffffffff);
  sd_power_gpregret_set(BOOTLOADER_DFU_START);
  nrf_pwr_mgmt_shutdown(NRF_PWR_MGMT_SHUTDOWN_GOTO_DFU);
  NVIC_SystemReset();
}
特别注意:, 根据官方的答复,写GPREGRET寄存器之前,需要先Clear
 
参考文章:https://blog.csdn.net/musicalspace/article/details/87863744

NORDIC 烧录BLE协议栈后不能用JLINK仿真bootloader问题及修改方案的更多相关文章

  1. 深入浅出低功耗蓝牙(BLE)协议栈

    深入浅出低功耗蓝牙(BLE)协议栈 BLE协议栈为什么要分层?怎么理解蓝牙"连接"?如果蓝牙协议只有ATT没有GATT会发生什么? 协议栈框架 一般而言,我们把某个协议的实现代码称 ...

  2. TI BLE协议栈软件框架分析

    看源代码的时候,一般都是从整个代码的入口处开始,TI  BLE 协议栈源码也不例外.它的入口main()函数就是整个程序的入口,由系统上电时自动调用. 它主要做了以下几件事情: (一)底层硬件初始化配 ...

  3. BLE协议栈及传统蓝牙协议栈对比图

    1. BLE协议栈的层次图如下: 主机控制接口层: 为主机和控制器之间提供标准通信接口 逻辑链路控制及自适应协议层: 为上层提供数据封装服务 安全管理层: 定义配对和密钥分配方式,为协议栈其他层与另一 ...

  4. 深入浅出讲解低功耗蓝牙(BLE)协议栈

    详解BLE连接建立过程https://www.cnblogs.com/iini/p/8972635.html 详解BLE 空中包格式—兼BLE Link layer协议解析https://www.cn ...

  5. 蓝牙BLE: 蓝牙(BLE)协议栈

    蓝牙协议是通信协议的一种,一般而言,我们把某个协议的实现代码称为协议栈(protocol stack),BLE协议栈就是实现低功耗蓝牙协议的代码,理解和掌握BLE协议是实现BLE协议栈的前提.当前的蓝 ...

  6. CentOS 7合盖后黑屏但不进入睡眠模式修改

    CentOS 7合盖后黑屏但不进入睡眠模式修改 systemd 能够处理某些电源相关的 ACPI事件,你可以通过从 /etc/systemd/logind.conf 以下选项进行配置: HandleP ...

  7. 【转】TI蓝牙BLE 协议栈代码学习

    BLE就是低功率蓝牙.要着重了解两种设备: dual-mode双模设备:简单说就是向下兼容. single-mode单模设备:仅仅支持BLE.   关于开发主要讲的是单模设备,它可以只靠纽扣电池即可持 ...

  8. TI CC2541 BLE协议栈蓝牙MAC 地址

    在Flash中有一块只读区域,从地址0x780E开始,蓝牙的MAC以小端方式存放在里面. 在TI的Peripheral例程里面,添加一个特征值,只读属性,6字节长度(蓝牙MAC长度为48-bit,6字 ...

  9. 解决 Orange Pi 烧录完系统后剩余可用空间过少的问题

    输入命令 df -ha 这图是拿别人的 看到系统才使用3.2g,内存卡有16g,不可能满的. 执行命令,加上sudo,防止权限不够: sudo fs_resize 如果上面那个不行的话,试试这个命令( ...

随机推荐

  1. easyui-datagrid配置宽度高度自适应

    在style属性中,去除之前添加的width和height属性(如果有的话),然后添加"fit:false"即可.

  2. 使用sort,uniq去重并统计出现次数

    测试文档test 1 2 3 4 1 2 1 1 sort把相同的放在一起 [root@salt-test ~]# sort test 1 1 1 1 2 2 3 4 uniq -c统计出现的次数 [ ...

  3. 使用python或robotframework调multipart/form-data接口上传文件

    这几天调一个multipart/form-data类型的接口,遇到点小阻碍.之前同事有使用urllib库写了个类似的方法实现,比较长,想要改的时候发现不太好使.在网上查找发现用requests库做这个 ...

  4. Qt598x64vs2017.跨线程传递std::string

    1.Qt编译的时候 提示 str::string 需要在main(...)中注册什么的(大概是这个意思,记不清了),于是 在main(...)中调用了 “qRegisterMetaType<st ...

  5. 性能优化-Bitmap内存管理及优化

    Bitmap作为重要Android应用之一,在很多时候如果应用不当,很容易造成内存溢出,那么这篇文章的目的就在于探讨Bitmap的有效运用及其优化 缓存介绍 当多次发送请求的时候,请求同一内容,为了使 ...

  6. webpack官网demo起步中遇到的问题

    在webpack官网demo一开始搭建中 

  7. Z1. 广度优先搜索(BFS)解题思路

    /** BFS 解题思路 特点:从某些特定的节点开始,感染相邻的节点; 被感染的节点,再感染其相邻的节点,以此类推. 题目常见于数据结构包括 二维数组.树.图 **/ /** 1). 二维数组特定节点 ...

  8. Windows Terminal Preview v0.7 Release

    Windows Terminal Preview v0.7 Release The following key bindings are included by default within this ...

  9. setting中executable for debug session对话框

  10. 使用HSE配置系统时钟并用MCO输出监测系统时钟

    使用模板,在User下新建文件夹RCC 新建bsp_rccclkconfig.h和bsp_rccclkconfig.c 工程和魔术棒添加 对照着上节的RCC源文件编写: void HSE_SetSys ...