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函数:
int main(void)
{
uint32_t err_code; // bool dfu_start = false;
bool app_reset = (NRF_POWER->GPREGRET == BOOTLOADER_DFU_START); #ifdef UART_DEBUG
uart_init();
M_LOG("\r\n[Boot]Uart Init OK.\r\n");
#endif if (app_reset)
{
M_LOG("[Boot]in DFU Mode...\r\n");
NRF_POWER->GPREGRET = ;
} // leds_init(); // This check ensures that the defined fields in the bootloader corresponds with actual
// setting in the nRF51 chip.
APP_ERROR_CHECK_BOOL(*((uint32_t *)NRF_UICR_BOOT_START_ADDRESS) == BOOTLOADER_REGION_START);
APP_ERROR_CHECK_BOOL(NRF_FICR->CODEPAGESIZE == CODE_PAGE_SIZE); // Initialize.
timers_init(); err_code = app_timer_create( &feed_wd_timer_id, APP_TIMER_MODE_REPEATED, timer_index_feed_wd );
APP_ERROR_CHECK(err_code); #if 0
buttons_init();
#endif (void)bootloader_init();
#if 0
if (bootloader_dfu_sd_in_progress())
{
// nrf_gpio_pin_clear(UPDATE_IN_PROGRESS_LED); err_code = bootloader_dfu_sd_update_continue();
APP_ERROR_CHECK(err_code); ble_stack_init(!app_reset);
scheduler_init(); err_code = bootloader_dfu_sd_update_finalize();
APP_ERROR_CHECK(err_code); // nrf_gpio_pin_set(UPDATE_IN_PROGRESS_LED);
}
else
#endif
{
// If stack is present then continue initialization of bootloader.
ble_stack_init(true);//!app_reset);//
scheduler_init();
M_LOG("[Boot]ble_stack_init OK...\r\n"); }
#if 0
dfu_start = app_reset;
dfu_start |= ((nrf_gpio_pin_read(BOOTLOADER_BUTTON) == ) ? true: false); if (dfu_start || (!bootloader_app_is_valid(DFU_BANK_0_REGION_START)))
#else
if(app_reset)
#endif
{
// nrf_gpio_pin_clear(UPDATE_IN_PROGRESS_LED); err_code = app_timer_start(feed_wd_timer_id, APP_TIMER_TICKS(,APP_TIMER_PRESCALER), NULL);
APP_ERROR_CHECK(err_code); // Initiate an update of the firmware.
err_code = bootloader_dfu_start();
APP_ERROR_CHECK(err_code); // nrf_gpio_pin_set(UPDATE_IN_PROGRESS_LED);
} if (bootloader_app_is_valid(DFU_BANK_0_REGION_START) && !bootloader_dfu_sd_in_progress())
{ (void)app_timer_stop( feed_wd_timer_id );
M_LOG("[Boot]bootloader_app_start...\r\n");
// Select a bank region to use as application region.
// @note: Only applications running from DFU_BANK_0_REGION_START is supported.
bootloader_app_start(DFU_BANK_0_REGION_START);
}
NVIC_SystemReset();
}
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(,APP_TIMER_PRESCALER), NULL);
APP_ERROR_CHECK(err_code);
(void)app_timer_stop( feed_wd_timer_id );
这个定时器就是解决今天尴尬的关键!
3.话说当 application 触发进入 OTA 模式很简单,只需要在加入以下代码即可:
void ota_mode_entry(void)
{
sd_softdevice_disable();
NRF_POWER->GPREGRET = 0xB1;
sd_softdevice_enable(NRF_CLOCK_LFCLKSRC_RC_250_PPM_8000MS_CALIBRATION,NULL);
NVIC_SystemReset();
}
但是,但是!!!!蛋蛋是!!!
如果你的 application 启动了 看门狗, 当软件复位的时候,看门狗是不会停止的,它还在工作,当你不喂它,很显然它就狂吠你,导致重启。
这时候重启很显然就没办法再进行升级了,而是又进入了application。
nRF51822 的看门狗很奇怪,它一旦起来了,就不能软件关闭了,而且调用NVIC_SystemReset() 不会致使它的寄存器清除,它还在跑。
解决的办法只能是在 bootloader 程序加喂狗程序咯。论坛上有人直接在 for(;;)循环里面加喂狗代码,但是并不十分管用,因为有个低功耗休眠函数会阻塞程序,导致喂不到狗,
不知道论坛上的那些大神是怎么想的,我也懒得去研究他们的办法和解释,
所以只能加个软件定时器,1秒喂一次,就当是把它关闭了吧。下面是这个软件定时器的回调:
static app_timer_id_t feed_wd_timer_id; static void timer_index_feed_wd( void *p_context )
{
//feed the dog
NRF_WDT->RR[] = WDT_RR_RR_Reload;
}
记得还要吧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
nRF51822 看门狗和OTA (无线升级功能)的尴尬笔记的更多相关文章
- 5、CC2541芯片中级教程-OSAL操作系统(PWM+看门狗)
本文根据一周CC2541笔记汇总得来—— 适合概览和知识快速索引—— 全部链接: 中级教程-OSAL操作系统\OSAL操作系统-实验01 OSAL初探 [插入]SourceInsight-工程建立方法 ...
- linux设备驱动归纳总结(十一):写个简单的看门狗驱动【转】
本文转载自:http://blog.chinaunix.net/uid-25014876-id-112879.html linux设备驱动归纳总结(十一):写个简单的看门狗驱动 xxxxxxxxxxx ...
- RM-Linux驱动--Watch Dog Timer(看门狗)驱动分析
from:http://blog.csdn.net/geekcome/article/details/6595265 硬件平台:FL2440 内核版本:2.6.28 主机平台:Ubuntu 11,04 ...
- tiny4412 裸机程序 三、关闭看门狗和调用C程序【转】
本文转载自:http://blog.csdn.net/eshing/article/details/37112779 一.原理说明 上是章中大家可能有会觉得奇怪,CPU不是有看门狗嘛?为什么CPU没有 ...
- 【Linux开发】linux设备驱动归纳总结(十一):写个简单的看门狗驱动
linux设备驱动归纳总结(十一):写个简单的看门狗驱动 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ...
- Spring Boot 实现看门狗功能 (调用 Shell 脚本)
需要实现看门狗功能,定时检测另外一个程序是否在运行,使用 crontab 仅可以实现检测程序是否正在运行,无法做到扩展,如:手动重启.程序升级(如果只需要实现自动升级功能可以使用 inotify)等功 ...
- STM32之看门狗(独立与窗口)
广大的互联网网友们,大家早上中午晚上好,我是某某某..对于狗..看过<忠犬八公>的我.无不深深的被狗的义气与灵气所震撼..我也觉得在所有mcu中用看门狗来形容让系统复位的功能是很恰当的.也 ...
- zigbee学习之路(十一):看门狗
一.前言 今天,我们要通过实验学习和认识一下看门狗的使用,看门狗是为了防止防止程序跑飞的,通过不断的喂狗,使看门狗能持续监管程序的运行状态,当程序跑飞时,能及时把程序拽回来. 二.原理与分析 在CPU ...
- STM32之独立看门狗与窗口看门狗总结
一.独立看门狗 STM32 的独立看门狗由内部专门的 40Khz 低速时钟驱动,即使主时钟发生故障,它也仍然有效. 看门狗的原理:单片机系统在外界的干扰下会出现程序跑飞的现象导致出现死循环,看门狗电路 ...
随机推荐
- Mysql 问题集
[1]实现如下需求 需求: 实现方案: (1)复现场景 SQL语句: -- [1]删除表 DROP TABLE tbl_name; -- [2]创建表 )); INSERT INTO tbl_name ...
- Mysql select into outfile 命令
[1]Mysql select into outfile命令 在Mysql中,与load data infile命令作用相反的一个命令是select into outfile命令 select int ...
- scala中val和var的区别
1:内容是否可变:val修饰的是不可变的,var修饰是可变的 2:val修饰的变量在编译后类似于java中的中的变量被final修饰 3:lazy修饰符可以修饰变量,但是这个变量必须是val修饰的 p ...
- 浅析libuv源码-node事件轮询解析(4)
这篇应该能结,简图如下. 上一篇讲到了uv__work_submit方法,接着写了. void uv__work_submit(uv_loop_t* loop, struct uv__work* w, ...
- “sgen.exe”未能运行。文件名或扩展名太长
问题 创建项目后无法运行 严重性 代码 说明 项目 文件 行 禁止显示状态 错误 MSB6003 指定的任务可执行文件"sgen.exe"未能运行.System.Component ...
- dotnet core 之 gRPC
dotnet core gRPC 原文在本人公众号中,欢迎关注我,时不时的会分享一些心得 HTTP和RPC是现代微服务架构中很常用的数据传输方式,两者有很多相似之处,但是又有很大的不同.HTTP是一种 ...
- 易语言 MD5生成
下载MD5脚本 https://download.csdn.net/download/zhangxuechao_/10573121 添加脚本组件 定义常量 生成MD5
- windows环境下基于nginx搭建rtmp服务器
基于nginx搭建rtmp服务器需要引入rtmp模块,引入之后需重新编译nginx linux环境几个命令行就能实现编译,笔者未尝试,网上有很多教程. windows环境还需要安装一系列的编译环境,例 ...
- Linux使用pt-archiver工具自动备份MySQL
操作系统: CentOS 6.9 脚本语言: shell https://github.com/iscongyang/Practical/blob/master/shell-scripts/pt-ar ...
- React源码 memo Fragment StrictMode cloneElement createFactory
1.memo react 16.6 推出的 api ,他的用意是给 function component 也有 PureComponent 这样一个类似的功能,因为我们知道 PureComponent ...