nRF52840脱坑指南

文章目录

  • 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中加宏定义

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的数据也通过串口输出出来。

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

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()

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里添加如下函数即可。

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

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

声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2022年2月28日
下一篇 2022年3月1日

相关推荐