MCU在线调试功能正常而离线工作异常原因探究

汽车电子

2302人已加入

描述

在嵌入式MCU软件开发过程中,通常我们需要先通过调试器(Debugger, 带程序下载(Flash/EEPROM擦除、编程和校验)功能)或者仿真器(Simulator,不带目标MCU编程功能)对所写代码的功能进行在线调试(online- debug),验证确认其功能符号设计需求后,在发布编程文件--S19/HEX/BIN给生成部门通过离线编程器(Offline/Stand-alone Flash Programmer)进行批量编程。批量(Mass Production,简称MP)的产品正常工作时是不需要/也不能连接调试器或者仿真器的(一方面,调试器和仿真器价格高昂,成本不允许,另一方面,无法满足系统设计的产品重量和空间要求),因此,我们开发的嵌入式MCU应用软件/程序必须保证其在拔掉调试器和编程器或仿真器后依然能够功能运行正常,即离线工作(Offline,也称作脱机工作)正常。

在实际工作中,大家常常会遇到,开发阶段在线调试工作正常的代码,离线工作时却无法正常工作,这是为什么呢?

本文就基于NXP的汽车级MCU(S32K1xx/KEA, S12(X), MaginiV S12Z和Qorivva MPC56/57xx系列)为例,给大家介绍这类问题的可能原因和具体解决办法,希望对大家有所帮助。

1.应用工程的编译目标为debug_RAM,将代码编译链接到SARM而非Flash

在嵌入式MCU的软件开发集成环境(IDE)中创建应用工程时,通常都会创建至少两个编译目标(build target)和调试目标(debug target),使用不同的连接文件,将编译结果分别编译链接到SRAM和Flash中。

比如,在NXP的S32DS IDE中,创建S32K1xx系列MCU的应用工程时,就会自动创建Debug、Debug_RAM和Release三个编译目标,其差异和用途如下:

调试器

Tips:a. 由于S32DS是基于GNU的工具链,编译器(gcc)优化这一块目前还不是很完善,建议量产时还是使用Debug的编译目标,以保证编译结果能够正常运行;

b. 编译目标中工具链的调试信息等级(debug level)配置,只影响elf文件中包含调试信息的多少,不会影响最终生成的编程文件(S19/HEX/BIN)大小,因为编程文件中不包含任何调试信息;

c.一个S32DS工程可以有多个编译目标,用户可以通过工程属性创建、配置不同的编译目标实现应用工程的个性化编译;

因此,若选择使用Debug_RAM作为在线调试时的编译目标,并通过Debug_RAM调试目标下载,则编译结果未被下载到Flash中,因此,拔掉调试器,无法正常工作。

解决办法:切换应用工程的编译目标和调试目标为debug/release,将应用程序编译链接并下载到掉电不丢失的Flash中。

2.启动代码(startup code)未对使用的SRAM进行ECC初始化

为了保证嵌入式MCU应用程序的正常运行,提高系统的抗干扰能力,越来越多的MCU在其存储器中加入了单比特自动纠错,多比特检错的ECC功能。

对于此类MCU,由于调试器的下载脚本(在线调试时会被自动调用和执行)会对其SRAM进行初始化,若应用工程的启动代码(startup code)未对其SRAM进行就去访问(读)SRAM,则会导致ECC错误,从而进入内核异常:

  • ARM CM0+/CM4F 内核的HardFault异常;
  • S12Z内核的Machine Check异常;
  • PowerPC e200系列内核的IVOR1异常);

Tips:通常若MCU的SRAM带有ECC功能,在新建应用工程的启动代码中都会添加相应的ECC初始化代码,比如S32K1xx系列MCU的startup启动流程如下,在startup的第③步即对SRAM进行了初始化:

调试器

Notes:需要注意的是,对RAM初始化时使用的起始地址和长度信息来自应用工程的链接文件定义,若在SRAM size小的MCU part number(比如S32K144, SRAM为60KB,起始地址为:0x1FFF_8000 ~ 0x2000_6FFF)的应用工程上移植SRAM size大的MCU part number(比如S32K146, SRAM为120KB,起始地址为:0x1FFF_0000 ~ 0x2000_EFFF)应用程序,若不替换使用相应part number MCU的链接文件,则会出现SRAM ECC未初始化即使的情况。

解决办法:Double check应用工程的启动代码(startup codes),确保CPU内核在访问(读取)SRAM之前有对其使用的全部地址空间进行了ECC初始化。

3.FlexNVM(EEE--Emulated EEPROM)分区失败

在NXP的S12XE系列MCU和S32K1xx系列MCU中都使用了EEE(Emulated EEPROM, 硬件状态机模拟EEPROM),在访问之前,必须对其进行分区(partion), 而能够成功分区的前提是EEE所使用的D-Flash/FlexNVM和分区信息储存区域(FIR)为擦除状态。在CodeWarrior和S32DS IDE的下载脚本中,通常都会有相应的擦除命令(erase all block或者mass erase)完成这些操作,从而在线调试时,其分区一定能够成功,而量产时,没有调试器连接下载的过程,若在应用程序中未做相应的容错处理,在EEE分区失败的情况下,继续使用EEE,则会到MCU工作异常。

Tips:关于NXP的S12XE系列MCU和S32K1xx系列MCU的EEE使用,请参考如下应用笔记和公众号文章(点击文章标题即可直接跳转阅读):

  • AN11983, Using the S32K1xx EEPROM Functionality (REV 2):

https://www.nxp.com/docs/en/application-note/AN11983.pdf

  • AN3490, Overview of the MC9S12XE Emulated EEPROM - Application Notes (REV 0):

https://www.nxp.com/docs/en/application-note/AN3490.pdf

  • AN3743, Emulated EEPROM Quick Start Guide - Application Notes (REV 0):

解决办法:在对此类MCU的EEE分区之前读取分区信息,判断是否已经分区,避免重复分区,添加容错处理代码,分区不成功时,不使用EEE,具体实现可参考以上应用笔记和公众号文章。

4.RAM初始化时未关闭看门狗,导致看门狗超时复位

为了保证MCU应用程序能够被正常下载并进行在线调试,在MCU的调试器下载脚本或者Flash算法文件中,会将目标MCU的片上看门狗(watchdog)关闭,以避免编程过程中,擦除和编程Flash所用时间过长导致看门狗超时异常复位。

离线工作时,这些下载脚本和Flash算法将不会被执行,若应用工程的启动代码(startup code)在进行RAM初始化(.data段和.bss段初始化)之前未关闭片上看门狗,而且应用工程中使用的全局变量又比较多的情况下,就极容易出现看门狗超时复位,从而无法正常执行应用程序。

解决办法:Double check应用工程的启动代码(startup codes),确保在进行RAM初始化之前,MCU的片上看门狗已经被关闭(disabled)。

5.内部参考时钟(IRC)没有校准(trim),导致系统和外设时钟误差过大

通常为了降低系统成本和提高时钟的稳定性,在嵌入式MCU中都集成了一定数量的内部参考时钟(IRC-Internal Reference Clock)。但是,有工艺设计的限制,这些IRC时钟源的频率误差都比较大,必须经过校准(trim)才能够提高MCU datasheet中所规范的时钟精度。

在MCU的调试器下载脚本或者Flash算法中,往往会提供MCU片内IRC trim的功能,从而保证,在线调试时,MCU能够使用比较稳定的IRC参考时钟。若在MCU的启动代码中缺少IRC trim的功能代码,则会导致脱机运行时,依赖IRC时钟的内核和外设模块工作异常。

解决办法:若使用IRC时钟作为参考时钟的外设模块对时钟精度要求比较高,请务必在应用工程的启动代码中添加IRC时钟的trim代码。

6.bootloader跳转导致APP程序启动或者时钟、外设初始化失败

在带有bootloader功能的嵌入式MCU产品(比如汽车ECU)开发中,bootloader也是一个完整的应用工程,它也会对目标MCU的系统时钟和外设模块(至少bootloader获取更新firmware需要的通信外设模块(比如CAN或者UAR)T和定时器(比如看门狗或者用于通信超时的timeout硬件定时器模块)以及GPIO模块)进行初始化,这些时钟资源和外设模块,若在跳转在应用程序(APP)之前未复位,则会影响APP功能代码再次初始化系统时钟和外设模块,从而导致产品功能异常。

APP工程单独下载在线调试时,不存在bootloader的影响,因此工作正常,而加入bootloader后,则必须考虑以上影响。

解决办法:在bootloader初始化MCU系统时钟和外设模块之前(越早越好,可能的话在bootloader的复位函数中通过汇编指令实现最好),就读取并判断APP更新状态,跳转到APP。若有APP更新需求,在运行bootloader功能代码完成APP firmware更新之后,通过看门狗或者软件复位重新运行bootloader再跳转,而不是更新完成后立即跳转到APP。

7.使用调试器的半主机(semi-host)模式重定向printf()到debug console输出调试信息

通过调试器的半主机(semi-host)模式重定向printf()到debug console输出调试信息,从而可以调用printf()函数格式化打印调试信息,将在线调试时关心的寄存器和变量数据等输出到debug console,从而提高调试效率。

这种方法可以避免对MCU外设资源的占用,但是断开调试器,离线运行时,由于缺少debug_console的半主机模式响应,printf()将无法正常运行,从而影响应用程序正常工作。
解决办法:在离线工作时,移除应用程序中使用printf()的相关代码即可。也可以通过宏定义将printf()定义为空函数。

8.外设模块冻结模式配置影响其功能配置失败

除了以上列出的可能原因,为了在线调试时的减少CPU内核的中断或者方便量产时产生生产,嵌入式MCU的很多外设模块和存储器控制器有冻结模式(Freeze mode,也就是调试模式)控制位,从而可能会导致外设模块在调试模式和离线工作的正常模式下功能有所差异。

解决办法:double check使用MCU的芯片参考手册,确认相关外设模块的冻结模式控制位配置正确,不允许其离线工作。

总结

本文以NXP的汽车级MCU(S32K1xx/KEA, S12(X), MaginiV S12Z和Qorivva MPC56/57xx系列)为例,给大家介绍MCU在线调试正常,但离线工作异常这类问题的可能原因和相应的解决办法。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分