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系统的稳定性和可靠性。

相关推荐
CC呢3 分钟前
基于单片机智能家居语音控制系统
单片机·嵌入式硬件·智能家居·单片机设计
耐达讯通信技术14 分钟前
“乾坤大挪移”:耐达讯自动化RS485转Profinet解锁HMI新乾坤
运维·网络·物联网·自动化·信息与通信
耐达讯通信技术19 分钟前
惊爆!耐达讯自动化RS485转Profinet,电机连接的“逆天神器”?
运维·网络·人工智能·科技·网络协议·自动化
MingYue_SSS26 分钟前
键盘上面有F3,四,R,F,V,按下没有反应,维修记录
嵌入式硬件·计算机外设·解决办法
二向箔reverse27 分钟前
从传统CNN到残差网络:用PyTorch实现更强大的图像分类模型
网络·pytorch·cnn
DemonAvenger1 小时前
从零到精通:数据库连接池的设计、优化与实战经验分享
数据库·sql·性能优化
JJ1M82 小时前
http问题汇总
网络·网络协议·http
Vae_Mars2 小时前
C语言中的运算符
数据库·单片机·mongodb
金色光环2 小时前
野火STM32Modbus主机读取寄存器/线圈失败(三)-尝试将存贮事件的地方改成数组(非必要解决方案)(附源码)
stm32·单片机·嵌入式硬件
心想事成的幸运大王3 小时前
计算机网络模型入门指南:分层原理与各层作用
网络·计算机网络