云计算百科
云计算领域专业知识百科平台

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

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

下面以国科安芯的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系统的稳定性和可靠性。

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » MCU外设初始化:为什么参数配置必须优先于使能
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!