【简介】
我们在之前介绍了S32K146 的使用方法,S32K系列哟那个的比较多的已经是S32K3系列,我们基于S32K314 芯片先熟悉下对应的启动代码.
step1. 启动代码的第开始是关闭中断,初始化通用寄存器R0-R7为0
_start: Reset_Handler: /*****************************************************/ /* Skip normal entry point as nothing is initialized */ /*****************************************************/ cpsid i mov r0, #0 mov r1, #0 mov r2, #0 mov r3, #0 mov r4, #0 mov r5, #0 mov r6, #0 mov r7, #0
step2 使能MSCM控制的时钟信号,本段代码首先检查MSCM 的时钟状态是否开启,如果未开启则通过MC_ME(Mode Entry Module
) 的MCME_PRINT1_C0FB0_CLKEN 寄存器开启时钟
#ifndef NO_MSCM_CLOCK_INIT InitMSCMClock: /* If the MSCM clock is enabled, skip this sequence */ ldr r0, =MCME_PRTN1_COFB0_STAT ldr r1, [r0] ldr r2, =MCME_MSCM_REQ and r1, r1, r2 cmp r1, 0 bne SetVTOR /* Enable clock in PRTN1 */ ldr r0, =MCME_PRTN1_COFB0_CLKEN ldr r1, [r0] ldr r2, =MCME_MSCM_REQ orr r1, r2 str r1, [r0] /* Set PUPD field */ ldr r0, =MCME_PRTN1_PUPD ldr r1, [r0] ldr r2, =1 orr r1, r2 str r1, [r0] /* Trigger update */ ldr r0, =MCME_CTL_KEY ldr r1, =MCME_KEY str r1, [r0] ldr r1, =MCME_INV_KEY str r1, [r0] #endif /* Check MSCM clock in PRTN1 */ WaitForClock: ldr r0, =MCME_PRTN1_COFB0_STAT ldr r1, [r0] ldr r2, =MCME_MSCM_REQ and r1, r1, r2 cmp r1, 0 beq WaitForClock
MSCM 的时钟信号对应MCME 控制寄存器的bit 24 位来控制。
MSCM 包含了系统的很多关键寄存器的访问 所以要确保打开MSCM 的时钟
未开启MSCM的时钟前对应的寄存器是无法访问的
以下流程图是手册中对MC_ME 时钟配置的流程说明图,跟上述代码流程是一致的代码中未进行PUPD 的状态判断,直接等待的MSCM 的时钟状态位enable.
step3 更新中断向量表指向内存区域
SetVTOR: /* relocate vector table to RAM */ ldr r0, =VTOR_REG ldr r1, =__RAM_INTERRUPT_START str r1,[r0]
__RAM_INTERRUPT_START 的位置在link file中进行定义
step4 根据coreid 来设置core 的MSP 指针,配置好SP指针后就可以来调用C函数了
/*GetCoreID*/ ldr r0, =0x40260004 ldr r1,[r0] ldr r0, =MAIN_CORE cmp r1,r0 beq SetCore0Stack b SetCore1Stack SetCore0Stack: /* set up stack; r13 SP*/ ldr r0, =__Stack_start_c0 msr MSP, r0 b DisableSWT0 SetCore1Stack: /* set up stack; r13 SP*/ ldr r0, =__Stack_start_c1 msr MSP, r0
__Stack_start_c0/__Stack_start_c1 的定义在link 文件中进行定义
step5 对 SRAM进行初始化,来更新ECC
RamInit: /* Initialize SRAM ECC */ ldr r0, =__RAM_INIT cmp r0, 0 /* Skip if __SRAM_INIT is not set */ beq SRAM_LOOP_END ldr r1, =__INT_SRAM_START ldr r2, =__INT_SRAM_END subs r2, r1 subs r2, #1 ble SRAM_LOOP_END movs r0, 0 movs r3, 0 SRAM_LOOP: stm r1!, {r0,r3} subs r2, 8 bge SRAM_LOOP SRAM_LOOP_END:
对整个SRAM 区域进行初始化
step6 初始化ITCM来更新ECC
ITCM_Init: /* Initialize ITCM ECC */ ldr r0, =__ITCM_INIT cmp r0, 0 /* Skip if __TCM_INIT is not set */ beq ITCM_LOOP_END /* Enable TCM */ LDR r1, =CM7_ITCMCR LDR r0, [r1] LDR r2, =0x1 ORR r0, r2 STR r0, [r1] ldr r1, =__INT_ITCM_START ldr r2, =__INT_ITCM_END subs r2, r1 subs r2, #1 ble ITCM_LOOP_END movs r0, 0 movs r3, 0 ITCM_LOOP: stm r1!, {r0,r3} subs r2, #8 bge ITCM_LOOP ITCM_LOOP_END:
step7 初始化DTCM
DTCM_Init: /* Initialize DTCM ECC */ ldr r0, =__DTCM_INIT cmp r0, 0 /* Skip if __DTCM_INIT is not set */ beq DTCM_LOOP_END /* Enable TCM */ LDR r1, =CM7_DTCMCR LDR r0, [r1] LDR r2, =0x1 ORR r0, r2 STR r0, [r1] ldr r1, =__INT_DTCM_START ldr r2, =__INT_DTCM_END subs r2, r1 subs r2, #1 ble DTCM_LOOP_END movs r0, 0 movs r3, 0 DTCM_LOOP: stm r1!, {r0,r3} subs r2, #8 bge DTCM_LOOP DTCM_LOOP_END:
stsp 8 初始化DATA 段和 bss 段数据
/************************/ /* Erase ".bss Section" */ /************************/ _DATA_INIT: #ifndef RAM_DATA_INIT_ON_ALL_CORES /* If this is the primary core, initialize data and bss */ ldr r0, =0x40260004 ldr r1,[r0] ldr r0, =MAIN_CORE cmp r1,r0 beq _INIT_DATA_BSS b __SYSTEM_INIT #endif _INIT_DATA_BSS: bl init_data_bss
step9 调用SystemInit 函数进行系统初始化
/******************************************************************/ /* Autosar Guidance 10 - In the start-up code a default */ /* initialization of the MCU clock system shall be performed */ /* including global clock prescalers. */ /******************************************************************/ __SYSTEM_INIT: bl SystemInit
/*================================================================================================*/ /* * system initialization : system clock, interrupt router ... */ void SystemInit(void) { uint32 i; uint32 coreMask = 0UL; uint8 coreId = OsIf_GetCoreID(); #ifdef MPU_ENABLE uint8 index = 0U; uint8 regionNum = 0U; #endif /* MPU_ENABLE */ switch(coreId) { case CM7_0: coreMask = (1UL << MSCM_IRSPRC_M7_0_SHIFT); break; case CM7_1: #ifdef S32K324 coreMask = (1UL << MSCM_IRSPRC_M7_1_SHIFT); #endif break; default: coreMask = 0UL; break; } /* Configure MSCM to enable/disable interrupts routing to Core processor */ for (i = 0; i < MSCM_IRSPRC_COUNT; i++) { IP_MSCM->IRSPRC[i] |= coreMask; } /**************************************************************************/ /* FPU ENABLE*/ /**************************************************************************/ #ifdef ENABLE_FPU /* Enable CP10 and CP11 coprocessors */ S32_SCB->CPACR |= (S32_SCB_CPACR_CPx(10U, 3U) | S32_SCB_CPACR_CPx(11U, 3U)); ASM_KEYWORD("dsb"); ASM_KEYWORD("isb"); #endif /* ENABLE_FPU */ /**************************************************************************/ /* MPU ENABLE*/ /**************************************************************************/ #ifdef MPU_ENABLE /**************************************************************************/ /* DEFAULT MEMORY ENABLE*/ /**************************************************************************/ /* Init MPU table for memory layout*/ /* Cover all memory on device as background set all memory as strong-order and no access*/ rbar[0]=0x00000000UL; rasr[0]=0x1004003FUL; /* ITCM for cortex M7 if no set it as zero */ rbar[1]=(uint32)__INT_ITCM_START; rasr[1]=0x0104001FUL; /*Program flash which would extract from linker symbol*/ rbar[2]=(uint32)__ROM_CODE_START; rasr[2]=0x060B002BUL; /*Data flash which would extract from linker symbol*/ rbar[3]=(uint32)__ROM_DATA_START; rasr[3]=0x16050023UL; /* Device, Non-cache, Share */ /*DTCM for cortex m7 if no set it as zero*/ rbar[4]=(uint32)__INT_DTCM_START; rasr[4]=0x01040021UL; /*Ram unified section + stack*/ #if !defined(S32K344) && !defined(S32K324) rbar[5]=(uint32)__INT_SRAM_START; rasr[5]=((uint32)0x030B0001UL)|(((uint32)__RAM_CACHEABLE_SIZE - 1) << 1); #else rbar[5]=(uint32)__INT_SRAM_START; /*disable subregion 7-8*/ rasr[5]=((uint32)0x030B0001UL)|(((uint32)__RAM_CACHEABLE_SIZE - 1) << 1)|(1<<15)|(1<<14); #endif /*Ram non-cache section plus int result which is using for test report*/ rbar[6]=(uint32)__RAM_NO_CACHEABLE_START; rasr[6]= ((uint32)0x130C0001UL)|(((uint32)__RAM_NO_CACHEABLE_SIZE - 1) << 1); /*Ram shareable section*/ rbar[7]=(uint32)__RAM_SHAREABLE_START; rasr[7]=((uint32)0x130C0001UL)|(((uint32)__RAM_SHAREABLE_SIZE - 1) << 1); /* Additional configuration for peripheral device*/ /*AIPS_0*/ rbar[8]=0x40000000UL; rasr[8]=0x13050029UL; /*AIPS_1*/ rbar[9]=0x40200000UL; rasr[9]=0x13050029UL; /*AIPS_2*/ rbar[10]=0x40400000UL; rasr[10]=0x13050029UL; /*QSPI Rx*/ rbar[11]=0x67000000UL; rasr[11]=0x13050013UL; /*QSPI AHB*/ rbar[12]=0x68000000UL; rasr[12]=0x030B0035UL; /*QSPI AHB*/ rbar[13]=0xE0000000UL; rasr[13]=0x13040027UL; ASM_KEYWORD("dsb"); ASM_KEYWORD("isb"); /*Checking if cache is enable before*/ if (((((uint32)1U << (uint32)17U) & S32_SCB->CCR) != (uint32)0) || ((((uint32)1U << (uint32)16U) & S32_SCB->CCR) != (uint32)0)) { /*synchronize cache before update mpu */ sys_m7_cache_clean(); sys_m7_cache_disable(); } /* Set default memory regions */ for (index = 0U; index < 15; index++) { if ((rasr[index]&(uint32)0x1) == (uint32)0x1) { S32_MPU->RNR = regionNum; S32_MPU->RBAR = rbar[index]; S32_MPU->RASR = rasr[index]; regionNum++; } } /* Enable MPU */ S32_MPU->CTRL |= S32_MPU_CTRL_ENABLE_MASK; ASM_KEYWORD("dsb"); ASM_KEYWORD("isb"); #endif /* MPU_ENABLE */ /**************************************************************************/ /* ENABLE CACHE */ /**************************************************************************/ #if defined(D_CACHE_ENABLE) || defined(I_CACHE_ENABLE) sys_m7_cache_init(); #endif /*defined(D_CACHE_ENABLE) || defined(I_CACHE_ENABLE)*/ } /* Cache apis which are using for cache initilization, please make sure MPU is enable before calling these apis. Due to limitation of speculative access on cortex m7, MPU need to be initialized before enable cache. So if user specify -DDISABLE_MPUSTARTUP, cache will be disable in startup as well. If user want to enable cache again please call cache api after RM_init() or MPU_init() */ static INLINE void sys_m7_cache_init(void) { #ifdef D_CACHE_ENABLE uint32 ccsidr = 0U; uint32 sets = 0U; uint32 ways = 0U; /*init Data caches*/ S32_SCB->CSSELR = 0U; /* select Level 1 data cache */ ASM_KEYWORD("dsb"); ccsidr = S32_SCB->CCSIDR; sets = (uint32)(CCSIDR_SETS(ccsidr)); do { ways = (uint32)(CCSIDR_WAYS(ccsidr)); do { S32_SCB->DCISW = (((sets << SCB_DCISW_SET_Pos) & SCB_DCISW_SET_Msk) | ((ways << SCB_DCISW_WAY_Pos) & SCB_DCISW_WAY_Msk) ); ASM_KEYWORD("dsb"); } while (ways-- != 0U); } while(sets-- != 0U); ASM_KEYWORD("dsb"); S32_SCB->CCR |= (uint32)SCB_CCR_DC_Msk; /* enable D-Cache */ ASM_KEYWORD("dsb"); ASM_KEYWORD("isb"); #endif /*D_CACHE_ENABLE*/ #ifdef I_CACHE_ENABLE /*init Code caches*/ ASM_KEYWORD("dsb"); ASM_KEYWORD("isb"); S32_SCB->ICIALLU = 0UL; /* invalidate I-Cache */ ASM_KEYWORD("dsb"); ASM_KEYWORD("isb"); S32_SCB->CCR |= (uint32)SCB_CCR_IC_Msk; /* enable I-Cache */ ASM_KEYWORD("dsb"); ASM_KEYWORD("isb"); #endif /*I_CACHE_ENABLE*/ } static INLINE void sys_m7_cache_disable(void) { sys_m7_cache_clean(); S32_SCB->CCR &= ~((uint32)1U << 17U); ASM_KEYWORD("dsb"); ASM_KEYWORD("isb"); S32_SCB->CCR &= ~((uint32)1U << 16U); ASM_KEYWORD("dsb"); ASM_KEYWORD("isb"); } static INLINE void sys_m7_cache_clean(void) { #ifdef D_CACHE_ENABLE uint32 ccsidr = 0U; uint32 sets = 0U; uint32 ways = 0U; S32_SCB->CSSELR = 0U; /* select Level 1 data cache */ ASM_KEYWORD("dsb"); ccsidr = S32_SCB->CCSIDR; sets = (uint32)(CCSIDR_SETS(ccsidr)); do { ways = (uint32)(CCSIDR_WAYS(ccsidr)); do { S32_SCB->DCCISW = (((sets << 5) & (uint32)0x3FE0U) | ((ways << 30) & (uint32)0xC0000000U) ); ASM_KEYWORD("dsb"); } while (ways-- != 0U); } while(sets-- != 0U); S32_SCB->CSSELR = (uint32)((S32_SCB->CSSELR) | 1U); #endif /*D_CACHE_ENABLE*/ #ifdef I_CACHE_ENABLE S32_SCB->ICIALLU = 0UL; #endif /*I_CACHE_ENABLE*/ ASM_KEYWORD("dsb"); }
该函数会根据配置宏开启cahche 及配置MPU 属性信息等
step 10 开启中断跳转到main 函数从而完成启动
/******************************************************************/ /* Call Main Routine */ /******************************************************************/ _MAIN: cpsie i bl startup_go_to_user_mode bl main
【总结】
S32K314 启动代码流程总结
S32K314 芯片的启动代码流程从硬件复位到进入用户 main 函数,经历了一系列关键初始化步骤,确保系统从原始状态安全过渡到可运行 C 程序的环境。以下是完整流程总结:
1. 初始状态准备
关闭全局中断(cpsid i),防止启动过程中被中断干扰
初始化通用寄存器 R0-R7 为 0,确保寄存器状态可预测
2. MSCM 时钟初始化
检查 MSCM(多核心管理单元)时钟是否已使能
如未使能,通过 MC_ME 模块配置并开启 MSCM 时钟
触发时钟更新并等待时钟稳定就绪
(MSCM 是核心管理模块,必须确保其时钟正常才能访问关键寄存器)
3. 中断向量表重定位
将中断向量表从 Flash 重定位到 RAM(通过配置 VTOR 寄存器)
使用链接脚本中定义的__RAM_INTERRUPT_START作为新的向量表起始地址(提升中断响应速度,RAM 访问速度快于 Flash)
4. 栈指针 (SP) 初始化
读取核心 ID 寄存器,区分主核心 (Core0) 和从核心 (Core1)
根据核心 ID 分别设置对应的主栈指针 (MSP)
栈地址由链接脚本定义(__Stack_start_c0和__Stack_start_c1)
5. 内存初始化
SRAM 初始化:通过写入 0 值初始化整个 SRAM 区域,激活 ECC 功能
ITCM 初始化:使能指令紧密耦合内存,初始化其 ECC
DTCM 初始化:使能数据紧密耦合内存,初始化其 ECC(ECC 初始化可防止未初始化内存导致的错误检测)
6. 数据段初始化
仅主核心执行数据段初始化(避免多核重复操作)
初始化.data段:将已初始化的全局变量从 Flash 复制到 RAM
初始化.bss段:将未初始化的全局变量清零
7. 系统级初始化(SystemInit 函数)
配置 MSCM 中断路由,使能中断向当前核心的分发
如使能 FPU,配置 CP10/CP11 协处理器并同步
如使能 MPU,配置内存保护区域(包括 ITCM、DTCM、SRAM、Flash 和外设区域)
初始化并使能指令缓存 (I-Cache) 和数据缓存 (D-Cache)
8. 进入用户程序
开启全局中断(cpsie i)
切换到用户模式
跳转到 main 函数,完成启动流程