本帖最后由 jixulifu2 于 2024-7-14 16:39 编辑
上一章点灯调试串口的过程中,跳过了系统初始化部分。今天就来一起过一下吧。
0x00: Device_init()中的函数:
//
// Disable the watchdog
//
SysCtl_disableWatchdog();
//
// Call Device_cal function when run using debugger
// This function is called as part of the Boot code. The function is called
// in the Device_init function since during debug time resets, the boot code
// will not be executed and the gel script will reinitialize all the
// registers and the calibrated values will be lost.
// Sysctl_deviceCal is a wrapper function for PMUTrims_cal OscTrims_cal
//
SysCtl_deviceCal();
//
// Call Flash Initialization to setup flash waitstates. This function must
// reside in RAM.
//
Flash_initModule(FLASH0CTRL_BASE, FLASH0ECC_BASE, DEVICE_FLASH_WAITSTATES);
//
// Set up PLL control and clock dividers
//
SysCtl_setClock(DEVICE_SETCLOCK_CFG);
//
// Make sure the LSPCLK divider is set to the default (divide by 4)
//
SysCtl_setLowSpeedClock(SYSCTL_LSPCLK_PRESCALE_4);
//
// These asserts will check that the #defines for the clock rates in
// device.h match the actual rates that have been configured. If they do
// not match, check that the calculations of DEVICE_SYSCLK_FREQ and
// DEVICE_LSPCLK_FREQ are accurate. Some examples will not perform as
// expected if these are not correct.
//
ASSERT(SysCtl_getClock(DEVICE_OSCSRC_FREQ) == DEVICE_SYSCLK_FREQ);
ASSERT(SysCtl_getLowSpeedClock(DEVICE_OSCSRC_FREQ) == DEVICE_LSPCLK_FREQ);
//
// Turn on all peripherals
//
Device_enableAllPeripherals();
//
// Lock VREGCTL Register
// The register VREGCTL is not supported in this device. It is locked to
// prevent any writes to this register
//
ASysCtl_lockVREG();
static inline void
SysCtl_disableWatchdog(void)
{
EALLOW;
//
// Set the disable bit.
//
HWREG(WD_BASE + SYSCTL_O_WDCR) = (HWREG(WD_BASE + SYSCTL_O_WDCR) & ~0x80)
| (SYSCTL_WD_CHKBITS | SYSCTL_WDCR_WDDIS);
EDIS;
}
使用静态+内联修饰函数,确保代码只提供接口,不能修改。内联修饰优化效率。
EALLOW;EDIS;是宏定义的汇编代码。
跳转定义后发现除了常用的NOP还有EINT;和DINT;
#define NOP asm volatile("nop")
#define EALLOW asm("csrsi 0x7C1, 0x01") // eallow register id is 0x7C1 ,enable write spieacl register
#define EDIS asm("csrci 0x7C1, 0x01") // disable
//#define ESTOP0 asm(" ESTOP0") //if in debug ,set 1 dsp stop,not in debug, just a nop
//#define ESTOP0 asm(" ebreak"); //send debug call
#define EINT asm("csrsi mstatus, 0x8")
#define DINT asm("csrci mstatus, 0x8")
EALLOW;EDIS;注释写的很清楚,分别是开启写特殊功能寄存器功能和关闭写特殊功能寄存器。
在官方参考手册中,有如下解释:
3.1.2 EALLOW 保护
系统中的一些寄存器通过 EALLOW 保护机制来防止出现虚假的 CPU 写操作。 它使用
特殊的 CPU 指令 EALLOW 和 EDIS 来启用和禁用对受保护寄存器的访问。 当前保护状态
由 CPU ST1 寄存器中的 EALLOW 位给出, 如表 3-1。
寄存器保护在启动时默认启用。 当受保护时, CPU 对受保护寄存器的所有写操作都
被忽略。 只允许 CPU 读、 JTAG 读和 JTAG 写。 如果通过执行 EALLOW 指令禁用了保护,
则允许 CPU 自由地写入受保护的寄存器。 在修改寄存器之后, 可以通过执行 EDIS 指令
清除 EALLOW 位来再次保护它们。
对时钟配置和外设时钟启用寄存器的写入可能会被禁用, 直到下一次通过写入特
殊锁寄存器进行复位
表 3-1 访问受 allow 保护的寄存器
EALLOW 位 CPU 写 CPU 读 JTAG 写 JTAG 读
0 Ignored Allowed Allowed Allowed
1 Allowed Allowed Allowed Allowed
(1) EALLOW 位被 JTAG 端口覆盖, 允许在代码调试期间完全访问受保护的寄存器 IDE
™ 接口。
DINT和EINT没有注释,查询参考手册里发现如下解释:
和 PIE 一样, CPU 为它的每个中断提供标志并使能寄存器位。 有一个使能寄存器
(IER)和一个标志寄存器(IFR), 它们都是内部 CPU 寄存器。 还有一个全局中断掩码,
由 Mstatus 寄存器中 MIE 位控制。 可以使用 CPU 的 SETC 和 CLRC 指令设置和清除此掩
码。 在 C 代码中, DINT 和 EINT 宏可以用于此目的。(不同)
可以发现DINT和EINT是开关全局中断的汇编
参考手册中3.5.4.3介绍禁用中断章节的内容中有实际流程设计DINT和EINT:
1.全局禁用中断( DINT)。
2.清除 PIEIER bit。
3.等待 5 个周期, 以确保任何传播中断已到达 CPU IFR 寄存器。
4.清除中断 PIE 组的 CPU IFR 位。
5.清除中断的 PIE 组的 PIEACK 位。
6.全局使能中断( EINT)。
可以使用 CPU IER 寄存器禁用中断组。 这不会导致竞争状况, 因此不需要特殊程
序。
看完汇编继续回来。disablewatchdog中除了汇编只有一句代码。
跳转HWREG
#define HWREG(x) \
(*((volatile uint32_t *)((uintptr_t)(x))))
#define HWREG_BP(x) \
(*((volatile uint32_t *)((uintptr_t)(x))))
使用volatile修饰的uint32_t类型的指针,直接操作硬件地址,是一种更底层但是效率极高的用法。
HWREG(WD_BASE + SYSCTL_O_WDCR) = (HWREG(WD_BASE + SYSCTL_O_WDCR) & ~0x80)| (SYSCTL_WD_CHKBITS | SYSCTL_WDCR_WDDIS);
传入HWREG函数的是WD的基地址加O_WDCR的偏移地址
#define WD_BASE 0x00038E00U
#define SYSCTL_O_WDCR 0x50U // Watchdog Control Register
把SYSCTL_O_WDCR实际地址上的0x80位清零并且与上SYSCTL_WD_CHKBITS和SYSCTL_WDCR_WDDIS
static inline void
SysCtl_deviceCal(void)
{
//
// Call the PMUTrims_cal OscTrims_cal function
//
(* PMUTrims_cal)();
(* OscTrims_cal)();
}
使用两个函数指针调用了宏定义分别对电源管理和时钟进行校准。
//
// Call Flash Initialization to setup flash waitstates. This function must
// reside in RAM.
//
Flash_initModule(FLASH0CTRL_BASE, FLASH0ECC_BASE, DEVICE_FLASH_WAITSTATES);
看函数名就知道是配置关于flash的内容
//*****************************************************************************
//
// Flash_initModule
//
//*****************************************************************************
void CODE_SECTION("ramfuncs")
Flash_initModule(uint32_t ctrlBase, uint32_t eccBase, uint16_t waitstates)
{
//
// Check the arguments.
//
ASSERT(Flash_isCtrlBaseValid(ctrlBase));
ASSERT(Flash_isECCBaseValid(eccBase));
ASSERT(waitstates <= 0xFU);
//
// Set the bank fallback power mode to active.
//
Flash_setBankPowerMode(ctrlBase, FLASH_BANK, FLASH_BANK_PWR_ACTIVE);
//
// Disable cache and prefetch mechanism before changing wait states
//
Flash_disableCache(ctrlBase);
Flash_disablePrefetch(ctrlBase);
//
// Set waitstates according to frequency.
//
Flash_setWaitstates(ctrlBase, waitstates);
//
// Enable cache and prefetch mechanism to improve performance of code
// executed from flash.
//
Flash_enableCache(ctrlBase);
Flash_enablePrefetch(ctrlBase);
//
// At reset, ECC is enabled. If it is disabled by application software and
// if application again wants to enable ECC.
//
Flash_enableECC(eccBase);
//
// Force a pipeline flush to ensure that the write to the last register
// configured occurs before returning.
//
FLASH_DELAY_CONFIG;
}
修饰函数名称中有CODE_SECTION("ramfuncs")实际为#define CODE_SECTION(v) __attribute__((section(v)))的宏定义
表明这段代码定义再ram区固定块中。
通过断言判断传入参数的合理性,
设置后备电源模式为主动后备模式
禁用缓存和预取机制,然后根据频率设置等待状态,接着启用缓存和预取机制以提高从闪存执行的代码的性能。启动错误校验。
配置完成后通过flash_delay_config宏定义延迟,等待配置生效
#define FLASH_DELAY_CONFIG asm volatile(".align 2;RPTI 10,4;NOP")
时钟配置比较复杂,我们后面再看,接下来的
void Device_enableAllPeripherals(void)
{
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_DMA);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_TIMER0);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_TIMER1);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_TIMER2);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_CPUBGCRC);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_HRPWM);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_ERAD);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EPWM1);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EPWM2);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EPWM3);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EPWM4);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EPWM5);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EPWM6);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EPWM7);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EPWM8);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_ECAP1);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_ECAP2);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_ECAP3);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_HRCAP);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EQEP1);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EQEP2);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_SCIA);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_SPIA);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_SPIB);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_I2CA);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_I2CB);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_I2S);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_CANA);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_ADCA);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_ADCC);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_CMPSS1);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_CMPSS2);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_CMPSS3);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_CMPSS4);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_FSITXA);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_FSIRXA);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_LINA);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_LINB);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_PMBUSA);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_DCC0);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_DCC1);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_CLB1);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_CLB2);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_HICA);
}
使能了所有外设的时钟
static inline void ASysCtl_lockVREG(void)
{
EALLOW;
//
// Write a 1 to the lock bit in the LOCK register.
//
HWREG(ANALOGSUBSYS_BASE + ASYSCTL_O_LOCK) |= ASYSCTL_LOCK_VREGCTL;
EDIS;
}
设置了ADCLOCK寄存器的LOCK位
DEVICE_INITGPIO()解锁了所有IO口
void Device_initGPIO(void)
{
//
// Disable pin locks.
//
GPIO_unlockPortConfig(GPIO_PORT_A, 0xFFFFFFFF);
GPIO_unlockPortConfig(GPIO_PORT_B, 0xFFFFFFFF);
GPIO_unlockPortConfig(GPIO_PORT_H, 0xFFFFFFFF);
}
void
Interrupt_initModule(void)
{
//
// Disable and clear all interrupts at the CPU
//
(void)Interrupt_disableGlobal();
IER = 0x0000U;
IFR = 0x0000U;
//
// Clear all PIEIER registers
//
HWREG(PIECTRL_BASE + PIE_O_IER1) = 0U;
HWREG(PIECTRL_BASE + PIE_O_IER2) = 0U;
HWREG(PIECTRL_BASE + PIE_O_IER3) = 0U;
HWREG(PIECTRL_BASE + PIE_O_IER4) = 0U;
HWREG(PIECTRL_BASE + PIE_O_IER5) = 0U;
HWREG(PIECTRL_BASE + PIE_O_IER6) = 0U;
HWREG(PIECTRL_BASE + PIE_O_IER7) = 0U;
HWREG(PIECTRL_BASE + PIE_O_IER8) = 0U;
HWREG(PIECTRL_BASE + PIE_O_IER9) = 0U;
HWREG(PIECTRL_BASE + PIE_O_IER10) = 0U;
HWREG(PIECTRL_BASE + PIE_O_IER11) = 0U;
HWREG(PIECTRL_BASE + PIE_O_IER12) = 0U;
//
// Clear all PIEIFR registers
//
HWREG(PIECTRL_BASE + PIE_O_IFR1) = 0U;
HWREG(PIECTRL_BASE + PIE_O_IFR2) = 0U;
HWREG(PIECTRL_BASE + PIE_O_IFR3) = 0U;
HWREG(PIECTRL_BASE + PIE_O_IFR4) = 0U;
HWREG(PIECTRL_BASE + PIE_O_IFR5) = 0U;
HWREG(PIECTRL_BASE + PIE_O_IFR6) = 0U;
HWREG(PIECTRL_BASE + PIE_O_IFR7) = 0U;
HWREG(PIECTRL_BASE + PIE_O_IFR8) = 0U;
HWREG(PIECTRL_BASE + PIE_O_IFR9) = 0U;
HWREG(PIECTRL_BASE + PIE_O_IFR10) = 0U;
HWREG(PIECTRL_BASE + PIE_O_IFR11) = 0U;
HWREG(PIECTRL_BASE + PIE_O_IFR12) = 0U;
//
// Enable vector fetching from PIE block
//
HWREG(PIECTRL_BASE + PIE_O_CTRL) |= PIE_CTRL_ENPIE;
}
//*****************************************************************************
//
// Interrupt_initVectorTable
//
//*****************************************************************************
void
Interrupt_initVectorTable(void)
{
uint32_t i;
EALLOW;
//
// We skip the first three locations because they are initialized by Boot
// ROM with boot variables.
//
for(i = 3U; i < 224U; i++)
{
HWREG(PIEVECTTABLE_BASE + (4U * i)) =
(uint32_t)Interrupt_defaultHandler;
}
//
// NMI and ITRAP get their own handlers.
//
HWREG(PIEVECTTABLE_BASE + ((INT_NMI >> 16U) * 4U)) =
(uint32_t)Interrupt_nmiHandler;
EDIS;
}
中断全部清零,中断向量表也全部清零。