当前位置: 首页 > 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.dtcms.com/a/328531.html

相关文章:

  • redis的过期策略和定时器
  • 支持任意 MCP 协议的客户端
  • SQL180 每类试卷得分前3名
  • Mybatis源码解读-Plugin插件源码
  • (C++)继承全解析及运用
  • Labelme从安装到标注:零基础完整指南
  • MySQL基础面试
  • Springboot整合Thrift
  • 移动端网页调试实战,键盘弹出与视口错位问题的定位与优化
  • 汉高携手SAP推出AI驱动的退换货与争议管理解决方案
  • 赛灵思ZYNQ官方文档UG585自学翻译笔记:UART Controller,通用异步收发传输器控制器
  • Vue接口平台十三——测试记录
  • Ubuntu 全盘备份
  • 九尾狐未来机械晶核技术
  • k3s部署
  • 电脑硬件详解
  • ZYNQ AXI-GPIO学习——ZYNQ学习笔记8
  • 学习游制作记录(背包UI以及各种物品的存储)8.12
  • kafka 消费者组的概念是什么?它是如何实现消息的点对点和发布/订阅模式?
  • Supabase快速入门与实战指南
  • LangChain 入门学习
  • Spring AI Alibaba - 聊天机器人快速上手
  • SpringAI 使用通义千问进行聊天对话开发
  • 考研复习-计算机组成原理-第五章-CPU
  • [NoC]Outstanding和Credit的概念详解
  • Fluent Bit 日志合并正则表达式(上)
  • Nginx 高级配置
  • Python训练Day41
  • 基于PAI-ChatLearn的GSPO强化学习实践
  • LLM - 搭建 Grounded SAM 2 模型的视觉检测与分割服务 API