在微控制器領域,初始化參數配置階段至關重要。此時,雖無電源驅動,但微控制器在使能信號到來前,借初始化參數配置這一精細步驟,開啟關鍵準備進程。初始化參數配置如同物理坐標錨定、邏輯指令部署、內在秩序預設,各參數像深埋沃土的種子,坐標、朝向、深度經精密計算,為未來指令運行奠定基礎。
下面以國科安芯的MCU芯片AS32A601為例,詳細展示下MCU這一嚴格的設計特性:
?1. ?外設檢測階段?:MCU會嘗試檢測外設可用性,然后才開始執行用戶代碼。
2. 時鐘樹配置?:系統時鐘(CK_SYS)、AHB、APB等總線時鐘必須在其他外設初始化前完成配置。
為什么參數要在使能前配置?
避免電平跳變?:
- GPIO復用模式下,若先使能外設再配置復用選擇器,會導致短暫電平變化。
- 普通輸出IO默認輸出低電平,若先使能再設置高電平,會出現短暫低脈沖。
? 防止硬件沖突?:
- 時鐘使能必須在外設初始化之前,否則會導致外設無法正常工作。
- 寄存器默認值可能不符合應用需求,直接使能可能導致意外行為。
確保穩定狀態?:
- 外設使能前需要建立正確的時鐘源、中斷優先級等基礎環境。
- 參數配置需要一定時間生效,立即使能可能導致功能異常。
時鐘配置
- 通過閱讀芯片手冊,確認好項目所需外設所在時鐘
- 確保時鐘最先配置,再去配置外設
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | void?Systemclock_Init() { ????//注意:此處需要開啟系統總線級的時鐘配置,具體外設時鐘配置可在各模塊初始化函數中具體開啟,具體請參考時鐘樹或者下圖注釋 ????//????? 1. 使用串口時,由于串口掛在APB0總線下,需要在此處開啟AXIBUS3時鐘、AXI4TOAPB0時鐘以及APBBUS0時鐘。 ????//????? 2. 使用延時函數時,需要開啟CLINT時鐘 ????//????? 3. 使用eflash、qspi時,需要開啟AXIBUS3時鐘、AXILITEBUS2時鐘 ????? ????/* AXIBus3 clock operation Guide*/ ????AXIBUS3_CLK_ENABLE(); ????AXI4TOAPB0_CLK_ENABLE(); ????APBBUS0_CLK_ENABLE(); ????AXI4TOAPB1_CLK_ENABLE(); ????APBBUS1_CLK_ENABLE(); ????AXILITEBUS1_CLK_ENABLE(); ????AXILITEBUS2_CLK_ENABLE(); ????EFLASH_CLK_ENABLE();?? ????PLIC_CLK_ENABLE(); ????CLINT_CLK_ENABLE(); ????? ????SMU_PLLInitTypeDef SMU_PLLInitStruct; ????SMU_ClockInitTypeDef SMU_ClockInitStruct; ??? ????/* Set PLL parameters values */ ????SMU_PLLInitStruct.OscillatorType = SMU_OSCILLATORTYPE_OSC; ????SMU_PLLInitStruct.FIRCOscState = DISABLE; ????SMU_PLLInitStruct.FIRCCalibrationValue = 0x00; ????SMU_PLLInitStruct.PLLConfig.PLLState = ENABLE; ????SMU_PLLInitStruct.PLLConfig.PLLSource = SMU_PLLCLK_OSC; ????SMU_PLLInitStruct.PLLConfig.PLLDivR = 0x01; ????SMU_PLLInitStruct.PLLConfig.PLLDivQ = 0x01; ????SMU_PLLInitStruct.PLLConfig.PLLDivN = 0x14; ????SMU_PLLInitStruct.PLLConfig.PLLDivF = 0xA0; ????SMU_PLLInit(&SMU_PLLInitStruct); ????? ????/* Ensure that the EFLASH is consistent with the system clock */ ????FLASH_UnlockCtrl(); ????FLASH_SetCLKFreq(0xA0); ????? ????/* Set System Clock parameters values */ ????SMU_ClockInitStruct.SYSCLKSelect = SMU_SYSCLK_PLL; ????SMU_ClockInitStruct.AXI4Bus3CLKDiv = AXI4Bus3CLKDiv1; ????SMU_ClockInitStruct.APBBus0CLKDiv = APBBus0CLKDiv1; ????SMU_ClockInitStruct.APBBus1CLKDiv = APBBus1CLKDiv8; ????SMU_ClockInitStruct.CANX2CLKDiv = CANX2CLKDiv1; ??? ????SMU_ClockInit(&SMU_ClockInitStruct); ????? ????EFLASH_CLK_UPDATE_ENABLE(); ????EFLASH_CLK_UPDATE_DISABLE(); ? ????FLASH_LockCtrl(); ????? ????/* Get System Clock values */ ????SMU_GetClocksFreq(&SMU_ClocksStruct); } |
GPIO初始化
開始GPIO對應時鐘
如果是復用IO,首先要配置復用
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | void?GPIO_Init(void) { ???GPIO_InitTypeDef? GPIO_InitStructure; ???/*開啟GPIO所在時鐘*/ ???GPIOD_CLK_ENABLE(); ???GPIOG_CLK_ENABLE(); ???GPIOF_CLK_ENABLE(); ???/* Set GPIO multiplex mapping */ ???GPIO_PinAFConfig(GPIOD, GPIO_PinSource13, GPIO_AF_CAN1);//先開啟復用模式 ???GPIO_PinAFConfig(GPIOD, GPIO_PinSource14, GPIO_AF_CAN1); ?? ???/* GPIO Configure */ ???GPIO_StructInit(&GPIO_InitStructure); ???GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; ???GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; ???GPIO_InitStructure.GPIO_OType = GPIO_Out_PP; ???GPIO_InitStructure.GPIO_OStrength = GPIO_OStrength_9mA; ??? ???GPIO_Init(GPIOD, &GPIO_InitStructure); ???GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14; ???GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; ???GPIO_InitStructure.GPIO_IType = GPIO_IPU; ???GPIO_InitStructure.GPIO_OStrength = GPIO_OStrength_9mA; ???GPIO_Init(GPIOD, &GPIO_InitStructure); ???? ????/* GPIOB Configure */ ????GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_14 | GPIO_Pin_15; ????GPIO_InitStructure.GPIO_Mode????? = GPIO_Mode_OUT; ????GPIO_InitStructure.GPIO_OType???? = GPIO_Out_PP; ????GPIO_InitStructure.GPIO_OStrength = GPIO_OStrength_9mA; ????? ????GPIO_Init(GPIOG, &GPIO_InitStructure); ??? ????/* GPIOB Configure */ ????GPIO_InitStructure.GPIO_Pin?????? = GPIO_Pin_1; ????GPIO_InitStructure.GPIO_Mode????? = GPIO_Mode_IN; ????GPIO_InitStructure.GPIO_IType???? = GPIO_IPU; ????GPIO_InitStructure.GPIO_OType???? = GPIO_Out_PP; ????GPIO_InitStructure.GPIO_OStrength = GPIO_OStrength_9mA; ????? ????GPIO_Init(GPIOF, &GPIO_InitStructure);? } |
部分外設參數配置
Usart
- 最后使能外設
- 配置外設參數
- 配置GPIO先配置復用
- 開啟GPIO和外設時鐘
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | void?User_Print_Init(uint32_t BaudRate) { ????USART_InitTypeDef USART_InitStructure; ????GPIO_InitTypeDef? GPIO_InitStructure; ????PLIC_InitTypeDef PLIC_InitStructure; ????/*GOPI/外設時鐘使能*/ ????GPIOD_CLK_ENABLE(); ????USART0_CLK_ENABLE(); ????/* Set GPIO multiplex mapping */ ????GPIO_PinAFConfig(GPIOD, GPIO_PinSource8, GPIO_AF_USART0);?????? /* USART0_TX */?開啟復用模式 ????GPIO_PinAFConfig(GPIOD, GPIO_PinSource9, GPIO_AF_USART0);?????? /* USART0_RX */ ????/* GPIO Configure */ ????GPIO_InitStructure.GPIO_Pin?????? = GPIO_Pin_8;???????????? ????GPIO_InitStructure.GPIO_Mode????? = GPIO_Mode_OUT; ????GPIO_InitStructure.GPIO_OType???? = GPIO_Out_PP; ????GPIO_InitStructure.GPIO_OStrength = GPIO_OStrength_4_5mA; ????GPIO_Init(GPIOD, &GPIO_InitStructure); ????GPIO_InitStructure.GPIO_Pin?????? = GPIO_Pin_9;???????????? ????GPIO_InitStructure.GPIO_Mode????? = GPIO_Mode_IN; ????GPIO_InitStructure.GPIO_IType???? = GPIO_IN_FLOATING; ????GPIO_InitStructure.GPIO_OStrength = GPIO_OStrength_4_5mA; ????GPIO_Init(GPIOD, &GPIO_InitStructure); ????/*防止配置沖突*/ ????USART_DeInit(USART0); ????USART_StructInit(&USART_InitStructure); ? ????/* Initializes the USART0 */ ????USART_InitStructure.USART_BaudRate???? = BaudRate; ????USART_InitStructure.USART_WordLength?? = USART_WordLength_8b; ????USART_InitStructure.USART_StopBits???? = USART_StopBits_1; ????USART_InitStructure.USART_Parity?????? = USART_Parity_No; ????USART_InitStructure.USART_Mode???????? = USART_Mode_Rx | USART_Mode_Tx; ????USART_InitStructure.USART_OverSampling = USART_OverSampling_16; USART_Init(USART0, &USART_InitStructure); /*配置好相關參數后,使能USART*/ ????USART_Cmd(USART0, ENABLE); ????USART_ITConfig(USART0, USART_IT_RXNE, ENABLE); ????? ?????/* Configer the USART0 interrupt */ ????PLIC_InitStructure.PLIC_IRQChannel = USART0_IRQn; ????PLIC_InitStructure.PLIC_IRQPriority = 1; ????PLIC_InitStructure.PLIC_IRQChannelCmd = ENABLE; ????PLIC_Init(&PLIC_InitStructure); } |
CAN
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | void?User_CANFD3_Init() { ????CANFD3_CLK_ENABLE(); ????GPIOC_CLK_ENABLE(); ???? ????GPIO_InitTypeDef? GPIO_InitStructure; ????CANFD_InitTypeDef CANFD_InitStructure; ????PLIC_InitTypeDef? PLIC_InitStructure; ? ????/* Set GPIO multiplex mapping */ ????GPIO_PinAFConfig(GPIOC, GPIO_PinSource7, GPIO_AF_CAN3); ????GPIO_PinAFConfig(GPIOC, GPIO_PinSource8, GPIO_AF_CAN3); ? ????/* GPIO Configure */ ????GPIO_StructInit(&GPIO_InitStructure); ????GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; ????GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; ????GPIO_InitStructure.GPIO_OType = GPIO_Out_PP; ????GPIO_InitStructure.GPIO_OStrength = GPIO_OStrength_18mA; ????? ????GPIO_Init(GPIOC, &GPIO_InitStructure); ????GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; ????GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; ????GPIO_InitStructure.GPIO_IType = GPIO_IPU; ????GPIO_InitStructure.GPIO_OStrength = GPIO_OStrength_18mA; ????GPIO_Init(GPIOC, &GPIO_InitStructure); ????? ????/* Initializes the CANFD1 */ ????/* Arbitration Phase (Nominal) Baud Rate 500KHz */ ????/* Data Phase Baud Rate 2MHz */ ????CANFD_StructInit(&CANFD_InitStructure); ????CANFD_InitStructure.CANFD_SRR = CANFD_SRR_RESET; ????CANFD_InitStructure.CANFD_APBRPR = CANFD_APBRPR_10tp; ????CANFD_InitStructure.CANFD_APBTR_APTS1 = CANFD_APBTR_TS1_11tp; ????CANFD_InitStructure.CANFD_APBTR_APTS2 = CANFD_APBTR_TS2_4tp; ????CANFD_InitStructure.CANFD_APBTR_APSJW = CANFD_APBTR_SJW_2tp; ????? ????CANFD_InitStructure.CANFD_DPBRPR = CANFD_DPBRPR_2tp; ????CANFD_InitStructure.CANFD_DPBTR_DPTS1 = CANFD_DPBTR_TS1_7tp; ????CANFD_InitStructure.CANFD_DPBTR_DPTS2 = CANFD_DPBTR_TS2_2tp; ????CANFD_InitStructure.CANFD_DPBTR_DPSJW = CANFD_DPBTR_SJW_2tp; ????CANFD_Init(CANFD3, &CANFD_InitStructure); ????????? ????/* CANFD receive filter configure */ ????CANFD_FilterInit(CANFD3, TB0, 0xFFE00000, 0X62E00000);??????? ? ????CANFD_AutoRetransConfig(CANFD3,ENABLE); ????/* Enable new message received interrupt */ ????CANFD_ITConfig(CANFD3, CANFD_IT_ERXOK, ENABLE); ????/* CANFD Enable */ ????CANFD_Enable(CANFD3); ????? ????PLIC_StructInit(&PLIC_InitStructure); ? ????/* Configer the CANFD1 interrupt */ ????PLIC_InitStructure.PLIC_IRQChannel = CANFD3_IRQn; ????PLIC_InitStructure.PLIC_IRQPriority = 2; ????PLIC_InitStructure.PLIC_IRQChannelCmd = ENABLE; ????PLIC_Init(&PLIC_InitStructure); ????CANFD_ClearITPendingBit(CANFD3, CANFD_CLEAR_ALL); } |
通過遵循"參數配置在先,外設使能在后"的原則,并采用結構化初始化流程,可以顯著提高MCU系統的穩定性和可靠性。