(rt-thread gdb)cm系列的GDB移植

本文详细介绍Cortex-M3处理器的调试技术,包括DebugMonitor模式的启用、断点设置、观察点配置及单步执行等核心功能。文章还提供了具体的寄存器配置代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

cm版本已经更新,关于项目的更多说明

见https://code.youkuaiyun.com/wzyy2/gdbstub4rtt/tree/master/readme-zh.txt


移植主要分三个主要的实现和debug模式

ps : CM0的断点设置有所不同,不能运行


Debug Monitor(调试监控器)

CM系列可以脱离JTAG调试的主要基础就是debugmon模式

关于debugmon和halt的区别,见以下图


简单的说debugmon可以按照一般的异常处理,而halt是直接停机内核

关于debugmon和halt debug的办法,见以下两张图



使用 debug monitor的办法就是置位DEMCR寄存器的MON_EN

软件唤起debug monitor的办法是置位DEMCR寄存器的MON_PENDING

    base = (unsigned long*)(GDB_DEBUG_REG_BASE + GDB_DEBUG_REG_DEMCR);
     /* 
      * Enable the debug monitor. When enabled, the System handler priority
      * register controls its priority level.
      * If disabled, then all debug events go
      * to Hard fault
      */
    *base |= GDB_DEBUG_REG_DEMCR_MON_EN;

    //Fall into debug monitor
    *base |= GDB_DEBUG_REG_DEMCR_MON_PEND;


寄存器说明见Cortex-M3 Technical Reference Manual  10.2.4 Debug Exception and Monitor Control Register


1.断点(breakpoint)

CM断点的主要实现是使用Flashpatch and Breakpoint(FPB):

.A set of address matching tags, that reroute accesses into flash to a special part of SRAM. This permits patching flash locations for breakpointing and quick fixes orchanges.

FPB可以被编程用来实现断点功能,他有一个比较器,当地址,有两个选择,一是将该地址指向指定的ram地址,二是在该地址设置BKPT指令,因为我们要用的是断点功能,自然是设置断点了

FPB的使用有两个使能位,一个是总开关

    // Enable the FPB-FLASH PATCH BREAKPOINT 
    base = (unsigned long*)(GDB_FPB_REG_BASE + GDB_FPB_REG_CTRL);
    *base |= GDB_FPB_REG_CTRL_KEY | GDB_FPB_REG_CTRL_ENABLE ;
一个是每个比较器的开关

            base = (unsigned long*)(GDB_FPB_REG_BASE + GDB_FPB_REG_COMP + i * 4);
            
            *base = GDB_FPB_REG_COMP_ADDR & ((unsigned long)(breakinfo[i].addr));

            if (breakinfo[i].addr & 2)
                *base |= (1UL << 31); //set BKPT on upper halfword
            else 
                *base |= (1UL << 30); //set BKPT on lower halfword,

            *base |= GDB_FPB_REG_COMP_ENABLE ; 

设置断点的办法如上,把要设置地址的28-2位写入FPB_COMP的28-2位,要在高半字设置断点需要置位BIT31,低半字则置位BIT30

更多功能及寄存器说明见Cortex-M3 Technical Reference Manual  11.4 FPB


2.观察点(watchpoint)

CM观察点的主要实现是使用Data Watchpoint and Trace(DWT)

待更

/**
 * gdb_breakpoint - generate a breadk
 * It is used to sync up with a debugger and stop progarm
 */
void gdb_breakpoint()
{
    volatile unsigned long *base;

    // Enable the FPB-FLASH PATCH BREAKPOINT 
    base = (unsigned long*)(GDB_FPB_REG_BASE + GDB_FPB_REG_CTRL);
    *base |= GDB_FPB_REG_CTRL_KEY | GDB_FPB_REG_CTRL_ENABLE ;

    base = (unsigned long*)(GDB_DEBUG_REG_BASE + GDB_DEBUG_REG_DEMCR);
     /* 
      * Enable the debug monitor. When enabled, the System handler priority
      * register controls its priority level.
      * If disabled, then all debug events go
      * to Hard fault
      */
    *base |= GDB_DEBUG_REG_DEMCR_MON_EN;

    // Enable DWT
    *base |= GDB_DEBUG_REG_DEMCR_TRCENA ;

    //Fall into debug monitor
    *base |= GDB_DEBUG_REG_DEMCR_MON_PEND;

}

    // Install the watchpoint
    for (i = 0; i < HWP_NUM; i++) {
        if (watchinfo[i].enabled) {
            base = (unsigned long*)(GDB_DWT_REG_BASE + GDB_DWT_REG_COMP + i * 12);
            *base = watchinfo[i].addr;

            base = (unsigned long*)(GDB_DWT_REG_BASE + GDB_DWT_REG_MASK + i * 12);
            while (watchinfo[i].len >> num) {
                num++;
            }
            *base = num - 1; //DWT matching is performed as:(ADDR & (~0 << MASK)) == COMP

            base = (unsigned long*)(GDB_DWT_REG_BASE + GDB_DWT_REG_FUNCTION + i * 12);

            if (watchinfo[i].type == BP_WRITE_WATCHPOINT) 
                *base =  (*base & ~GDB_DWT_REG_FUNCTION_FUC) + 0x05;            
            else if (watchinfo[i].type == BP_READ_WATCHPOINT) 
                *base =  (*base & ~GDB_DWT_REG_FUNCTION_FUC) + 0x06;          
            else if (watchinfo[i].type == BP_ACCESS_WATCHPOINT) 
                *base =  (*base & ~GDB_DWT_REG_FUNCTION_FUC) + 0x07;

        }   
    }

更多功能及寄存器说明见Cortex-M3 Technical Reference Manual  11.5 DWT


3.单步(singlestep)

单步主要实现是DEMCR寄存器的MON_STEP位

.When MON_EN= 1, this steps the core. When MON_EN= 0, this bitis ignored. This is the equivalent to C_STEP. Interrupts are only stepped according to the priority of the monitor and settings of PRIMASK, FAULTMASK, or BASEPRI

/*we need to block all pending interrupts by swtting basepri
 * before doing the steo
 */
void gdb_single_step()
{
    volatile unsigned long *base;

    //mask all interrupts
    single_step_basepri = regs->basepri;
    regs->basepri = GDB_CORTEXM_PRIORITY_MAX;

    //When MON_EN = 1, this steps the core     
    base = (unsigned long*)(GDB_DEBUG_REG_BASE + GDB_DEBUG_REG_DEMCR);
    *base |= GDB_DEBUG_REG_DEMCR_MON_STEP;

    /* Clear any bits set in DFSR*/
    base = (unsigned long*)(GDB_NVIC_REG_BASE + GDB_NVIC_REG_DFSR);
    *base = 0xffffffff;

}

void gdb_clear_single_step()
{
    volatile unsigned long *base;

    regs->basepri = single_step_basepri;

    /*clear single step*/
    base = (unsigned long*)(GDB_DEBUG_REG_BASE + GDB_DEBUG_REG_DEMCR);
    *base &= ~GDB_DEBUG_REG_DEMCR_MON_STEP;

    // Clear any bits set in DFSR
    base = (unsigned long*)(GDB_NVIC_REG_BASE + GDB_NVIC_REG_DFSR);
    *base = 0xffffffff;

这里有很重要的一点就是我们要通过basepri来屏蔽中断

之所以要屏蔽中断是因为设置单步的目的的是为了到达当前函数的下一行

而不是在中断里单步

如果不屏蔽的话,调试模式返回后会先去执行中断

然后我们就要淹没在无止境的systick里出不来了生气

还有一个地方就是GDB_CORTEXM_PRIORITY_MAX

#ifndef GDB_CORTEXM_PRIORITY_MAX 
    #define GDB_CORTEXM_PRIORITY_MAX  (1 << 6)
#endif

如果优先级分组有更改要更改这个宏

我们设置basepri的目的是屏蔽低优先级的中断,同时不屏蔽debugmon

debugmon的默认优先级是0,所以至少要保证GDB_CORTEXM_PRIORITY_MAX的抢占优先级要大于0

不然可能出现单步之后无法进入调试模式的情况


寄存器说明见Cortex-M3 Technical Reference Manual  10.2.4 Debug Exception and Monitor Control Register

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值