nRF51822 看門狗和OTA (無線升級功能)的尷尬筆記


很久沒有記筆記了。今天要記點東西,不然以后又忘記了。

隨着時代的發展,現在的SDK已經是13.0了。藍牙5.0也就來了。廢話就少說了,記筆記吧。

兩年前搞過nRF51822 的無線升級功能,那時候用的還是 SDK5.20,直接用hex鏡像進行升級的。后來的SDK就不再是hex,要用zip了,現在還不清楚具體做APP時候的用法。以后再說,先用官方提供了nRF_ToolBox能升級就很不錯了。

現在用了新的SDK,試了很長一段時間,各種各樣的文檔都過了,各種各樣的方法都試過了,就是不行,真特么尷尬。后來今天又試了,到官方論壇去搜各種各樣的情況,嘗試,到底還是有點眉目了。

SDK9.0的DFU例子,在..\nRF51_SDK_9.0.0_2e23562\examples\dfu\bootloader\pca10028\dual_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("\r\n[Boot]Uart Init OK.\r\n");
11 #endif
12 
13     if (app_reset)
14     {
15         M_LOG("[Boot]in DFU Mode...\r\n");
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...\r\n");
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...\r\n");
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
.\nrfutil.exe dfu genpkg app.zip --application app.bin --application-version 0xffffffff --dev-revision 0xffff --dev-type 0xffff --sd-req 0x0064

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM