文章目录

  • 52840 相关
    • 1、P0.9和P0.10
    • 2、SPI问题
    • 3、I2C问题
    • 4、FDS问题
    • 5、堆栈问题
    • 6、GPIO中断问题
    • 7、低功耗问题
    • 8、复位问题
    • 9、重启定位问题
    • 10、PC指针
    • 11、fstorage问题
    • 12、日志问题
    • 13、调试相关
    • 14、各组件打开功耗
  • 操作系统相关
    • 1、内存问题
    • 2、中断问题
    • 3、打印与功耗问题
    • 4、优先级问题
    • 5、定时器问题
    • 6、任务名字问题
    • 7、看门狗问题
    • 8、系统时钟问题
    • 9、调试相关

在项目中使用的52840搭载的FreeRTOS操作系统,使用的是SES开发环境而非Keil(因为Nordic买了SES的版权,使用SES不会有版权问题)

NRF52840使用记录

在项目中使用的52840搭载的FreeRTOS操作系统,使用的是SES开发环境而非Keil(因为Nordic买了SES的版权,使用SES不会有版权问题)

52840 相关

1、P0.9和P0.10

由于52840支持NFC功能,因此该两个引脚默认为NFC引脚,在项目中如果用作普通的GPIO,则需要进行设置。

需要在system_nrf52.c中加宏定义

#define CONFIG_NFCT_PINS_AS_GPIOS

2、SPI问题

在nrf52840做主机时,需要使用DMA进行发送,但是由于SPI的easyDMA(不只是SPI)的长度限制为不超过256字节,因此,在我的项目中,由于使用的是每包512字节的机制,所以需要进行分包发送。还出现过uninit时,while循环导致看门狗重启,由从机导致。需要注意此点。

3、I2C问题

目前有很多单片机中的I2C变成了TWI。TWI全兼容I2C,但并不局限于I2C,双线发送均可使用TWI进行操作。

TWI在操作上较I2C复杂,需要自己写一个I2C的接口,使用TWI进行封装

4、FDS问题

  1. 需要对数据长度有较好管控,否则一旦读取的长度比实际长度长时,可能会导致HardFault,原因是fds不对地址溢出进行校验,因此长度过长,超出FLASH的映射空间,就会有HardFault产生。
  2. 读FLASH数据时,需要使用memcpy将数据读出,否则可能会导致HardFault,原因是fds返回的地址并非是内存地址(0x2000000起始),而是flash地址(0x0起始),在执行一些操作时,由于地址不是内存地址而产生
  3. fds不对数据进行加密,当使用flash读取工具时,(jFlash,nrf—connect)则会读出存储的设备信息,可能有很关键的信息,这个是需要考虑的点,当然也可以在产品出厂时设置为flash不可读取,但是也会有一些不方便之处
  4. 我实测一次gc的时间大概是800ms左右
  5. 推荐进行封装成write和read两个函数,否则操作很麻烦

5、堆栈问题

nrf52840的例程中,使用的heap较小,当开辟较大数据时,容易出现开辟失败的情况,如果需要的话,需要对heap进行扩容。也需要保证malloc和free的匹配性,当然也可以使用官方的内存管理机制,为原子操作,更放心,但是需要对其较为了解。

6、GPIO中断问题

GPIO本来是只支持8个引脚的中断,但是使用PORT,还有sdk_config.h中的宏,来进行规避此问题,例如我的项目中就高达10个中断。

使用该方式时,有可能需要将结构体元素中的hi_accuracy进行赋值为1,否则可能会有检测不到中断的可能性!!!但会增加部分功耗(10uA)

7、低功耗问题

  1. 起始芯片自身的功耗是非常少的,只有2~3uA,因此即使是一个小电容也可能供电一段时间,这也是一个调低功耗的坑,断电时间过短,由于电容供电,导致芯片还在工作一点时间,需要把握好这个时间节点,也可以使用一些外部的短路等快速放电
  2. 蓝牙的功耗,蓝牙的功耗是随着广播时间的间隔或者打开关闭来改变的,但是广播也和设备连接有一定的关系,广播越久,功耗越低,设备连接越慢,需要进行取舍。我的项目中,测试大概是1s广播间隔,连接时间最长可能达到十多秒,平均功耗在20uA左右,可以尝试了解快慢广播的概念,然后进行配置,在两者之间做出平衡
  3. 蓝牙的引脚,蓝牙的引脚默认都是disconnect的状态,因此,不配置就是最低的功耗。低功耗应用场景,一般都有对于外围芯片电源的控制,因此即开即关也是一个功耗处理点,对于不需要关闭电源的设备,一般来说会有加速度传感器,加速度传感器一般的选型是LiS2DH,该芯片的内部有一个上拉电阻,功耗可达百微安级别,需要设置成不可使用上下拉,另外一个采样频率也是一个功耗点,我的项目中为25Hz,浮点型计算也是一个功耗点
  4. MCU的外设也是需要即开即关,但是有可能会init和uninit不同步导致的断言问题,因此需要控制好
  5. 蓝牙引脚设置为默认状态时,外部设备的连接为浮空状态,可能为高电平,该状态可能与外部IC冲突,导致的功耗问题,我的项目中需要和另一个wifi芯片进行通讯,wifi芯片的唤醒中断引脚,因为这个默认状态而导致的休眠失败是一个功耗点
  6. 如果使用浮点型计算,千万要记得关闭FPU,该寄存器会有大概6mA左右电流

8、复位问题

nrf芯片可以记录复位原因,包括复位引脚,上电,看门狗,也可以用户在需要重启的时候写入寄存器,自定义原因,在上电时,就可以进行分别处理,我的项目中,是做了非用户操作的重启,则用户不感知重启的功能。重启不清零数据的内存地址放到了 attribute((section(“.non_init”)));如果有bootloader,需要同步设置

9、重启定位问题

  1. APP_ERROR_CHECK,在app_error.c文件夹中,可以打印出具体的文件名字和行号、以及错误代码,较为简单。
  2. HardFault,在hardfault_implementation.c文件中,已经详细对其做出了打印,则根据PC指针,LR寄存器等,来推断导致hardfault的位置。LR寄存器一般存放产生hardfault的函数,pc指针定位到了具体的代码地址
  3. 看门狗复位,看门狗是为了防止程序异常死机,但是正常情况下也是不允许该情况的,可以在看门狗中断函数中,读出传参sp[6]的值,该值就是PC指针,然后记录下来,放到重启不清零的RAM地址(attribute((section(".non_init")))),即可进行打印地址,定位问题。
  4. 用户复位就不需要分析了吧

10、PC指针

这个可以通过map文件搜索,和debug模式下搜索,可以找到具体的代码,进行定位问题。

或者使用objdump对elf进行反汇编。需要安装

arm-none-eabi 工具。如下命令:

arm-none-eabi-objdump -D “T7400_1.0.0.4.elf” > T7400_1.0.0.4.S

在生成汇编文件后,即可进行查看汇编代码查看具体问题

11、fstorage问题

默认队列为4,当队列用完时,会返回错误码,此处导致的问题需要注意;

nrf_fstorage_write flash等函数,操作数据源地址(*p_src)也需要四字节对齐,可使用 attribute((aligned(4)))进行对齐。并且flash写入是异步操作,所以数据源地址(*p_src)要注意不要使用局部变量;

12、日志问题

由于我的项目中,软件测试是用串口接收打印,而不是使用Jlink,因此需要将数据通过串口输出,但是当使用串口进行输出时,出现的异常重启则不可以进行打印,导致分析出现问题。因此需要将APP_ERROR_CHECK和HardFault的数据也通过串口输出出来。

下面为我的调试代码:用于重大错误即将重启之前的调用

nrf_drv_uart_t m_uart = NRF_DRV_UART_INSTANCE(UART_LOG_INSTANCE);
static volatile bool m_xfer_done;
//发送完成中断函数
static void uart_evt_handler(nrf_drv_uart_event_t *p_event, void *p_context)
{m_xfer_done = true;
}//重大错误调用函数,在HardFault中也可调用
void _log_error(char *fmt, uint16_t len)
{//反初始化串口,这个地方需要注意,因为不知道有没有进行开始串口,内部可通过标志位或者事件进行对应处理uart_driver_deinit();//初始化串口nrf_drv_uart_config_t config = NRF_DRV_UART_DEFAULT_CONFIG;config.pseltxd = UART_LOG_TX_PIN;   //只需要用到发送串口config.pselrxd = NRF_UART_PSEL_DISCONNECTED;config.pselcts = NRF_UART_PSEL_DISCONNECTED;config.pselrts = NRF_UART_PSEL_DISCONNECTED;config.baudrate = (nrf_uart_baudrate_t)NRF_LOG_BACKEND_UART_BAUDRATE;nrf_drv_uart_init(&m_uart, &config, uart_evt_handler);//日志进行格式化,带颜色较为清晰uint8_t err_buf[256];snprintf(err_buf, sizeof(err_buf), "\r\n\033[31m<<<<<reboot>>>>>:\033[0m\033[33m %s\033[0m", fmt);m_xfer_done = false;//进行数据输出nrf_drv_uart_tx(&m_uart, (uint8_t *)err_buf, strlen(err_buf));//tick用来确保中断被关闭时,也能正常退出uint32_t tick = 1000000;while (m_xfer_done == false && tick-- != 0){}nrf_drv_uart_uninit(&m_uart);//调试使用,连上jlink时,也可进行jlink输出NRF_LOG_FLUSH();
}

13、调试相关

使用jlink调试,可以查看所有内存信息和堆栈调用。参考博客 https://github.com/meishaoming/blog/issues/53

14、各组件打开功耗

外设 运行功耗
CPU 3~6mA
Radio 4~16mA
SAADC 1.24mA
PWM 0.2mA
WDT 0.003mA
GPIOTE 0.017mA
DMA 2mA
FPU 6mA
I2C 0.1mA
SPI 0.1mA
adv 0dBm 1s广播 0.022mA

操作系统相关

1、内存问题

在所有使用freertos的工程中,一般默认推荐的都是使用的heap_4这个内存管理机制。

该内存管理机制是用FreeRTOS进行统一管理,FreeRTOS使用的所有内存都从一个数组中进行开辟。而Nordic官方使用的heap_1作为例程。当进行任务开辟时,非常容易由于总共的堆栈空间分配不足,导致失败。因此我后来也是选用了heap_4这个内存管理机制

但是当任务堆栈不足时,也会导致任务开辟失败。可通过修改configTOTAL_HEAP_SIZE的值进行处理。默认为4k,几个任务就不够了。

需要注意的问题是,你任务中使用的所有变量,局部变量、函数调用占用的空间等,都是占用的任务的堆栈空间,malloc函数占用的是程序的堆空间。因此要保证开辟任务时,保证开辟的任务堆栈空间不足,否则就会导致重启,可通过configCHECK_FOR_STACK_OVERFLOW为1,在钩子内进行打印堆栈溢出的任务名字,进行确认。还可以通过使用INCLUDE_uxTaskGetStackHighWaterMark的方式来查看任务的最深调用。当接近0时,需要增加任务堆栈,当一直远远大于0时,可考虑进行减少任务堆栈。

需要注意可能并不是所有任务都初始化时就开始,有些任务可能开辟,不久就释放,所以测试时,需要进行全部任务开启测试,保证运行中开辟任务时,出现内存不够的问题。

2、中断问题

由于FreeRTOS的机制问题,需要区分中断的快速操作处理还是非中断模式下的可延时等待处理,因此给了两个函数,中断中需要调用带FromISR的函数,因此在写代码时需要非常注意。但是可以通过一个函数来进行判断0 == __get_CONTROL()

if (0 == __get_CONTROL()) // in isr handler
{BaseType_t xHigherPriorityTaskWoken = pdFALSE;xQueueSendFromISR(log_QueueHandle, &info, &xHigherPriorityTaskWoken);
}
else
{xQueueSend(log_QueueHandle, &info, wait_time);
}

3、打印与功耗问题

由于nordic移植的函数 configUSE_IDLE_HOOK一般为0,不会有功耗问题,但是打印不全,因为没有位置调用NRF_LOG_FLUSH函数,进行日志输出。但是当该值设置为1时,打印完全,但是芯片却没有休眠(8mA)线程未休眠都是8mA左右,一直在执行该函数。

知道该原因也就好解决了,我的采用方式是,定义自己的日志输出函数,通过串口输出,当自己的日志进行输出时,也直接调用NRF_LOG_FLUSH函数。

4、优先级问题

nordic的任务优先级configMAX_PRIORITIES中最大为3 ,可能不满足任务要求,推荐经典值16 ,与uCOSII不同,该值越大,优先级越高

当高优先级的任务产生时,会直接打断正在运行的低优先级任务,因此很多函数可能需要做好重入处理。比如外设的init和uninit函数。否则由于该问题导致的重启就很难找到。

5、定时器问题

nordic的定时器任务深度默认只有80,当项目中增加定时器,需要注意此处导致的重启configTIMER_TASK_STACK_DEPTH,我的项目中应用的为1k

6、任务名字问题

nordic的默认名字configMAX_TASK_NAME_LEN长度为4 ,推荐根据具体项目具体更改。

7、看门狗问题

建议看门狗单独做一个任务,且任务优先级为1,不能和其他任务同时使用,否则则可能出现任务中的其他功能阻塞掉看门狗任务,导致看门狗重启。

8、系统时钟问题

nordic默认 configTICK_RATE_HZ 宏为1024,但是如果使用该值,所有延时时间都会提前结束,一秒钟提前几个毫秒,累加提前,十分钟大概12~13s。需要将该宏修改为1000,或者延时,乘上节拍系数 。该值为portTICK_PERIOD_MS 。但是如果任务调度过多,该方式可能会导致延时稍晚结束。但比1024准确很多,如需必须很精准定时,需要使用rtc时间

9、调试相关

可以在hard fault函数里打印当前任务名字,当前堆栈值,可通过堆栈值进行判断。堆栈深度和堆栈初始值,可以判断是否堆栈溢出,部分堆栈溢出不会调用钩子,直接被hard fault了。

在task.c里添加如下函数即可。

void xTaskStackShow(TCB_t *pxTCB){volatile unsigned long *stack;unsigned long addr1;unsigned long addr2;unsigned long addr3;unsigned long addr4;if (pxTCB == NULL)return;stack = (volatile unsigned long *)pxTCB->pxTopOfStack;//打印当前任务所有堆栈信息_log_error("dump task:[%s] pxStack %x,depth %x", pxTCB->pcTaskName, pxTCB->pxStack, pxTCB->uxStackDepth);while (stack < ((unsigned long *)(pxTCB->pxStack) + (UBaseType_t)(pxTCB->uxStackDepth))){addr1 = *stack++;addr2 = *stack++;addr3 = *stack++;addr4 = *stack++;_log_error("[<%08lx>] [<%08lx>] [<%08lx>] [<%08lx>] ", addr1, addr2, addr3, addr4);}
//打印当前任务名字char * xTaskGetCurrentTaskName(void){TCB_t *task = xTaskGetCurrentTaskHandle();return task->pcTaskName;}//打印当前任务信息void xTaskStackShowCurrentTask(void){xTaskStackShow(xTaskGetCurrentTaskHandle());}

uxStackDepth该成员变量官方库并未给出,需要自己在TCB_t中添加

注意添加位置和添加类型.。再创建任务时进行赋值

nRF52840脱坑指南相关推荐

  1. [专栏精选]Unity中编码Encoding脱坑指南

    本文节选自洪流学堂公众号技术专栏<大话Unity2018>,未经允许不可转载. 洪流学堂公众号回复专栏,查看更多专栏文章. 洪流学堂,让你快人几步.你好,我是郑洪智. 大智:"昨 ...

  2. Redis 脱坑指南

    原文地址:Redis 脱坑指南 博客地址:http://www.extlight.com 一.前言 Redis 是一款 key-value 内存数据库.由于其上手快,执行效率高,拥有多种数据结构,支持 ...

  3. Android 7.0脱坑指南

    本文已授权微信公众号:鸿洋(hongyangAndroid)原创首发. Android适配系列: Android 6.0 的动态权限管理 Android 7.0脱坑指南 Android 8.0适配指北 ...

  4. 技术人综合症脱坑指南

    We_Can_Do_It.jpg 上周遇到一设计师,改了几次设计稿,在电话中尥蹶子不干了.boss在边低声问:"设计师都这样?" 其实心高气傲的岂止是设计师?程序员,工程师,大部分 ...

  5. STM8S系列单片机脱坑指南

    STM8S脱坑指南 你好!这是你第一次使用 STM8S003K3 .如果你想学习如何使用STM8S003K3, 可以速速滚蛋,因为这一点也不好玩.理由如下: 1.参考资料少 2.官方资源少且混乱 3. ...

  6. 大数据 SQL Boy 脱坑指南

    不可否认的是 SQL 是一个伟大的发明,它让增删改查的操作更加地便捷化,而且 SQL 的学习成本相对其他编程语言来说较低,被逼到会写 SQL 的运营和产品我都见过不少... 大数据行业跟 SQL 更是 ...

  7. 虚幻4脱坑指南——官网C++编程教程中第一人称设计游戏教程的若干问题及解决方法

    一.前言 我使用的虚幻4引擎版本为4.25.3,碰到的问题是针对官网C++编程教程中第一人称设计游戏教程出现的情况. 二.问题与实现 2.1.缺少引用的编译错误 如图1所示的步骤2.7中,将官网的代码 ...

  8. 基于Blinker的小爱同学语音控制【脱坑指南】

    基于Blinker的小爱同学语音控制ESP8266 前些天在使用esp8266时遇到很多小爱不能控制设备问题,现在来叙述我控制过程中所遇到的问题,以及到完整的小爱能成功控制Esp8266的过程. 1. ...

  9. CV脱坑指南(二):ResNet·downsample详解

    到这儿来-(feat.美丽的嫦娥姐姐 嗯经过了一周的实(mo)践(yu)之后,打算还是给ResNet出个续集 毕竟downsample这一块儿实在是挺费解的 其中ResNet出现的downsample ...

  10. 脱坑指南:Vant选择器没有确认按钮和标题?!的解决办法

    文章目录 问题描述 解决方法! 在van-picker标签中加入 show-toolbar!!! 问题描述 项目用了vant选择器,代码怎么看都觉得没有问题,就死活不出确认取消按钮和标题,找bug找到 ...

最新文章

  1. python 元组和列表区别_Python 基础(六):列表与元组
  2. 机器学习、深度学习所需掌握的数学知识全都在这里了!
  3. js中的正则表达式入门
  4. 『中级篇』k8s的NodePort类型Service以及Label的简单实用(68)
  5. html+设置img+src属性值,javascript获取、设置修改img的src属性(get/setAttribute)
  6. 关于jQuery对象与DOM对象
  7. python保存模块_Python使用Pickle模块进行数据保存和读取的讲解
  8. php like %%,thinkphp实现like模糊查询实例
  9. 我心中的核心组件(可插拔的AOP)~大话开篇及目录
  10. 如何批量制作ITF-14条码
  11. 魔兽争霸3-游戏简单剖析 No.2 物品
  12. 李智慧 - 架构师训练营总览
  13. eclipse java验证码_spring整合kaptcha验证码
  14. 假期日历服务器无响应,PrimeNg日历日期无法正常工作(示例代码)
  15. WINDWOS XP应用大全
  16. 数据分析(1)——统计学中的各种分布
  17. 盛志凡:智能电视操作系统TVOS2.0-广电终端智能化的主引擎
  18. python Note II
  19. Effective Java读书笔记---二、创建和销毁对象
  20. 【office word】半角格式问题导致 西文格式无法修改

热门文章

  1. 【23】数据可视化:基于 Echarts + Python 动态实时大屏范例 - Redis 数据源
  2. dnsmasq, ipset和iptables配置
  3. 项管专栏丨项目管理的利器 — WBS工作分解结构
  4. 想多赚钱!程序员如何把副业搞得风生水起?
  5. 比较(0,π/2]上对sinx/x的定积分、对x/sinx的定积分与1的大小关系
  6. goeasy java_Java GoEasy 实现服务端推送和Web端推送
  7. PG数据库 创建自增序列 创建序列 查询序列 使用序列
  8. 【Python游戏】Python实现一个简易版本的阴阳师游戏 | 附带源码
  9. Mac 软件汉化教程(一)
  10. json rpc 2.0 java_使用JSONRPC 2.0规范解决多语言RPC交互的方案