当前位置: 首页 > news >正文

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

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

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

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

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

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

避免电平跳变‌:

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

‌ 防止硬件冲突‌:

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

确保稳定状态‌:

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

时钟配置

  1. 通过阅读芯片手册,确认好项目所需外设所在时钟
  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系统的稳定性和可靠性。

http://www.lryc.cn/news/618584.html

相关文章:

  • Ceph的FileStore存储引擎详解
  • 如何提升需求分析能力
  • NLP—词向量转换评论学习项目分析
  • 【SpringBoot】05 容器功能 - SpringBoot底层注解的应用与实战 - @Configuration + @Bean
  • IIS Express中可以同时加载并使用.net4.0和.NET 2.0的 DLL
  • 面试八股之从jvm层面深入解析Java中的synchronized关键字
  • 使用pyqt5实现可勾选的测试用例界面
  • MM DEMO-2025 | 北航新融合LLM与多模态交互的无人机导航系统!AirStar,智能空中助手等你来体验
  • 前端/在vscode中创建Vue3项目
  • NoC设计中Router Table的作用
  • Day05 店铺营业状态设置 Redis
  • 【C++】迭代器失效问题
  • THCV215一种高速视频数据收发器,采用低电压差分信号(LVDS)技术支持高速串行数据传输,支持1080p/60Hz高分辨率传输
  • 软考备考(三)
  • 2-1〔O҉S҉C҉P҉ ◈ 研记〕❘ 漏洞扫描▸理论基础与NSE脚本
  • 26 届秋招建议指南
  • Git与CI/CD相关知识点总结
  • [激光原理与应用-251]:理论 - 几何光学 - 长焦与短焦的比较
  • k8s-scheduler 解析
  • 【Java项目与数据库、Maven的关系详解】
  • 正向传播与反向传播(神经网络思维的逻辑回归)
  • Gradient Descent for Logistic Regression|逻辑回归梯度下降
  • B站 韩顺平 笔记 (Day 16)
  • 微软发布GPT-5赋能的Copilot:重构办公场景的智能革命
  • MODBUS RTU协议:工业物联网的“普通话“(Android开发实战指南)
  • C++ Rust与Go
  • LeetCode算法领域经典入门题目之“Two Sum”问题
  • Springboot3多数据源案例
  • Springboot注册过滤器的三种方式(Order 排序)
  • 亚马逊后台功能风险解构:“清除并替换库存” 的致命陷阱与全链路防控策略