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

随着时代的发展,现在的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. vue组件、自定义指令、路由

    1.vue组件 组件(Component)是 Vue.js 最强大的功能之一.组件可以扩展 HTML 元素,封装可重用的代码.组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的 ...

  2. K8s 学习者绝对不能错过的最全知识图谱(内含 58个知识点链接)

    作者 | 平名 阿里服务端开发技术专家 导读:Kubernetes 作为云原生时代的“操作系统”,熟悉和使用它是每名用户的必备技能.本篇文章概述了容器服务 Kubernetes 的知识图谱,部分内容参 ...

  3. tkmybatis VS mybatisplus

    本文是简单对比了以下官网上的内容 文章目录 TkMybatis Vs MybatisPlus 1.基础CRUD BaseMapper 2.代码生成器 3. 全局主键 Sequence主键 4. 热加载 ...

  4. [转] console.log的高级用法

    //基本用法 console.log('最常见用法\n换行'); console.error('输出错误信息 会以红色显示'); console.warn('打印警告信息 会以黄色显示'); cons ...

  5. Git分支和版本回退

    一.分支 1.分支简单介绍 简单使用: 可以将git branch new_branch和git checkout new_branch两个命令合并成一个命令: git checkout -b new ...

  6. RabbitMQ如何实现高可用

    RabbitMQ一共具有三种模式:单机.普通集群.镜像集群 单机模式 单机模式,就是我们平常玩的demo,生产上肯定不能用.具体安装部署过程可以参考我的这篇文章:CentsOS原生RabbitMQ安装 ...

  7. 解决 new file()在IOS下不兼容 的问题

    最近 做项目,做的要是拍照后上传相片,以file格式上传..所以 拍照 后用canvas生成base64格式再转file..在PC和安卓都是没有问题,到IOS上面不行..new file后就是生成一个 ...

  8. 个人项目-wc

    个人项目-WC   (C语言) 一.Github地址:https://github.com/Lin-J-F/WC 二.PSP表格 PSP2.1 Personal Software Process St ...

  9. HTTP Status 406 – Not Acceptable

    前端调用这个方法报错: HTTP Status 406 – Not Acceptable Type Status Report Description The target resource does ...

  10. 06. redis cluster

    目录 Redis Cluster redis cluster 特点 搭建redis cluster 访问redis cluster redis-cli 访问redis cluster 重新分片数据 新 ...