赞
踩
断点是程序地址或表达式,当条件为真时,会暂停程序执行或执行指定的命令。可以通过以下几种方式定义和修改断点:
以上是定义和修改断点的几种常见方法。
Access Break(A)在设置Read、Write或两者都设置标志时定义。当发生指定的内存访问时,触发断点。以字节或表达式的对象大小指定内存访问窗口的大小。对于此断点类型,表达式必须解析为内存地址和内存类型。允许使用的运算符(&、&&、<、<=、>、>=、==和!=)在程序执行被暂停或执行命令之前比较变量值。
Execution Break(E)在Expression解析为代码地址时定义。当到达指定的代码地址时触发断点。代码地址必须引用CPU指令的第一个字节。
Conditional Break(C)在Expression不能简化为地址时定义。当条件表达式成为TRUE时,触发断点。条件表达式在每个CPU指令后重新计算,可能会显著减慢程序的执行速度。
设置一个在time.sec写入时触发的断点:BS WRITE time.sec
设置一个在主函数地址处执行时触发的断点:BS main
设置一个在timer0函数地址处执行并在第10次调用之后触发的断点,并执行命令"MyRegs()":BS timer0,10,“MyRegs()”
设置一个当sindex等于8时触发的条件断点:BS sindex == 8
设置一个当save_record[5].time.sec大于5时触发的条件断点,并在第三次满足条件时停止程序执行:BS save_record[5].time.sec > 5, 3
设置一个在读取interval.min访问时,当interval结构或联合的min元素为3时触发的内存访问断点:BS READ interval.min == 3
设置一个在写入savefirst访问时,并且savefirst为5且累加器(acc)为0x12时触发的内存访问断点:BS WRITE savefirst == 5 && acc == 0x12
对于Cortex-M处理器,使用常量作为地址表达式可能会导致数据大小比较不明确。可以使用指针类型转换来消除歧义。例如:
设置一个在地址0x20000018处写入0x00000003时触发的内存访问断点:BS WRITE * ((unsigned int*)0x20000018) == 0x00000003
对于Cortex-M处理器,可以使用相对路径指定文件并设置执行断点。例如:
设置一个在cpp_template应用程序中文件STM32F10x.s的第136行代码执行之前触发的断点:BS \cpp_template…/…/source/RVCT/STM32F10x.s\136, 1
Debug函数是µVision的一个强大功能,可以帮助调试和测试应用程序。Debug函数可以实现以下功能:
Debug函数使用C编程语言的子集。其基本的能力和限制如下:
本章包含以下几节内容:
使用内置的Debug函数编辑器创建、修改和编译debug函数。在调试模式下,通过菜单Debug - Function Editor打开编辑器。系统会要求您输入一个文件名,或者编辑器会打开在“Options for Target - Debug - Initialization File”字段中指定的初始化文件。该文件的内容在每次启动调试会话时进行执行编译处理并且执行脚本函数,类似于python 脚本编译器。
在debug 环境下,在命令行窗口,在调试会话中使用INCLUDE命令来读取和处理文件。在调试过程中,定义在该文件中的Debug函数会立即生效。调试命令会在解析文件时执行。例如:
>INCLUDE MYFUNCS.INI
从命令窗口调用和运行debug函数。在命令行中输入函数名和参数。例如,要运行内置的printf函数,请输入以下文本:
>> printf ("Hello World\n")
µVision调试器将打印文本"Hello World"到输出。
作为另一种方法,可以定义一个工具栏按钮来调用该函数:
DEFINE BUTTON "button_label", "command"
DEFINE BUTTON "Print HelloWorld", "printf ("Hello World\n")"
用户鼠标点击工具栏按钮即可触发;
预定义函数可以帮助开发人员调试应用程序并创建自己的函数。
下表列出了所有预定义的调试函数:
用户函数是由开发人员创建的,可用于µVision调试器中进行调试。可以直接在命令窗口或函数编辑器中创建用户函数。有关详细信息,请参阅创建函数。用户函数可以使用系统变量。
用户函数以关键字FUNC开头,定义如下:
FUNC 返回类型 函数名 (参数列表) {
语句
}
其中:
示例:
以下用户函数显示了几个CPU寄存器的内容。
FUNC void MyRegs (void) {
printf ("---------- MyRegs() ----------\n");
printf (" R4 R8 R9 R10 R11 R12\n");
printf (" %04X %04X %04X %04X %04X %04X\n",
R4, R8, R9, R10, R11, R12);
printf ("------------------------------\n");
}
通过在命令窗口中输入函数名来调用函数。
>> MyRegs()
函数输出可能如下所示:
Signal Functions可以在µVision运行目标程序的同时在后台重复执行操作。它们有助于模拟和测试串行和模拟I/O、端口通信和其他重复的外部事件,如信号输入和脉冲。
开发人员可以直接在命令窗口或函数编辑器中创建Signal Functions。有关详细信息,请参阅Creating Functions。
必须至少调用内置函数twatch一次以延迟执行并让µVision运行目标程序。对于从未调用twatch的Signal Functions会触发错误。系统变量可以在Signal Functions中使用。
Signal Functions以关键字SIGNAL开头,定义如下:
SIGNAL void fname (parameter_list) {
statements
}
其中,
示例:
以下Signal Function将字符’A’放入串行输入缓冲区中,延迟1,000,000个CPU状态,然后重复执行。
SIGNAL void StuffS0in (void) {
while (1) {
S0IN = 'A';
twatch (1000000);
}
}
在命令窗口中输入函数名称来调用该函数。
>> StuffS0in()
µVision维护着所有活动Signal Functions的队列。一个Signal Function可以处于空闲(idle)或运行(running)状态。当一个Signal Function调用twatch函数时,它会进入空闲状态,持续的CPU状态数由twatch指定。在用户程序执行了指定数量的CPU状态后,Signal Function会变为运行状态。执行将继续在twatch之后的语句上进行。
当调用Signal Function时,它会被添加到队列并标记为运行状态。Signal Function只能被调用一次。如果函数被调用两次,则会显示警告信息。
如果一个Signal Function因为return语句而退出,则它会自动从活动Signal Functions的队列中移除。
命令SIGNAL STATE可以显示所有活动Signal Functions的状态。
命令SIGNAL KILL fname可以从队列中移除一个Signal Function
ANSI C和µVision中用于支持用户函数和Signal Functions特性的语言子集之间存在一些区别。
µVision不区分大小写。对象和控制语句的名称可以使用大写或小写字母。
µVision没有预处理器。不支持预处理指令,如#define、#include和#ifdef。
µVision不支持全局声明。标量变量必须在函数定义内部声明。您可以使用DEFINE命令定义符号,并像使用全局变量一样使用它们。
在µVision中,变量在声明时不能进行初始化。必须使用显式的赋值语句来初始化变量。
µVision函数仅支持标量变量类型。不允许使用结构体、数组和指针。这适用于函数的返回类型和参数类型。
µVision函数只能返回标量变量类型,不能返回指针和结构体。
µVision函数不能递归调用。在函数执行过程中,µVision会识别递归调用,并在检测到递归时中止函数执行。
µVision函数只能通过函数名直接调用,不支持通过指针进行间接函数调用。
µVision仅支持具有参数列表的ANSI风格函数声明。不支持旧的K&R(Kernighan和Ritchie)格式。
例如,以下是可接受的ANSI风格函数声明:
func test (int pa1, int pa2) {
/* ... */
}
以下是不被接受的K&R风格函数声明:
func test (pa1, pa2)
int pa1, pa2;
{
/* ... */
}
keil debug script 提供debug function 的扩展功能,能够使用类C语言风格的函数与变量,不能使用结构体定义,宏定义等,且在debug script中无法调用工程已经定义的C函数,会产生***error 34:undefined identifier,其函数库仅限于debug function,但是可以引用C环境下的全局变量(包括函数变量);
设计如下流程可以在命令行中触发C语言环境下的函数执行:
1:用户在命令行输入如下命令:
>> test_function_2(uart_send_cmd,0x20002008,0x10)
在debug模式下,输入命令可以不打断C语言环境运行,只是在命令输入时刻插入运行部分代码;
2:触发函数执行,部分函数执行于PC端,通过func_addr = addr,直接给C语言环境下全局变量赋值,通过set_bit 函数调用_RDWORD _WDWORD等预定义函数操作CPU寄存器; set_bit(0xE000ED04UL,28,1,1); 用于设置SVC 标志位触发 SVC_Handler函数执行;
FUNC void test_function_2(int addr,int param1,int param2)
{
func_addr = addr;
func_param_num =2;
cmd_debug_flag =1;
func_param_1 = param1;
func_param_2 = param2;
debug_dhcsr = _RDWORD(0xE000EDF0);
set_bit(0xE000ED04UL,28,1,1);
exec("G");
}
3:test_function_2 函数退出,芯片硬件环境继续执行;
4:芯片硬件探测SVC 被置起,跳转到SVC_Handler 函数执行,最终跳转到PendSV_Handler函数中执行;
5:PendSV_Handler 判断 cmd_debug_flag 触发是否由debug function触发,若是则通过强制转换实现目标函数执行;
6:uart_send_cmd(0x20002008,0x10)函数执行将相关内存中的内容发送出去;函数入参可以为全局变量,或者具体的地址数值,需要用户清楚理解函数调用的入参;
7:清除相关寄存器的触发设置,使得系统全速运行;
1: 快速实现类python/ 类shell 执行效果,相对而言,不用绑定函数和命令,格式类似于C语言的调用;
比如:可以直接调用UART等接口,也可以调用更上层的函数API,比如HCI_SEND() HCI底层实现调用UART接口发送数据;
2:可以快速调试系统,在C环境下添加一下获取系统信息的函数,可以在函数运行的时候,定时获取一定的执行信息,或者输入一定的信息;
3:复用一定的C环境下的C函数,容易在一定的条件下重复触发函数执行;
4:与breakpoint 结合,可以在断点时候触发额外执行复杂函数,而不仅仅是 user defined function;
#include <stdint.h> #include <stdbool.h> #include <stdlib.h> #include <string.h> #include <assert.h> #include "platform.h" uint32_t cpu_reg_r0 =0; uint32_t cpu_reg_r1 =0; uint32_t cpu_reg_r2 =0; uint32_t cpu_reg_r3 =0; uint32_t cpu_reg_r4 =0; uint32_t cpu_reg_r5 =0; uint32_t cpu_reg_r6 =0; uint32_t cpu_reg_r7 =0; uint32_t cpu_reg_r8 =0; uint32_t cpu_reg_r9 =0; uint32_t cpu_reg_r10 =0; uint32_t cpu_reg_r11 =0; uint32_t cpu_reg_r12 =0; uint32_t cpu_reg_sp =0; uint32_t cpu_reg_lr =0; uint32_t cpu_reg_pc =0; uint32_t cpu_reg_xpsr =0; uint32_t func_addr =0; uint32_t func_param_num =0; uint32_t func_param_1 =0; uint32_t func_param_2 =0; uint32_t func_param_3 =0; uint32_t func_param_4 =0; uint32_t cmd_debug_flag =0; uint32_t debug_dhcsr =0; void svc_function_end( void ) { cmd_debug_flag =0; } #include "FreeRTOSConfig.h" typedef uint32_t (* func_1_t)(void *); typedef uint32_t (* func_2_t)(void *,void *); typedef uint32_t (* func_3_t)(void *,void *,void *); typedef uint32_t (* func_4_t)(void *,void *,void *,void *); __weak void PendSV_Handler_c(void) { } void PendSV_Handler(void) { __nop(); __nop(); if(cmd_debug_flag ==1) { if(func_param_num ==1) { func_1_t fun = (func_1_t)(func_addr+1); fun((void *)func_param_1); } if(func_param_num ==2) { func_2_t fun = (func_2_t)(func_addr+1); fun((void *)func_param_1,(void *)func_param_2); } if(func_param_num ==3) { func_3_t fun = (func_3_t)(func_addr+1); fun((void *)func_param_1,(void *)func_param_2,(void *)func_param_3); } if(func_param_num ==4) { func_4_t fun = (func_4_t)(func_addr+1); fun((void *)func_param_1,(void *)func_param_2,(void *)func_param_3,(void *)func_param_4); } cmd_debug_flag =0; if(debug_dhcsr&CoreDebug_DHCSR_S_HALT_Msk) { CoreDebug->DHCSR = 0XA05F0000 |(CoreDebug->DHCSR&0XFFFF)|CoreDebug_DHCSR_C_HALT_Msk; CoreDebug->DHCSR = 0XA05F0000 |(CoreDebug->DHCSR&0XFFFF)|CoreDebug_DHCSR_C_STEP_Msk; } }else { PendSV_Handler_c(); } } __asm void svc_function_start( void ) { PRESERVE8 IMPORT cpu_reg_r0 IMPORT cpu_reg_r1 IMPORT cpu_reg_r2 IMPORT cpu_reg_r3 IMPORT cpu_reg_r4 IMPORT cpu_reg_r5 IMPORT cpu_reg_r6 IMPORT cpu_reg_r7 IMPORT cpu_reg_r8 IMPORT cpu_reg_r9 IMPORT cpu_reg_r10 IMPORT cpu_reg_r11 IMPORT cpu_reg_r12 IMPORT cpu_reg_sp IMPORT cpu_reg_lr IMPORT cpu_reg_pc IMPORT cpu_reg_xpsr IMPORT func_addr IMPORT func_param_num IMPORT func_param_1 IMPORT func_param_2 IMPORT func_param_3 IMPORT func_param_4 // PUSH {R0-R12} // POP {R0-R11} // ldr R12,=cpu_reg_r0 // ldr R0,[R12] // ldr R12,=cpu_reg_r1 // ldr R1,[R12] // ldr R12,=cpu_reg_r2 // ldr R2,[R12] // ldr R12,=cpu_reg_r3 // ldr R3,[R12] // ldr R12,=cpu_reg_r4 // ldr R4,[R12] // ldr R12,=cpu_reg_r5 // ldr R5,[R12] // ldr R12,=cpu_reg_r6 // ldr R6,[R12] // ldr R12,=cpu_reg_r7 // ldr R7,[R12] // ldr R12,=cpu_reg_r8 // ldr R8,[R12] // ldr R12,=cpu_reg_r9 // ldr R9,[R12] // ldr R12,=cpu_reg_r10 // ldr R10,[R12] // ldr R12,=cpu_reg_r11 // ldr R11,[R12] // ldr R12,=cpu_reg_sp // ldr R12,[R12] // // ldr R12,=cpu_reg_pc // ldr LR,[R12] // BX LR SVC #0 //SVC_Dead // B SVC_Dead ; None Existing SVC ALIGN } void cpu_regs_reset(void) { cpu_reg_r0 =0; cpu_reg_r1 =0; cpu_reg_r2 =0; cpu_reg_r3 =0; cpu_reg_r4 =0; cpu_reg_r5 =0; cpu_reg_r6 =0; cpu_reg_r7 =0; cpu_reg_r8 =0; cpu_reg_r9 =0; cpu_reg_r10 =0; cpu_reg_r11 =0; cpu_reg_r12 =0; cpu_reg_sp =0; cpu_reg_lr =0; cpu_reg_pc =0; cpu_reg_xpsr =0; }
FUNC void get_cpu_regs(void) { printf ("---------- cpu_regs ----------\n"); printf ("R0 = 0x%08X\r\n",R0 ); printf ("R1 = 0x%08X\r\n",R1 ); printf ("R2 = 0x%08X\r\n",R2 ); printf ("R3 = 0x%08X\r\n",R3 ); printf ("R4 = 0x%08X\r\n",R4 ); printf ("R5 = 0x%08X\r\n",R5 ); printf ("R6 = 0x%08X\r\n",R6 ); printf ("R7 = 0x%08X\r\n",R7 ); printf ("R8 = 0x%08X\r\n",R8 ); printf ("R9 = 0x%08X\r\n",R9 ); printf ("R10 = 0x%08X\r\n",R10 ); printf ("R11 = 0x%08X\r\n",R11 ); printf ("R12 = 0x%08X\r\n",R12 ); printf ("SP = 0x%08X\r\n",SP ); printf ("LR = 0x%08X\r\n",LR ); printf ("PC = 0x%08X\r\n",PC ); printf ("XPSR = 0x%08X\r\n",XPSR); printf ("------------------------------\n"); } FUNC void save_cpu_regs(void) { cpu_reg_r0 = R0 ; cpu_reg_r1 = R1 ; cpu_reg_r2 = R2 ; cpu_reg_r3 = R3 ; cpu_reg_r4 = R4 ; cpu_reg_r5 = R5 ; cpu_reg_r6 = R6 ; cpu_reg_r7 = R7 ; cpu_reg_r8 = R8 ; cpu_reg_r9 = R9 ; cpu_reg_r10 = R10 ; cpu_reg_r11 = R11 ; cpu_reg_r12 = R12 ; cpu_reg_sp = SP ; cpu_reg_lr = LR ; cpu_reg_pc = PC ; cpu_reg_xpsr = XPSR; } FUNC void resume_cpu_regs(void) { R0 = cpu_reg_r0 ; R1 = cpu_reg_r1 ; R2 = cpu_reg_r2 ; R3 = cpu_reg_r3 ; R4 = cpu_reg_r4 ; R5 = cpu_reg_r5 ; R6 = cpu_reg_r6 ; R7 = cpu_reg_r7 ; R8 = cpu_reg_r8 ; R9 = cpu_reg_r9 ; R10 = cpu_reg_r10 ; R11 = cpu_reg_r11 ; R12 = cpu_reg_r12 ; SP = cpu_reg_sp ; LR = cpu_reg_lr ; PC = cpu_reg_pc ; XPSR = cpu_reg_xpsr; } FUNC void test_function_0(int addr) { } FUNC unsigned long set_bit(unsigned long addr,int start_bit, int bits,int value) { unsigned long temp; unsigned long mask; //WRITE_REG((REG), (((READ_REG(REG)) & (~(CLEARMASK))) | (SETMASK))) temp =0; temp = _RDWORD(addr); // printf("get the register addr: %08x value : %08x \r\n",addr,temp); if(bits!= 32) { mask = (((1<<bits) -1)<<start_bit); //printf("get the register mask: %08x bits : %08x \r\n",mask,bits); }else { mask = 0XFFFFFFFF; } temp = temp&(~mask); //printf("get the register addr: %08x value : %08x \r\n",addr,temp); temp = temp|(value<<start_bit); // printf("set the register addr: %08x value : %08x \r\n",addr,temp); _WDWORD(addr,temp); return 0; } FUNC void test_function_1(int addr,int param) { func_addr = addr; func_param_num =1; cmd_debug_flag =1; func_param_1 = param; set_bit(0xE000ED04UL,28,1,1); exec("G"); } FUNC void test_function_2(int addr,int param1,int param2) { func_addr = addr; func_param_num =2; cmd_debug_flag =1; func_param_1 = param1; func_param_2 = param2; debug_dhcsr = _RDWORD(0xE000EDF0); set_bit(0xE000ED04UL,28,1,1); exec("G"); } FUNC void test_function_3(int addr,int param1,int param2,int param3) { func_addr = addr; func_param_num =3; cmd_debug_flag =1; func_param_1 = param1; func_param_2 = param2; func_param_3 = param3; debug_dhcsr = _RDWORD(0xE000EDF0); set_bit(0xE000ED04UL,28,1,1); exec("G"); } FUNC void test_function_4(int addr,int param1,int param2,int param3,int param4) { func_addr = addr; func_param_num =2; cmd_debug_flag =1; func_param_1 = param1; func_param_2 = param2; func_param_3 = param3; func_param_4 = param4; debug_dhcsr = _RDWORD(0xE000EDF0); set_bit(0xE000ED04UL,28,1,1); exec("G"); }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。