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

随着时代的发展,现在的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 (无线升级功能)的尴尬笔记的更多相关文章

  1. 5、CC2541芯片中级教程-OSAL操作系统(PWM+看门狗)

    本文根据一周CC2541笔记汇总得来—— 适合概览和知识快速索引—— 全部链接: 中级教程-OSAL操作系统\OSAL操作系统-实验01 OSAL初探 [插入]SourceInsight-工程建立方法 ...

  2. linux设备驱动归纳总结(十一):写个简单的看门狗驱动【转】

    本文转载自:http://blog.chinaunix.net/uid-25014876-id-112879.html linux设备驱动归纳总结(十一):写个简单的看门狗驱动 xxxxxxxxxxx ...

  3. RM-Linux驱动--Watch Dog Timer(看门狗)驱动分析

    from:http://blog.csdn.net/geekcome/article/details/6595265 硬件平台:FL2440 内核版本:2.6.28 主机平台:Ubuntu 11,04 ...

  4. tiny4412 裸机程序 三、关闭看门狗和调用C程序【转】

    本文转载自:http://blog.csdn.net/eshing/article/details/37112779 一.原理说明 上是章中大家可能有会觉得奇怪,CPU不是有看门狗嘛?为什么CPU没有 ...

  5. 【Linux开发】linux设备驱动归纳总结(十一):写个简单的看门狗驱动

    linux设备驱动归纳总结(十一):写个简单的看门狗驱动 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ...

  6. Spring Boot 实现看门狗功能 (调用 Shell 脚本)

    需要实现看门狗功能,定时检测另外一个程序是否在运行,使用 crontab 仅可以实现检测程序是否正在运行,无法做到扩展,如:手动重启.程序升级(如果只需要实现自动升级功能可以使用 inotify)等功 ...

  7. STM32之看门狗(独立与窗口)

    广大的互联网网友们,大家早上中午晚上好,我是某某某..对于狗..看过<忠犬八公>的我.无不深深的被狗的义气与灵气所震撼..我也觉得在所有mcu中用看门狗来形容让系统复位的功能是很恰当的.也 ...

  8. zigbee学习之路(十一):看门狗

    一.前言 今天,我们要通过实验学习和认识一下看门狗的使用,看门狗是为了防止防止程序跑飞的,通过不断的喂狗,使看门狗能持续监管程序的运行状态,当程序跑飞时,能及时把程序拽回来. 二.原理与分析 在CPU ...

  9. STM32之独立看门狗与窗口看门狗总结

    一.独立看门狗 STM32 的独立看门狗由内部专门的 40Khz 低速时钟驱动,即使主时钟发生故障,它也仍然有效. 看门狗的原理:单片机系统在外界的干扰下会出现程序跑飞的现象导致出现死循环,看门狗电路 ...

随机推荐

  1. Java 微信支付分对接记录 (先享后付)

    微信支付分(先享后付)对接记录: 微信支付分对接步骤 填写开通支付分的申请表格 此步骤大概需要审核 1-3 个工作日; (模板-服务信息配置表-[先享后付免确认]-[商户名].xls) 填写商户信息 ...

  2. JVM 的GC算法和垃圾收集器

    1.标记清除算法 黑色部分代表可回收对象,灰色部分代表存活对象,绿色部分代表未使用的.最基础的收集算法就是标记清除算法如同他名字一样,算法分为"标记"和"清除" ...

  3. WPF 精修篇 Winform 嵌入WPF控件

    原文:WPF 精修篇 Winform 嵌入WPF控件 首先 创建WPF控件库 这样就有了一个WPF界面 在wpf中增加界面等 在winform中增加WPFDLL 重新生成解决方案 在左侧工具栏 出现W ...

  4. DSAPI CMD命令行进程代理

    DSAPI.文件.CMD命令行进程代理,是用来和CMD.exe或指定exe进行输出重定向的简化使用工具,可隐藏或显式地启动一个cmd.exe,并将输出流.输入流和错误流重定向至代理,通过事件触发方式与 ...

  5. JS删除指定下标的元素

    在开发过程中,有时我们需要删除数组中某一下标的元素.JAVA中ArrayList有remove函数.但是在JavaScript中没有直接的删除方法.我们可以利用splice来实现.Array.spli ...

  6. MySQL中的存储过程、游标和存储函数

    MySQL中的存储过程首先来看两个问题: 1.什么是存储过程? 存储过程(Stored Procedure)是在数据库系统中,一组为了完成特定功能的SQL语句集,经编译后存储在数据库中,用户通过指定存 ...

  7. 如何让SQL语句不执行默认排序,而是按照in语句的顺序返回结果

    Oracle: ')order by instr('111,222,333,444,555,666',order_id); Mysql: ') order by instr(',111,222,333 ...

  8. js 数组 添加或删除 元素 splice 创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素 filter

    里面可以用 箭头函数 splice         删除 增加 数组 中元素 操作数组 filter 创建新数组  检查指定数组中符合条件的所有元素

  9. 0x02 Python logging模块利用配置加载logger

    目录 logging模块利用配置加载logger 方式一模板:logging.config.dictConfig(config_dict) logging模块利用配置加载logger logging. ...

  10. Django框架(十三)--Django分页组件

    一.分页器 数据量大的话,可以分页获取,查看 例如:图书管理中,如果有成千上万本书,要是都在一个页面中渲染出来,会影响页面美观,所以就要用分页器分页渲染 二.分页器的使用 基本写法 基本写法: 后端: ...