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

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


以前nRF SDK DFU的实现是通过nRF51 Dongle配合主机nRF connect工具,且借助Secure DFU的后台式更新速率较快(见另一篇笔记),现在的nRF mesh DFU分角色,全都由DK充当:一个带有serial串口交互的发送设备(source)和若干个待升级设备(relay或target)角色,从而实现整个网络所有设备全都批量升级,这对未来的物联网是一次崭新的创意点。这篇笔记会基于nrf SDK15.3+mesh3.2实现两个部分:

a)Configuring and Perfoming DFU over Mesh

b)Integrating DFU process into the application

升级过程:

按照官方教程《Configuring and Perfoming DFU over Mesh》安全升级需要使用nrfutil工具,但原先nrf SDK DFU的nrfutil不能直接使用,两者版本不兼容,否则会提示没有”--mesh””genpkg””--application-id”,也就是注意nrf5 SDK DFU和nrf5 mesh DFU的python工具有些微不同,要用到pc-util/mesh_dfu,pc-util/mesh_dfu仓库地址为:

https://github.com/NordicSemiconductor/pc-nrfutil/tree/mesh_dfu,安装前必须要把仓库完整下载下来,然后按照仓库pc-util/mesh_dfu提示来安装。(注意会覆盖原来的工具,可以备份,做法可看帖子)。

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

完整流程:

  1. 产生安全秘钥private_key,同时修改JSON对象配置
    在这里插入图片描述

  2. 产生device_page,生成tools\dfu\bin\device_page_nrf52832_xxAA_s132_6.1.1.hex
    在这里插入图片描述

  3. 生成升级包.zip(注意用mesh版本的nrfutil指令)
    在这里插入图片描述

  4. 烧录协议栈bin\softdevice\s132_nrf52_6.1.1_softdevice.hex,烧录前需整片或整扇区擦除,由flash工作机理决定。

  5. 烧录引导程序mesh_bootloader_serial_gccarmemb_nrf52832_xxAA.hex实现IAP自编程,目录Bin\bootloader\gccarmemb\mesh_bootloader_serial_gccarmemb_nrf52832_xxAA.hex

  6. 烧录应用部分。当烧录应用时,可以烧录dfu例程examples\dfu\build\dfu_nrf52832_xxAA_s132_6.1.1_Debug\dfu_nrf52832_xxAA_s132_6.1.1.hex编译出来的固件做演示或者烧录用户自己mesh程序(要带dfu功能)比如examples\light_switch\server(DFU)\build\light_switch_server_nrf52832_xxAA_s132_6.1.1_dfu_Debug\light_switch_server_nrf52832_xxAA_s132_6.1.1_dfu.hex做实际项目。本文为演示,烧录模板例程,用户普通mesh程序怎么添加dfu见下一章节。

  7. 烧录刚才第二步生产的device_page,(跟以前nrf SDK DFU用mergehex指令合并这4大块为一个整体不同)4大块全部完成后让芯片复位:
    图1 第4~7步完整过程

  8. 可以检查一下device_page和bootloader(这步可做可不做):
    在这里插入图片描述

  9. 串口启动升级过程。敲击命令nrfutilmesh dfu serial -pkg blinky_dfu_test.zip -p COM54 -b 115200 -fc --mesh:
    在这里插入图片描述
    注意:默认dfu是dual-bank方式,所以进度条提示100%完成时还要等40s左右等它新固件搬移复制到旧固件位置来(见上图),否则会出现flash有两个固件但bootloader依然引导旧程序运行并且还能进行下一次升级的现象,RTT终端提示 NRF_MESH_EVT_DFU_END才算完成,并且板子上4个灯会全部开始闪烁而不是官方教程说的仅1个灯亮,官方教程还有一处小错误,就是第6步烧录dfu模板例程时给定的路径是错的,按本文来,官方教程合计两处小错误。

2.添加 DFU功能到mesh程序:

按照官方教程《Integrating DFU process into the application》指导来做。目录examples\dfu为带dfu功能的模板,可以参考它来给自己的mesh程序添加DFU,具体做法比如light_switch/server在main.c添加充当target或relay角色相应处理代码:

static nrf_mesh_evt_handler_t m_evt_handler;
static bool fw_updated_event_is_for_me(const nrf_mesh_evt_dfu_t * p_evt)
{
    switch (p_evt->fw_outdated.transfer.dfu_type)
    {
        case NRF_MESH_DFU_TYPE_APPLICATION:
            return (p_evt->fw_outdated.current.application.app_id == p_evt->fw_outdated.transfer.id.application.app_id &&
                    p_evt->fw_outdated.current.application.company_id == p_evt->fw_outdated.transfer.id.application.company_id &&
                    p_evt->fw_outdated.current.application.app_version < p_evt->fw_outdated.transfer.id.application.app_version);


        case NRF_MESH_DFU_TYPE_BOOTLOADER:
            return (p_evt->fw_outdated.current.bootloader.bl_id == p_evt->fw_outdated.transfer.id.bootloader.bl_id &&
                    p_evt->fw_outdated.current.bootloader.bl_version < p_evt->fw_outdated.transfer.id.bootloader.bl_version);


        case NRF_MESH_DFU_TYPE_SOFTDEVICE:
            return false;


        default:
            return false;
    }
}

static const uint32_t * optimal_bank_address(void)
{
    /* The incoming transfer has to fit on both sides of the bank address: First it needs to fit
     * above the bank address when we receive it, then it needs to fit below the bank address when
     * we install it. We want to put the bank address in the middle of the available application
     * code area, to maximize the potential transfer size we can accept. */
    const uint32_t * p_start;
    uint32_t dummy;
    ERROR_CHECK(mesh_stack_persistence_flash_usage(&p_start, &dummy));


    uint32_t middle_of_app_area = (CODE_START + (intptr_t) p_start) / 2;


    /* The bank can't start in the middle of the application code, and should be page aligned: */
    return (const uint32_t *) ALIGN_VAL(MAX(middle_of_app_area, CODE_END), PAGE_SIZE);
}

static void mesh_evt_handler(const nrf_mesh_evt_t* p_evt)
{
    switch (p_evt->type)
    {
        case NRF_MESH_EVT_DFU_FIRMWARE_OUTDATED:
        case NRF_MESH_EVT_DFU_FIRMWARE_OUTDATED_NO_AUTH:
            if (fw_updated_event_is_for_me(&p_evt->params.dfu))
            {
                const uint32_t * p_bank = optimal_bank_address();
                __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Requesting DFU transfer with bank at 0x%p\n", p_bank);


                ERROR_CHECK(nrf_mesh_dfu_request(p_evt->params.dfu.fw_outdated.transfer.dfu_type,
                                                 &p_evt->params.dfu.fw_outdated.transfer.id,
                                                 p_bank));
                hal_led_mask_set(LEDS_MASK, false); /* Turn off all LEDs */
            }
            else
            {
                ERROR_CHECK(nrf_mesh_dfu_relay(p_evt->params.dfu.fw_outdated.transfer.dfu_type,
                                               &p_evt->params.dfu.fw_outdated.transfer.id));
            }
            break;

        case NRF_MESH_EVT_DFU_START:
            //hal_led_mask_set(LEDS_MASK_DFU_RUNNING, true);
    __LOG(LOG_SRC_APP, LOG_LEVEL_INFO,"NRF_MESH_EVT_DFU_START\n");
            break;

        case NRF_MESH_EVT_DFU_END:
            //hal_led_mask_set(LEDS_MASK, false); /* Turn off all LEDs */
            //hal_led_mask_set(LEDS_MASK_DFU_ENDED, true);
    __LOG(LOG_SRC_APP, LOG_LEVEL_INFO,"NRF_MESH_EVT_DFU_END\n");
            break;

        case NRF_MESH_EVT_DFU_BANK_AVAILABLE:
            //hal_led_mask_set(LEDS_MASK, false); /* Turn off all LEDs */
    __LOG(LOG_SRC_APP, LOG_LEVEL_INFO,"NRF_MESH_EVT_DFU_BANK_AVAILABLE\n");
            ERROR_CHECK(nrf_mesh_dfu_bank_flash(p_evt->params.dfu.bank.transfer.dfu_type));
            break;

        default:
            break;

    }
}

新建DFU文件夹,添加文件nrf_mesh_dfu.c,同时不妨添加serial串口操作功能让其有source角色功能,新建Serial文件夹,添加mesh/serial/src下全部文件(共14个),添加路径和宏定义NRF_MESH_SERIAL_ENABLE:

…/…/…/mesh/serial/api

…/…/…/mesh/serial/include

在这里插入图片描述
在主函数mesh_init加入代码:


#if NRF_MESH_SERIAL_ENABLE
    ERROR_CHECK(nrf_mesh_serial_init(NULL));
#endif

Start函数加入代码:

#if NRF_MESH_SERIAL_ENABLE
    __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Enabling serial interface...\n");
    ERROR_CHECK(nrf_mesh_serial_enable());
#endif
posted on 2023-02-01 11:57  xuejianqiang  阅读(39)  评论(1编辑  收藏  举报  来源
打造一个通用性MCU架构,支持CX32/AT32/NRF51/NRF52等。 OS支持RTX4/RTX5/FreeRtos。 采用VsCode+GCC组合,VsCode+KEIL5,超强开发方式。 QQ群:524408033