625|1

14

帖子

0

TA的资源

一粒金砂(中级)

楼主
 

【中科昊芯HXS320F28025C】系统初始化函数学习和熟悉库函数风格 [复制链接]

 
本帖最后由 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_CHKBITSSYSCTL_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;
}

中断全部清零,中断向量表也全部清零。

最新回复

使用静态+内联修饰函数,确保代码只提供接口,不能修改。内联修饰优化效率。 他这代码写得非常好呀。   详情 回复 发表于 2024-7-19 08:31
点赞 关注
 
 

回复
举报

6968

帖子

11

TA的资源

版主

沙发
 

使用静态+内联修饰函数,确保代码只提供接口,不能修改。内联修饰优化效率。

他这代码写得非常好呀。

 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/8 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表