MCU外设初始化:为什么参数配置必须优先于使能

在微控制器领域,初始化参数配置阶段至关重要。此时,虽无电源驱动,但微控制器在使能信号到来前,借初始化参数配置这一精细步骤,开启关键准备进程。初始化参数配置如同物理坐标锚定、逻辑指令部署、内在秩序预设,各参数像深埋沃土的种子,坐标、朝向、深度经精密计算,为未来指令运行奠定基础。

下面以国科安芯的MCU芯片AS32A601为例,详细展示下MCU这一严格的设计特性:

‌1. ‌外设检测阶段‌:MCU会尝试检测外设可用性,然后才开始执行用户代码。

  1. 时钟树配置‌:系统时钟(CK_SYS)、AHB、APB等总线时钟必须在其他外设初始化前完成配置。

为什么参数要在使能前配置?

避免电平跳变‌:

  • GPIO复用模式下,若先使能外设再配置复用选择器,会导致短暂电平变化。
  • 普通输出IO默认输出低电平,若先使能再设置高电平,会出现短暂低脉冲。

‌ 防止硬件冲突‌:

  • 时钟使能必须在外设初始化之前,否则会导致外设无法正常工作。
  • 寄存器默认值可能不符合应用需求,直接使能可能导致意外行为。

确保稳定状态‌:

  • 外设使能前需要建立正确的时钟源、中断优先级等基础环境。
  • 参数配置需要一定时间生效,立即使能可能导致功能异常。

时钟配置

通过阅读芯片手册,确认好项目所需外设所在时钟
2. 确保时钟最先配置,再去配置外设

|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 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初始化

  1. 开始GPIO对应时钟

  2. 如果是复用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
  1. 最后使能外设
  2. 配置外设参数
  3. 配置GPIO先配置复用
  4. 开启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系统的稳定性和可靠性。

相关推荐
点灯小铭1 分钟前
基于K210的车牌识别设计
单片机·毕业设计·课程设计
huluang18 分钟前
中国网络安全处罚综合研究报告(2020-2025)
网络·安全·web安全
厦门辰迈智慧科技有限公司21 分钟前
现代化水库运行管理矩阵建设的要点
运维·网络·物联网·线性代数·安全·矩阵·监测
yy里2 小时前
H5性能优化实践
前端·性能优化
二川bro3 小时前
第十篇:3D模型性能优化:从入门到实践
3d·性能优化
我怕是好3 小时前
学习STM32 脉冲计数实验
stm32·嵌入式硬件·学习
总结所学3 小时前
电路板的GND与外壳地EARTH通过电容电阻相连
单片机·嵌入式硬件
居7然4 小时前
MCP协议更新:从HTTP+SSE到Streamable HTTP,大模型通信的进化之路
网络·网络协议·http
音视频牛哥4 小时前
从感知到执行:人形机器人低延迟视频传输与多模态同步方案解析
网络·人工智能·深度学习·大牛直播sdk·机器人视觉·人形机器人·智能机器人