0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

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

安芯 ? 来源:jf_29981791 ? 作者:jf_29981791 ? 2025-08-13 10:38 ? 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

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

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

  1. 外设检测阶段:MCU会尝试检测外设可用性,然后才开始执行用户代码。
  2. 时钟树配置:系统时钟(CK_SYS)、AHB、APB等总线时钟必须在其他外设初始化前完成配置。

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

避免电平跳变:

① GPIO复用模式下,若先使能外设再配置复用选择器,会导致短暂电平变化。

② 普通输出IO默认输出低电平,若先使能再设置高电平,会出现短暂低脉冲。

防止硬件冲突:

① 时钟使能必须在外设初始化之前,否则会导致外设无法正常工作。

寄存器默认值可能不符合应用需求,直接使能可能导致意外行为。

确保稳定状态:

① 外设使能前需要建立正确的时钟源、中断优先级等基础环境。

② 参数配置需要一定时间生效,立即使能可能导致功能异常。

  1. 时钟配置

i. 通过阅读芯片手册,确认好项目所需外设所在时钟

ii. 确保时钟最先配置,再去配置外设

**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);

}
  1. GPIO初始化

i. 开始GPIO对应时钟

ii. 如果是复用IO,首先要配置复用

**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);  

}
  1. 部分外设参数配置

a) Usart

i. 开启GPIO和外设时钟

ii. 配置GPIO先配置复用

iii. 配置外设参数

iv. 最后使能外设

**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);

}

b) CAN

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

审核编辑 黄宇

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • mcu
    mcu
    +关注

    关注

    146

    文章

    18074

    浏览量

    370876
  • 参数
    +关注

    关注

    11

    文章

    1868

    浏览量

    33262
收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    定义IO初始化结构体

    由上述IOPORT相关功能的枚举类型我们可以知道,在对IOPORT模块进行初始化时需要根据情况配置它们。因此我们定义一个IOPORT初始化的结构体类型IOPORT_Init_t,它的成员包括了由上述所有枚举类型所声明的变量,因此
    的头像 发表于 07-16 16:26 ?703次阅读

    IM 系列设备过载保护机制下界面初始化中断的底层逻辑与解决方案

    一、过载保护机制与界面初始化的关联基础 IM 系列设备的过载保护机制是保障设备安全运行的核心功能,其通过传感器实时采集设备运行参数,如电流、电压、温度、系统资源占用率等。一旦这些参数超出预设阈值
    的头像 发表于 06-27 09:58 ?143次阅读

    stm32cubumx使用1.28.0固件包无法初始化fsmc怎么解决?

    在使用CUBEMX配置fsmc驱动norflash时,勾选写使选项,在初始化fsmc函数中,程序会进入void Error_Handler(void)导致死机,而这个情况在1.25.
    发表于 06-10 07:42

    stm32cubumx使用1.28.0固件包无法初始化fsmc怎么解决?

    在使用CUBEMX配置fsmc驱动norflash时,勾选写使选项,在初始化fsmc函数中,程序会进入void Error_Handler(void)导致死机,而这个情况在1.25.
    发表于 06-06 07:16

    stm32cubumx使用1.28.0固件包无法初始化fsmc怎么解决?

    在使用CUBEMX配置fsmc驱动norflash时,勾选写使选项,在初始化fsmc函数中,程序会进入void Error_Handler(void)导致死机,而这个情况在1.25.
    发表于 04-27 08:15

    STM32CubeMX用于STM32配置初始化C代码生成

    电子发烧友网站提供《STM32CubeMX用于STM32配置初始化C代码生成.pdf》资料免费下载
    发表于 02-26 17:32 ?677次下载

    初始化AFE4400的时候,哪些控制字是必须最先写的?

    想使用AFE 4400,但是遇到了一些问题: 在初始化AFE4400的时候,哪些控制字是必须最先写的?初始化AFE4400之前,建立SPI通讯时,CPU出送出的信号是正确的,但是AFE4400没有返回的信号,是怎么回事? 欢迎
    发表于 02-08 07:49

    ADS1259初始化程序必须执行两次才能够初始化成功,为什么?

    最近在调试ADS1259这个片子,发现初始化程序必须执行两次才能够初始化成功,然后读出来的CONFIG0寄存器的最高位是“0”(官方文档上是“1”),不知道是什么原因,求TI工程师解答呀!
    发表于 01-10 12:41

    STM32F407 MCU使用SD NAND?不断电初始化失效解决方案

    STM32F407微控制器单元(MCU)与SD NAND的结合提供了强大的存储解决方案。然而,不断电初始化失效问题可能会导致系统稳定性和数据完整性受损。我们将STM32F407与SD NAND集成时可能遇到的初始化问题,并提供专
    的头像 发表于 12-11 10:51 ?1063次阅读
    STM32F407 <b class='flag-5'>MCU</b>使用SD NAND?不断电<b class='flag-5'>初始化</b>失效解决方案

    segger编译器初始化问题

    的图; 2.第二张图是该变量在文件中的所有操作,第一行是初始化,该行代码在初始化部分最后一个,执行完就是主循环了; 3.第2,3行也是对变量的赋值,在主循环中; 4.第4行已注释; 5.第6行是对变量
    发表于 12-09 18:06

    DDC264第一次执行初始化,DOUT无输出的原因?怎么解决?

    得到正确的回读信号。目前想到的是CLK信号不连续问题。但我为了能不手动上电模拟重新上电过程,每次初始化都会关掉CLK并重新激活,且在CLK激活500us后才开始后面的复位等操作。 重要参数:CLK
    发表于 11-19 06:32

    请问LMX2595配置时如何进行初始化

    您好,查阅手册说初始化按照1.r0的rest置为1;2.r0的reset置为1;3.按照寄存器表格配置寄存器;4.fcal_en置为1的顺序来初始化。请问在第三步中,按照寄存器表配置
    发表于 11-12 06:51

    基于旋转平移解耦框架的视觉惯性初始化方法

    精确和鲁棒的初始化对于视觉惯性里程计(VIO)至关重要,因为不良的初始化会严重降低姿态精度。
    的头像 发表于 11-01 10:16 ?1047次阅读
    基于旋转平移解耦框架的视觉惯性<b class='flag-5'>初始化</b>方法

    TMS320C6000 McBSP初始化

    电子发烧友网站提供《TMS320C6000 McBSP初始化.pdf》资料免费下载
    发表于 10-26 10:10 ?1次下载
    TMS320C6000 McBSP<b class='flag-5'>初始化</b>

    如何在i.MX RT微控制器上初始化LWIP协议栈

    在i.MX RT微控制器上初始化LWIP协议栈是一个复杂但有趣的过程,它涉及多个步骤和关键组件的配置.
    的头像 发表于 10-12 11:48 ?930次阅读
    如何在i.MX RT微控制器上<b class='flag-5'>初始化</b>LWIP协议栈