问题原因:

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. laravel输出HTML内容

    blade模板引擎中的{{ $xxx }}表达式的返回值将被自动传递给 PHP 的 htmlentities 函数进行处理,以防止 XSS 攻击. 如果需要展示未转义的数据,可以使用{!! $xxx ...

  2. [简短问答]LODOP如何查看用LODOP打印设计的代码

    该博文为图文简短问答,具体详细介绍可查看本博客的相关博文,生成JS代码相关详细博文:Lodop打印设计(PRINT_DESIGN)介绍.Lodop打印设计.维护.预览.直接打印简单介绍.Lodop打印 ...

  3. <configSections> 位置引起的错误

    今天在配置一个项目的时候,花了挺长时间配置完成,然后一启动项目,懵了,启动报错:错误显示 Configuration Error Description: An error occurred duri ...

  4. .git泄露及利用php弱类型松散比较构造json的payload

    一道ctf题,文章搬运到了自己的网站上: http://101.132.137.140:202/archives/2019-11-16

  5. Mybatis表关联一对多、多对一、多对多

    项目工程结构如下: 1. 搭建MyBatis框架环境 首先需要引入两个包:mybatis.jar 和 sqljdbc42.jar包 若分页需要导入两个包:pagehelper-5.1.0.jar 和 ...

  6. Haystack--基于Django的全文检索框架

    好文章转载自:https://suguangti.cnblogs.com/p/11167097.html 阅读目录 1.什么是Haystack 2.安装 3.配置 4.处理数据 创建索引 5.设置视图 ...

  7. python_网络编程_基础

    基本的架构有C/S架构 和B/S架构 B/S架构优于C/S架构? 因为统一入口 , 都是从浏览器开始访问 两台电脑实现通信, 需要网卡, 网卡上有全球唯一的mac地址 ARP协议 #通过ip地址就能找 ...

  8. Ubuntu18.04命令行安装mysql未提示输入密码,修改mysql默认密码

    Ubuntu18.04命令行安装mysql未提示输入密码,修改mysql默认密码 mysql默认密码为空 但是使用mysql -uroot -p 命令连接mysql时,报错ERROR 1045 (28 ...

  9. mssql sqlserver时间戳与时间格式互相转换的方法分享

    转自: http://www.maomao365.com/?p=9336 摘要: 下文讲述mssql中时间戳和时间格式的转换方法,如下所示: 实验环境:sql server 2008 R2 时间戳简介 ...

  10. 【51nod】1634 刚体图

    [51nod]1634 刚体图 给一个左边n个点右边m个点二分图求合法的连通图个数,每条边选了之后会带来价值乘2的贡献 类似城市规划那道题的计数 设\(g[i][j]\)为左边\(i\)个点,右边\( ...