在嵌入式应用的开发过程中,虽然良好的编程实践和配合适当的编码规范检测软件能够减少代码编写阶段中出现的错误数量,但仍然不可避免的会出现一些只有在程序运行过程中才会触发的错误。为了解决程序运行过程中的问题,需要使用调试器,观察代码的执行及软件状态变化。
在程序调试的过程中,断点的重要性不言而喻。在调试状态下,当程序遇到断点时,会停止执行并将控制权交给调试软件,调试器可以显示当前应用程序的状态,包括变量和寄存器的值,内存、堆栈使用情况,显示应用程序到达断点位置的函数调用关系等,这些信息可以帮助开发人员分析程序的执行状况是否符合预期,并在问题出现时帮助确定错误原因。
(1)在RAM区域内调试
在开发过程中,可以将应用程序下载到RAM运行和调试,调试器只需使用简单的断点指令,且RAM允许多次读取和写入,RAM区域内的断点指令不会对程序执行产生明显的影响。但该方法的局限是MCU所拥有的RAM空间通常较小,应用较大时,无法在RAM进行调试。
(2)在Flash区域内调试
与RAM不同,Flash存储空间通常较大,当无法在RAM调试时只能在Flash区域内进行调试。微控制器设计人员提供了用于在Flash区域调试时使用的硬件断点,硬件断点会将PC指针与断点位置进行比较,并检查指令是否被调用,当断点处指令被调用时,程序将停止并启动调试器。硬件断点的数量由芯片所使用的内核决定,在ARM7和ARM9内核中仅包含2个硬件断点,在Cortex-M3和M4内核中包含4-6个可用的硬件断点。在调试过程中,当硬件断点数量用完时则无法添加新的断点,只能取消前面添加的断点后才能添加新的断点,这无疑将严重影响程序开发效率。
(3)外扩Flash存储芯片调试
当所开发的应用程序的复杂度进一步上升时,可能会使用到外扩的Flash存储,那么此时该如何进行应用程序调试呢?在大多数使用Cortex-M内核的微控制器中,芯片内部提供的硬件断点在调试过程中能够生效的地址范围是有限的,当使用外扩Flash时,自带的硬件断点将无法在外扩Flash存储的地址范围内生效,此时将无法在这些区域内设置断点来调试应用程序。
当使用基于地址映射扩展的外部Flash存储时,Segger J-Link产品所支持的无限Flash断点功能能够帮助我们对片外Flash添加断点并调试。
J-Link支持一项名为“无限Flash断点”(Unlimited Flash Breakpoints)的调试功能。“无限Flash断点”允许用户在Flash中调试时设置无限数量的断点。如果没有此功能,在Flash中能够设置的断点数量限制为CPU调试单元支持的硬件断点数。
J-Link的“无限Flash断点”适用于片内和外扩的Flash,包括通过内存映射添加的QSPI闪存。
Segger J-Link系列产品在实现无限Flash断点功能时,会使用硬件和软件断点的混合,来尽可能的减少对于Flash的影响。当硬件断点数量用完再添加新断点时,Segger软件将对断点所在位置的Flash区块进行重新编程来添加断点。
虽然Flash存在一定的写入次数限制,但Segger在实现该功能时已经做了大量针对性的优化来减少对于Flash的影响,例如处于同一区块内的多个断点,Segger将通过一次该Flash区块的重编编程来完成多个断点的添加。Segger仅在必要时才会对Flash区块进行重编程,部分操作将通过内置的指令集模拟器来完成,从而能够尽可能的减少对于Flash闪存的影响。
Segger的无限Flash断点调试功能解除了硬件断点对于程序调试的限制,能够提升开发人员的开发效率。对于Cortex-M内核芯片添加了外扩Flash的情形,无限Flash断点功能则可能是仅有的片外Flash调试解决方案。