复位向量
复位向量的地址统一在0x3F FFC0处。
0x003FFFC0处保存的是复位向量的地址,其值为0x003FD2AE。
复位后CPU的状态
PC指针指向0x003FD2AE,栈指针SP指向0x0400,XAR0寄存器为0xFFFFFFFF,其他寄存器全为0.
进入InitBoot
0x003FD2AE地址处保存的是厂家固化的InitBoot。
汇编指令为:
InitBoot的汇编源码
可以找到其汇编源代码:
D:\ti\c2000\C2000Ware_3_04_00_00\libraries\boot_rom\f2838x\revA\rom_sources\cpu1\F2838x_ROM\bootROM\source\cpu1brom_init_boot.asm
节选部分代码如下:
;
; Function: InitBoot
;
; This function performs the initial boot routine
; for the CPU1 boot ROM.
;
; This module performs the following actions:
;
; 1) Initializes the stack pointer
; 2) Sets the device for C28x operating mode
; 3) Setup device systems
; 4) Run RAM initialization and call the main boot function
;.sect ".InitBoot"
InitBoot:;
; Create stack section
;
__stack: .usect ".stack",0;
; EFUSE INTOSC and PMM Trim Blanking Window
;
; Calculate the Count for 75 uS at 15/4 MHz untrimmed clock, with buffer.
; This would result in 83uS blank window for count of 311
;MOV @T,#311RPT @T
|| NOP;
; Initialize the stack pointer
;MOV SP, #__stack;
; Initialize the device for running in C28x mode.
;C28OBJ ;Select C28x object modeC28ADDR ;Select C27x/C28x addressingC28MAP ;Set blocks M0/M1 for C28x modeCLRC PAGE0 ;Always use stack addressing modeMOVW DP, #0 ;Initialize DP to point to the low 64 KCLRC OVM ;Clear overflow mode bit
;
; Set Product Mode shift to 0
;SPM 0;
; Check for HWBIST as reset cause and handle accordingly
;
cpu1brom_hwbist_reset_check:
;
; if((CpuSysRegs.RESC.bit.HWBIST & 0x1) == 1) then check CSTCRET
;MOVW DP, #0x174e ;Set DP to CpuSysRegs.RESCAND AL, @0x0, #0x20 ;Load ACC with (CpuSysRegs.RESC & 0x20) which is HWBIST RESC bitLSR AL, 5 ;Right shift ACC (HWBIST RESC bit) value by 5TBIT @AL, #0x0 ;Check bit 0 of ACC value (HWBIST RESC)SBF cpu1brom_hwbist_reset_done, NTC ;Branch if reset bit not set
可以看到,二者是一一对应的:
代码版本
源代码的版本为v2.0,日期为19年8月。
与 CPU固件中的值是一致的。固件中boot版本号保存在0x003F FF7A的地方。
查看该处内容,正是0x0200 和0x0819
InitBoot代码分析
初始化CPU环境
;
; Initialize the device for running in C28x mode.
;C28OBJ ;Select C28x object modeC28ADDR ;Select C27x/C28x addressingC28MAP ;Set blocks M0/M1 for C28x modeCLRC PAGE0 ;Always use stack addressing modeMOVW DP, #0 ;Initialize DP to point to the low 64 KCLRC OVM ;Clear overflow mode bit
;
; Set Product Mode shift to 0
;SPM 0
检查硬件内置自检的结果
;
; Check for HWBIST as reset cause and handle accordingly
;
cpu1brom_hwbist_reset_check:
;
; if((CpuSysRegs.RESC.bit.HWBIST & 0x1) == 1) then check CSTCRET
;MOVW DP, #0x174e ;Set DP to CpuSysRegs.RESCAND AL, @0x0, #0x20 ;Load ACC with (CpuSysRegs.RESC & 0x20) which is HWBIST RESC bitLSR AL, 5 ;Right shift ACC (HWBIST RESC bit) value by 5TBIT @AL, #0x0 ;Check bit 0 of ACC value (HWBIST RESC)SBF cpu1brom_hwbist_reset_done, NTC ;Branch if reset bit not set
上述代码的作用是,读取(0x174e << 6 + 0x00=0x5D380)处的内容,再与0x20作“与运算”(相当于是判断bit5)。测试结果如果为0,则跳转到cpu1brom_hwbist_reset_done处(地址为0x3fd2dc)。
外设地址0x5D380处正是CPU复位原因寄存器。
系统控制寄存器组中,CPU系统寄存器的起始地址为0x0005 D300:
CPU系统寄存器中,复位原因寄存器的偏移量为0x80:
该寄存器的定义:
其中HWBISTn的说明:
如果该位为1,说明CPU的HWBIST自检不通过。
查看寄存器状态,该位为0.说明CPU自检结果正常。
继续运行,则跳转到0x3F D2DC处。对应的是cpu1brom_hwbist_reset_done函数。
检查EFUSE错误
cpu1brom_hwbist_reset_done:;
; Check for any eFUSE errors
;MOVW DP, #0x1741 ;Set DP to Device Config RegisterMOVL ACC, @0x34 ;Load DevConfig.FUSEERR.allSBF cpu1brom_fuseerr_none, EQ ;Branch if FUSEERR is ZEROMOVB ACC, #21 ;Load error code value (for single bit check) to ACCCMPL ACC, @0x34 ;Compare ACC value and DevConfig.FUSEERR.all valueSBF cpu1brom_fuseerr_reset, NEQ ;Branch to trigger reset if not equal (multi-bit error)SB cpu1brom_fuseerr_none, UNC ;Branch to continue flow (only single bit error)
先读取(0x1741 << 6) + 0x34 = 0x5 D074处的值。
对应的是,系统控制寄存器组(SYSCTRL)中的DevCfgRegs的FUSEERR寄存器。
如果寄存器的值为0,则跳转到cpu1brom_fuseerr_none。
没有错误,继续执行。
禁止看门狗
;
; Disable watchdog
;
cpu1brom_disable_wdog:EALLOWMOVW DP, #0x1c0 ;Set DP to Watchdog RegisterMOVB @0x29, #0x68, UNC ;Disable WatchdogEDIS
往寄存器中写入0x68,写入的地址=(0x01C0 << 6 ) + 0x29 = 0x7029。对应的是看门狗控制寄存器WDCR:
写入的0x68对应的是WDDIS=1, WDCHK=101, WDPS=000:
注意:WDDIS写入1为禁止看门狗,写入0则使能。
禁止看门狗后,继续执行。
检查POR和XRS复位
;
; Check if reset cause is from POR or XRS
;MOVW DP, #0x174e ;Set DP to CpuSysRegs.RESCMOVL ACC, @0x0 ;Load ACC with CpuSysRegs.RESCMOV AH, #0x0 ;Clear upper 16-bit of ACCANDB AL, #0x3 ;Mask to only include POR and XRS RESC bitsTEST ACCSBF stack_init, EQ ;Branch if ACC is zero (Not a POR or XRS reset) to stack init,
再次读取RESC寄存器,判断低2位。如果都等于0(既不是POR,也不是XRS),则跳转到stack_init。
由于现在是带着仿真器调试的,不是上电或者外部复位:
因此,会直接跳转到stack_init。
正常上电时的执行情况,后面再单独分析。
栈初始化
;
; Not POR - Initialize the stack used for boot to zero
;
stack_init:MOV AL, #0x150 ;Size of stackMOV AH, #0
stack_ram_zero_loop:MOV *SP++, #0 ;Zero out RAM for stackSUBB ACC, #1BF stack_ram_zero_loop, GEQ
stack_ram_init_done:MOV SP, #__stack ;Re-Initialize the stack pointer
相当于C代码:
stack_size = 0x150;
while(stack_size--)
{*sp++ = 0;
}
执行情况:当ACC自减后等于0时, BF stack_ram_zero_loop, GEQ这一句还是会跳转。因为GEQ的条件是“大于等于0”。再下一圈,ACC=-1=0xFFFFFFFF时,才不满足跳转条件,继续向下执行。
此时,ACC=-1:
调用CPU1BROM_startSystemBoot函数
stack_ram_init_done:MOV SP, #__stack ;Re-Initialize the stack pointer;
; RAM Init or Stack Init is complete, prepare to begin system initialization
;
cpu1brom_perform_ram_inits_complete:MOVW DP,#0 ;Initialize DP to point to the low 64 KCLRC OVM ;Clear overflow mode bitSPM 0 ;Set Product Mode shift to 0
;
; Branch to system initialization to run final initializations and execute boot mode
;LCR CPU1BROM_startSystemBoot
接下来,将SP指针还原为__stack=0x0060。最后调用CPU1BROM_startSystemBoot函数。
启动系统Boot
CPU1BROM_startSystemBoot函数为C代码。文件路径:
D:\ti\c2000\C2000Ware_3_04_00_00\libraries\boot_rom\f2838x\revA\rom_sources\cpu1\F2838x_ROM\bootROM\source\cpu1brom_system_boot.c
函数说明如下:
//*****************************************************************************
//
// Performs system initialization and boot mode execution
//
// Parameters: None
//
// This function performs the following actions:
// - Enable NMI
// - Initialization the DCSM
// - Perform memory power on self test (MPOST) (if enabled in user OTP)
// - Enable pullups on unbonded GPIOs
// - Decode the requested boot mode
// - Run the requested boot mode or bootloader
//
// Return: Returns the memory entry address that the device will branch to
// upon exiting boot.
//
//*****************************************************************************
uint32_t CPU1BROM_startSystemBoot(void)
{// …………
}
关键代码段:CPU1BROM_selectBootMode
选择BOOT模式
CPU1BROM_selectBootMode函数在文件cpu1brom_select_bootmode.c中。
uint32_t CPU1BROM_selectBootMode(void)
{uint32_t bootMode;EALLOW;if(((uint32_t)HWREG(CPUSYS_BASE + SYSCTL_O_RESC) & (uint32_t)SYSCTL_RESC_TRSTN_PIN_STATUS) == SYSCTL_RESC_TRSTN_PIN_STATUS){//// Run emulation boot flow when debugger connected.//bootMode = CPU1BROM_getEmulationBootMode();}else{//// Run standalone/true boot flow when debugger isn't connected.//bootMode = CPU1BROM_getStandaloneBootMode();}EDIS;return(bootMode);
}
连接仿真器时,会判断EMU_BOOTPIN_CONFIG_KEY的值,如果是0xA5,则进入仿真standalone模式;如果是0x5A,则读取 BOOTPINCONFIG 的值,选择相应的模式。其他值,则进入WaitBoot模式。
EMUBOOTPINCONFIG寄存器的地址是0x0D00。
注意:此地址与中断向量表PieVectTable有重叠,但不影响。具体情况可参考:
TMS320F280025的BOOT流程_booksyhay的专栏-CSDN博客CPU启动流程根据启动时是否连接了仿真器,分为两种情况:Standalone BootEmulation Boot独立运行时的流程Standalone Boot先看整体流程图:BOOT管脚配置BOOTPINCONFIGBOOT开始时,首先读取管脚配置PINCONFIG。管脚配置有2组:Z1和Z2.Z2的优先级比Z1的高。当Z2有效时,会忽略Z1的配置 。由于这个配置是一次性写入的,写入之后不能更改。因此,通常情况下,先全能Z1配置,保留...https://blog.csdn.net/booksyhay/article/details/120172063
一般情况下,0x0D00处的最高字节不是0x5A或者0xA5,比如,我仿真时就是0xA6。
因此,会进入WaitBoot模式。
在WAIT_BOOT模式
//// Get boot mode selected//CPU1BROM_bootMode = CPU1BROM_selectBootMode();…………//// Enter specified wait boot or enable watchdog, then branch to address//if(CPU1BROM_bootMode == WAIT_BOOT){SysCtl_enableWatchdog();for(;;){}}
在WAIT_BOOT模式下,程序会进入死循环。不会跳转到用户的main函数。
如果程序进入死循环,但又不是用户空间,而是BOOT空间,则可以查看手册,看是什么状况。
比如,WAIT_BOOT模式下,PC地址为0x3FB114,确实是处于wait boot mode的代码区间。