zoukankan      html  css  js  c++  java
  • nRF51822 看门狗和OTA (无线升级功能)的尴尬笔记

    很久没有记笔记了。今天要记点东西,不然以后又忘记了。

    随着时代的发展,现在的SDK已经是13.0了。蓝牙5.0也就来了。废话就少说了,记笔记吧。

    两年前搞过nRF51822 的无线升级功能,那时候用的还是 SDK5.20,直接用hex镜像进行升级的。后来的SDK就不再是hex,要用zip了,现在还不清楚具体做APP时候的用法。以后再说,先用官方提供了nRF_ToolBox能升级就很不错了。

    现在用了新的SDK,试了很长一段时间,各种各样的文档都过了,各种各样的方法都试过了,就是不行,真特么尴尬。后来今天又试了,到官方论坛去搜各种各样的情况,尝试,到底还是有点眉目了。

    SDK9.0的DFU例子,在.. RF51_SDK_9.0.0_2e23562examplesdfuootloaderpca10028dual_bank_ble_s110 这个路径,我修改了一点点程序,

    1.修改 bootloader_settings.c 文件下的这一行

    uint8_t  m_boot_settings[CODE_PAGE_SIZE] __attribute__((at(BOOTLOADER_SETTINGS_ADDRESS))) __attribute__((used)) 

    uint8_t  m_boot_settings[CODE_PAGE_SIZE] __attribute__((at(BOOTLOADER_SETTINGS_ADDRESS))) __attribute__((used)) = {BANK_VALID_APP};

    没有这个,程序用一些手段烧进去了它就一直是bootloader那运行,进不了application,具体的原因查看下下面的这个链接,官方论坛网友提的一个问题和别人的解答:

    https://devzone.nordicsemi.com/question/2304/device-is-always-in-bootloader-mode/

    2.修改main函数:

     1 int main(void)
     2 {
     3     uint32_t err_code;
     4 
     5 //    bool     dfu_start = false;
     6     bool     app_reset = (NRF_POWER->GPREGRET == BOOTLOADER_DFU_START);
     7 
     8 #ifdef UART_DEBUG
     9     uart_init();
    10     M_LOG("
    [Boot]Uart Init OK.
    ");
    11 #endif
    12 
    13     if (app_reset)
    14     {
    15         M_LOG("[Boot]in DFU Mode...
    ");
    16         NRF_POWER->GPREGRET = 0;
    17     }
    18  
    19  //  leds_init();  
    20     
    21     // This check ensures that the defined fields in the bootloader corresponds with actual
    22     // setting in the nRF51 chip.
    23     APP_ERROR_CHECK_BOOL(*((uint32_t *)NRF_UICR_BOOT_START_ADDRESS) == BOOTLOADER_REGION_START);
    24     APP_ERROR_CHECK_BOOL(NRF_FICR->CODEPAGESIZE == CODE_PAGE_SIZE);
    25 
    26     // Initialize.
    27     timers_init();
    28 
    29     err_code = app_timer_create( &feed_wd_timer_id, APP_TIMER_MODE_REPEATED, timer_index_feed_wd );
    30     APP_ERROR_CHECK(err_code); 
    31     
    32 #if 0
    33     buttons_init();
    34 #endif
    35 
    36     (void)bootloader_init();
    37 #if 0
    38     if (bootloader_dfu_sd_in_progress())
    39     {
    40 //        nrf_gpio_pin_clear(UPDATE_IN_PROGRESS_LED);
    41 
    42         err_code = bootloader_dfu_sd_update_continue();
    43         APP_ERROR_CHECK(err_code);
    44 
    45         ble_stack_init(!app_reset);
    46         scheduler_init();
    47 
    48         err_code = bootloader_dfu_sd_update_finalize();
    49         APP_ERROR_CHECK(err_code);
    50 
    51 //      nrf_gpio_pin_set(UPDATE_IN_PROGRESS_LED);
    52     }
    53     else
    54 #endif
    55     {
    56         // If stack is present then continue initialization of bootloader.
    57         ble_stack_init(true);//!app_reset);//
    58         scheduler_init();
    59         M_LOG("[Boot]ble_stack_init OK...
    ");
    60 
    61     }
    62 #if 0
    63     dfu_start  = app_reset;
    64     dfu_start |= ((nrf_gpio_pin_read(BOOTLOADER_BUTTON) == 0) ? true: false);
    65     
    66     if (dfu_start || (!bootloader_app_is_valid(DFU_BANK_0_REGION_START)))
    67 #else
    68     if(app_reset)
    69 #endif
    70     {
    71 //        nrf_gpio_pin_clear(UPDATE_IN_PROGRESS_LED);
    72 
    73        err_code = app_timer_start(feed_wd_timer_id, APP_TIMER_TICKS(1000,APP_TIMER_PRESCALER), NULL);
    74         APP_ERROR_CHECK(err_code);
    75 
    76 
    77         // Initiate an update of the firmware.
    78         err_code = bootloader_dfu_start();        
    79         APP_ERROR_CHECK(err_code);
    80 
    81 //        nrf_gpio_pin_set(UPDATE_IN_PROGRESS_LED);
    82     }
    83 
    84     if (bootloader_app_is_valid(DFU_BANK_0_REGION_START) && !bootloader_dfu_sd_in_progress())
    85     {
    86 
    87         (void)app_timer_stop( feed_wd_timer_id );
    88         M_LOG("[Boot]bootloader_app_start...
    ");
    89         // Select a bank region to use as application region.
    90         // @note: Only applications running from DFU_BANK_0_REGION_START is supported.
    91         bootloader_app_start(DFU_BANK_0_REGION_START);
    92     }
    93     NVIC_SystemReset();
    94 }
    View Code
    里面除了屏蔽很多行代码,还多了几行代码,是某个软件定时器的,创建、开启和关闭。
     err_code = app_timer_create( &feed_wd_timer_id, APP_TIMER_MODE_REPEATED, timer_index_feed_wd );
     APP_ERROR_CHECK(err_code); 
    err_code = app_timer_start(feed_wd_timer_id, APP_TIMER_TICKS(1000,APP_TIMER_PRESCALER), NULL);
    APP_ERROR_CHECK(err_code);
    (void)app_timer_stop( feed_wd_timer_id );

    这个定时器就是解决今天尴尬的关键!

    3.话说当 application 触发进入 OTA 模式很简单,只需要在加入以下代码即可:

    1 void ota_mode_entry(void)
    2 {
    3     sd_softdevice_disable();
    4     NRF_POWER->GPREGRET = 0xB1;
    5     sd_softdevice_enable(NRF_CLOCK_LFCLKSRC_RC_250_PPM_8000MS_CALIBRATION,NULL);
    6     NVIC_SystemReset();
    7 }

    但是,但是!!!!蛋蛋是!!!

    如果你的 application 启动了 看门狗, 当软件复位的时候,看门狗是不会停止的,它还在工作,当你不喂它,很显然它就狂吠你,导致重启。

    这时候重启很显然就没办法再进行升级了,而是又进入了application。

    nRF51822 的看门狗很奇怪,它一旦起来了,就不能软件关闭了,而且调用NVIC_SystemReset() 不会致使它的寄存器清除,它还在跑。

    解决的办法只能是在 bootloader 程序加喂狗程序咯。论坛上有人直接在 for(;;)循环里面加喂狗代码,但是并不十分管用,因为有个低功耗休眠函数会阻塞程序,导致喂不到狗,

    不知道论坛上的那些大神是怎么想的,我也懒得去研究他们的办法和解释,

    所以只能加个软件定时器,1秒喂一次,就当是把它关闭了吧。下面是这个软件定时器的回调:

    1 static app_timer_id_t feed_wd_timer_id;
    2 
    3 static void timer_index_feed_wd( void *p_context )
    4 {
    5    //feed the dog
    6      NRF_WDT->RR[0] = WDT_RR_RR_Reload;
    7 }

    记得还要吧timers_init()里的第二个参数调整加1

    #define APP_TIMER_MAX_TIMERS            4// 3  

    OK了,蛋蛋疼的OTA和看门狗之间的尴尬就化解了。

    其他打包 zip 和烧录的 工作,就交给 帮助文档吧。

    速度搜索一下 你的电脑,找到 How to generate the INIT file for DFU.pdf 文档。

    用到的工具是: 1.hex2bin.exe    2.nrfutil.exe

    下面是命令行脚本的内容,这样就可以生成 zip 了。

    .hex2bin.exe app.hex
    . rfutil.exe dfu genpkg app.zip --application app.bin --application-version 0xffffffff --dev-revision 0xffff --dev-type 0xffff --sd-req 0x0064

  • 相关阅读:
    Python学习 5day__基础知识
    pycharm 2018.1 专业版激活 亲测可用!!!
    JQuery 中 find() 和 filter() 的区别
    React 事件处理
    React 数据传递
    js操作cookie的一些注意项
    html5的技术要点
    css背景设置,让套图中某张图片居中显示的例子
    js对象封装内部图片的相关代码,采用base64图片串
    针对网上很多抱怨的言论,写了一个EF中update对象时,通用的遍历赋值方法,以供参考
  • 原文地址:https://www.cnblogs.com/ceibacity/p/7028234.html
Copyright © 2011-2022 走看看