IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> F460启动过程分析2-f460启动分析和时钟配置 -> 正文阅读

[嵌入式]F460启动过程分析2-f460启动分析和时钟配置

华大HC32f460启动分析和时钟配置

目录

华大HC32f460启动分析和时钟配置

软件环境

1. 启动过程

1.1 第一步:读取地址0x400上的内容

1.2 第二步:复位和系统时钟配置

1.3 第三步:进入用户程序main函数

2. 用户时钟配置分析

3. 调试问题:

?3.1 error: #223-D: function "BSP_CLK_Init" declared implicitly

3.2 error: ?#20: identifier "stc_clk_sysclk_cfg_t" is undefined

3.3 error: ?#254: type name is not allowed

3.5 error: ?#268: declaration may not appear after executable statement in block

3.6 编译通过;


软件环境

系统:win10
sdk版本:hc32f460_ddl_Rev2.0.0
数据手册版本:HC32F460系列用户手册 Rev1.21.pdf
ide:keil5
开发板:https://item.taobao.com/item.htm?spm=a2oq0.12575281.0.0.50111debhMzSwz&ft=t&id=660179379335https://item.taobao.com/item.htm?spm=a2oq0.12575281.0.0.50111debhMzSwz&ft=t&id=660179379335
时间:2022


1. 启动过程

1.1 第一步:读取地址0x400上的内容

数据手册中写道如下:

在这里插入图片描述

我们要注意两个地方:

  1. 复位解除后执行,这就说明,这个读flash的0x400地址是要优于程序的,也就是要在程序启动前执行。

  2. 由硬件电路读取,这就说明,这个读取的位置无法人为控制,就是0x400,我们只能在程序下载的时候将信息写道0x400开始的位置。

这个0x400配置了很有用的东西,其中就有看门狗,其实stm32的看门狗一直有一个缺陷,那就是若在芯片启动到main函数执行这个时间发生了跑飞,那么程序就没办法重启,就死机了,而hc32避免了这个问题,可以在复位解除的时候直接配上看门狗,提高了系统的稳定性。至于其他功能,请自行查阅用户手册。

1.2 第二步:复位和系统时钟配置

这段代码在汇编中执行,也就是.s文件,这个与传统cortex-m的芯片一样,都是执行reset_handler,配置系统时钟systeninit,在执行__main,最后跳到用户函数main,因为和传统stm32的一样,这个不展开细讨论。

要注意这个配置系统时钟systeninit往往使用的是芯片内部的高速时钟,这个配置系统时钟函数由sdk提供,不建议直接在这一步修改为外部时钟(不要随意修改sdk的东西),所以等到执行用户程序的时候需要重新配置到外部高速时钟。

同时要注意在执行配置系统时钟systeninit函数,以及之前这段时间,由于没有时钟配置,所以使用的是内部高速时钟直连的方式驱动的,所以那段程序执行是很慢的。

在这个.s文件,当看到那些中断号的时候可能会很怪异,当从stm32过来的人都会有错觉,把中断号写成序号IRQ001_Handler、002的是为了啥,这是因为华大的中断是很灵活的,需要在程序配置中断的时候为某个中断事件绑定一个中断号还有一个回调函数,这是为了解决入中断在判断的问题:如在stm32中,当我们同时开启串口接收中断和发送中断,这时候两个中断发生会进入一个中断函数,然后在这个中断函数里面加if来判断串口究竟是的那个中断发生了,而华大可以将每个事件都绑一个中断号,这样串口接收中断,发送中断就会进入不一样的中断函数。

1.3 第三步:进入用户程序main函数

进入main函数,即进入了用户自己的程序,这个时候首先要重新配置时钟,因为内部高速时钟往往不准,易受干扰,配置函数需要对照mcu的时钟系统框图来书写,感谢的是官网提供的官方评估板(EVB-HC32F460)软件包中写了一个时钟配置函数void BSP_CLK_Init(void),对照现成的改,就容易的多了。下面我们就对照着这个函数和时钟系统框图来分析一下。

2. 用户时钟配置分析

在官网提供的官方评估板(EVB-HC32F460)软件包中,ev_hc32f460_lqfp100_v2.c 文件里提供了一个利用外部高速晶振配置到200MHZ的方法函数,下面我们就对照分析一下配置的过程,配置时钟程序如下:
?

//华大初始化时钟为200MHZ
void BSP_CLK_Init(void)
{
    stc_clk_sysclk_cfg_t    stcSysClkCfg;
    stc_clk_xtal_cfg_t      stcXtalCfg;
    stc_clk_mpll_cfg_t      stcMpllCfg;
    stc_sram_config_t       stcSramConfig;
    
    MEM_ZERO_STRUCT(stcSysClkCfg);
    MEM_ZERO_STRUCT(stcXtalCfg);
    MEM_ZERO_STRUCT(stcMpllCfg);
    MEM_ZERO_STRUCT(stcSramConfig);

    /* Set bus clk div. */
    stcSysClkCfg.enHclkDiv  = ClkSysclkDiv1; //hclk的时钟来之分频器的1分频
    stcSysClkCfg.enExclkDiv = ClkSysclkDiv2; //exclk的时钟来之分频器的2分频
    stcSysClkCfg.enPclk0Div = ClkSysclkDiv1; //Pclk0的时钟来自分频器的1分频
    stcSysClkCfg.enPclk1Div = ClkSysclkDiv2; //Pclk1的时钟来自分频器的2分频
    stcSysClkCfg.enPclk2Div = ClkSysclkDiv4; //Pclk2的时钟来自分频器的4分频
    stcSysClkCfg.enPclk3Div = ClkSysclkDiv4; //Pclk3的时钟来自分频器的4分频
    stcSysClkCfg.enPclk4Div = ClkSysclkDiv2; //Pclk4的时钟来自分频器的2分频
    CLK_SysClkConfig(&stcSysClkCfg);

    /* Config Xtal and Enable Xtal */
    stcXtalCfg.enMode = ClkXtalModeOsc;
    stcXtalCfg.enDrv = ClkXtalLowDrv;
    stcXtalCfg.enFastStartup = Enable;
    CLK_XtalConfig(&stcXtalCfg);
    CLK_XtalCmd(Enable);

    /* sram init include read/write wait cycle setting */
    stcSramConfig.u8SramIdx = Sram12Idx | Sram3Idx | SramHsIdx | SramRetIdx;
    stcSramConfig.enSramRC = SramCycle2;
    stcSramConfig.enSramWC = SramCycle2;
    SRAM_Init(&stcSramConfig);

    /* flash read wait cycle setting */
    EFM_Unlock();
    EFM_SetLatency(EFM_LATENCY_5);
    EFM_Lock();

    /* MPLL config (XTAL / pllmDiv * plln / PllpDiv = 200M). */
    stcMpllCfg.pllmDiv = 1ul;
    stcMpllCfg.plln    = 50ul;
    stcMpllCfg.PllpDiv = 2ul;
    stcMpllCfg.PllqDiv = 2ul;
    stcMpllCfg.PllrDiv = 2ul;
    CLK_SetPllSource(ClkPllSrcXTAL);//开启外部高速晶振
    CLK_MpllConfig(&stcMpllCfg); //配置MPLL

    /* Enable MPLL. */
    CLK_MpllCmd(Enable);//开启MPLL
    /* Wait MPLL ready. */
    while(Set != CLK_GetFlagStatus(ClkFlagMPLLRdy))
    {
        ;
    }
    /* Switch driver ability */
    PWC_HS2HP();
    /* Switch system clock source to MPLL. */
    CLK_SetSysClkSource(CLKSysSrcMPLL);     
}

首先我们大家要知道,时钟的配置原则应该是从后向前配置,即从外设向晶振方向配置。那下面我们对照时钟系统框图来分析上面的代码。

上面函数对照的时钟系统框图配置方向为下图:

以上部分参考:?



华大MCU(二):HC32f460启动过程和时钟分析_Zhichao_Zhang的博客-CSDN博客_华大单片机时钟

3. 在GPIO例程上修改调试:

?在例程?手把手教程3: F460建立一个GPIO点灯例程? 的基础上, 添加clk设置的部分,

clk开关对应的是哪些功能模块,参考?F460 CLK配置功能模块说明

调试遇到了一些问题,记录如下。

把BSP_CLK_Init添加过来之后,报错无数:

一边编译,一边修改;

?3.1 error: #223-D: function "BSP_CLK_Init" declared implicitly

F460:

在main.c中初始化了BSP_CLK_Init函数(CSDN),在主函数中调用的时候,报了这个错误,提示声明不合法,

参考下面文章,在main.c开头进行了声明调用extern void BSP_CLK_Init(void);

之后报错消失;

参考:KEIL MDK中 warning: #223-D: function "xxx" declared implicitly 解决方法_Grant的工作笔记-CSDN博客

这里其实有点奇怪,BSP_CLK_Init并不是在另一个.c文件中声明,是在main.c文件中的,和main函数在同一个文件中,按说不应该出现这个问题;

先把程序搞通过,这里记录一下,后面再找原因;

3.2 error: ?#20: identifier "stc_clk_sysclk_cfg_t" is undefined

BSP_CLK_Init的错误没有了,还有12个错误:

..\App\src\main.c(92): error:  #20: identifier "stc_clk_sysclk_cfg_t" is undefined
      stc_clk_sysclk_cfg_t    stcSysClkCfg;
..\App\src\main.c(93): error:  #20: identifier "stc_clk_xtal_cfg_t" is undefined
      stc_clk_xtal_cfg_t      stcXtalCfg;
..\App\src\main.c(94): error:  #20: identifier "stc_clk_mpll_cfg_t" is undefined
      stc_clk_mpll_cfg_t      stcMpllCfg;
..\App\src\main.c(103): error:  #20: identifier "ClkSysclkDiv1" is undefined
      stcSysClkCfg.enHclkDiv  = ClkSysclkDiv1;//hclk的时钟来之分频器的1分频
..\App\src\main.c(104): error:  #20: identifier "ClkSysclkDiv2" is undefined
      stcSysClkCfg.enExclkDiv = ClkSysclkDiv2;//exclk的时钟来之分频器的2分频
..\App\src\main.c(107): error:  #20: identifier "ClkSysclkDiv4" is undefined
      stcSysClkCfg.enPclk2Div = ClkSysclkDiv4;//Pclk2的时钟来自分频器的4分频
..\App\src\main.c(110): warning:  #223-D: function "CLK_SysClkConfig" declared implicitly
      CLK_SysClkConfig(&stcSysClkCfg);
..\App\src\main.c(113): error:  #20: identifier "ClkXtalModeOsc" is undefined
      stcXtalCfg.enMode = ClkXtalModeOsc;
..\App\src\main.c(114): error:  #20: identifier "ClkXtalLowDrv" is undefined
      stcXtalCfg.enDrv = ClkXtalLowDrv;
..\App\src\main.c(116): warning:  #223-D: function "CLK_XtalConfig" declared implicitly
      CLK_XtalConfig(&stcXtalCfg);
..\App\src\main.c(117): warning:  #223-D: function "CLK_XtalCmd" declared implicitly
      CLK_XtalCmd(Enable);
..\App\src\main.c(126): warning:  #223-D: function "EFM_Unlock" declared implicitly
      EFM_Unlock();
..\App\src\main.c(127): warning:  #223-D: function "EFM_SetLatency" declared implicitly
      EFM_SetLatency(EFM_LATENCY_5);
..\App\src\main.c(127): error:  #20: identifier "EFM_LATENCY_5" is undefined
      EFM_SetLatency(EFM_LATENCY_5);
..\App\src\main.c(128): warning:  #223-D: function "EFM_Lock" declared implicitly
      EFM_Lock();
..\App\src\main.c(136): warning:  #223-D: function "CLK_SetPllSource" declared implicitly
      CLK_SetPllSource(ClkPllSrcXTAL);//开启外部高速晶振
..\App\src\main.c(136): error:  #20: identifier "ClkPllSrcXTAL" is undefined
      CLK_SetPllSource(ClkPllSrcXTAL);//开启外部高速晶振
..\App\src\main.c(137): warning:  #223-D: function "CLK_MpllConfig" declared implicitly
      CLK_MpllConfig(&stcMpllCfg);		//配置MPLL
..\App\src\main.c(140): warning:  #223-D: function "CLK_MpllCmd" declared implicitly
      CLK_MpllCmd(Enable);						//开启MPLL
..\App\src\main.c(142): warning:  #223-D: function "CLK_GetFlagStatus" declared implicitly
      while(Set != CLK_GetFlagStatus(ClkFlagMPLLRdy))
..\App\src\main.c(142): error:  #20: identifier "ClkFlagMPLLRdy" is undefined
      while(Set != CLK_GetFlagStatus(ClkFlagMPLLRdy))
..\App\src\main.c(147): warning:  #223-D: function "PWC_HS2HP" declared implicitly
      PWC_HS2HP();
..\App\src\main.c(149): warning:  #223-D: function "CLK_SetSysClkSource" declared implicitly
      CLK_SetSysClkSource(CLKSysSrcMPLL);
..\App\src\main.c(149): error:  #20: identifier "CLKSysSrcMPLL" is undefined
      CLK_SetSysClkSource(CLKSysSrcMPLL);
..\App\src\main.c: 12 warnings, 12 errors

分析对比了一下,发现ddl.cfg.h里相关功能模块的clk的开关没有打开,分别都打开:

#define DDL_ICG_ENABLE                              (DDL_ON)  //打开
#define DDL_UTILITY_ENABLE                          (DDL_ON)  //打开
#define DDL_PRINT_ENABLE                            (DDL_OFF)

#define DDL_ADC_ENABLE                              (DDL_ON)  //打开
#define DDL_AES_ENABLE                              (DDL_OFF)
#define DDL_CAN_ENABLE                              (DDL_OFF)
#define DDL_CLK_ENABLE                              (DDL_ON)  //打开
#define DDL_CMP_ENABLE                              (DDL_OFF)
#define DDL_CRC_ENABLE                              (DDL_OFF)
#define DDL_DCU_ENABLE                              (DDL_OFF)
#define DDL_DMAC_ENABLE                             (DDL_OFF)
#define DDL_EFM_ENABLE                              (DDL_ON)  //打开
#define DDL_EMB_ENABLE                              (DDL_OFF)
#define DDL_EVENT_PORT_ENABLE                       (DDL_OFF)
#define DDL_EXINT_NMI_SWI_ENABLE                    (DDL_ON)  //打开
#define DDL_GPIO_ENABLE                             (DDL_ON)  //打开
#define DDL_HASH_ENABLE                             (DDL_OFF)
#define DDL_I2C_ENABLE                              (DDL_ON)  //打开
#define DDL_I2S_ENABLE                              (DDL_OFF)
#define DDL_INTERRUPTS_ENABLE                       (DDL_ON)  //打开
#define DDL_INTERRUPTS_SHARE_ENABLE                 (DDL_ON)  //打开
#define DDL_KEYSCAN_ENABLE                          (DDL_ON)  //打开
#define DDL_MPU_ENABLE                              (DDL_ON)  //打开
#define DDL_OTS_ENABLE                              (DDL_OFF)
#define DDL_PWC_ENABLE                              (DDL_ON)  //打开
#define DDL_QSPI_ENABLE                             (DDL_OFF)
#define DDL_RMU_ENABLE                              (DDL_OFF)
#define DDL_RTC_ENABLE                              (DDL_OFF)
#define DDL_SDIOC_ENABLE                            (DDL_OFF)
#define DDL_SPI_ENABLE                              (DDL_OFF)
#define DDL_SRAM_ENABLE                             (DDL_ON)  //打开
#define DDL_SWDT_ENABLE                             (DDL_OFF)
#define DDL_TIMER0_ENABLE                           (DDL_OFF)
#define DDL_TIMER4_CNT_ENABLE                       (DDL_ON)  //打开
#define DDL_TIMER4_EMB_ENABLE                       (DDL_OFF)
#define DDL_TIMER4_OCO_ENABLE                       (DDL_OFF)
#define DDL_TIMER4_PWM_ENABLE                       (DDL_OFF)
#define DDL_TIMER4_SEVT_ENABLE                      (DDL_OFF)
#define DDL_TIMER6_ENABLE                           (DDL_OFF)
#define DDL_TIMERA_ENABLE                           (DDL_ON)  //打开
#define DDL_TRNG_ENABLE                             (DDL_OFF)
#define DDL_USART_ENABLE                            (DDL_ON)  //打开
#define DDL_USBFS_ENABLE                            (DDL_OFF)
#define DDL_WDT_ENABLE                              (DDL_ON)  //打开

将相关的库文件加入到工程里:

?

并打开相应模块的clk之后,BSP_CLK_Init中的报错都消失了:

3.3 error: ?#254: type name is not allowed

在hc32f460_pwc.c(305)中,变量声明在for循环中:

_RAM_FUNC void PWC_EnterPowerDownMd(void)
{
		ENABLE_PVD_REG_WRITE();

    /* Reset PVD1IRS & PVD2IRS */
    M4_SYSREG->PWR_PVDCR1 &= 0xddu;

    DISABLE_PVD_REG_WRITE();

    ENABLE_PWR_REG_WRITE();

    M4_SYSREG->PWR_STPMCR_f.STOP = 1u;

    __disable_irq();
    M4_SYSREG->PWR_PWRC0_f.PWDN = 1u;
    for(uint8_t i = 0u; i < 10u; i++)
		//for(i = 0u; i < 10u; i++)
    {
        __NOP();
    }
    __enable_irq();

    DISABLE_PWR_REG_WRITE();

    __WFI();
}

这个文件来自于库函数,应该是可以这样写的,估计哪里选项要修改一下,

为了快速搭建demo,先不找了,直接修改为:

__RAM_FUNC void PWC_EnterPowerDownMd(void)
{
    uint8_t i = 0u;
		ENABLE_PVD_REG_WRITE();

    /* Reset PVD1IRS & PVD2IRS */
    M4_SYSREG->PWR_PVDCR1 &= 0xddu;

    DISABLE_PVD_REG_WRITE();

    ENABLE_PWR_REG_WRITE();

    M4_SYSREG->PWR_STPMCR_f.STOP = 1u;

    __disable_irq();
    M4_SYSREG->PWR_PWRC0_f.PWDN = 1u;
    //for(uint8_t i = 0u; i < 10u; i++)
		for(i = 0u; i < 10u; i++)
    {
        __NOP();
    }
    __enable_irq();

    DISABLE_PWR_REG_WRITE();

    __WFI();
}

3.5 error: ?#268: declaration may not appear after executable statement in block

在hc32f460_efm.c中,有这个函数

en_result_t EFM_OtpLock(uint32_t u32Addr)
{
	DDL_ASSERT(IS_VALID_OTP_LOCK_ADDR(u32Addr));
    uint16_t u16Timeout = 0u;
    en_result_t enRet = Ok;    
	
    /* Enable program. */
    EFM_ErasePgmCmd(Enable);
    /* Set single program mode. */
    M4_EFM->FWMC_f.PEMOD = EFM_MODE_SINGLEPROGRAM;

    /* Lock the otp block. */
    *(uint32_t*)u32Addr = 0ul;

    while(1ul != M4_EFM->FSR_f.RDY)
    {
        u16Timeout++;
        if(u16Timeout > 0x1000u)
        {
            enRet = ErrorTimeout;
        }
    }

    EFM_ClearFlag(EFM_FLAG_EOP);
    /* Set read only mode. */
    M4_EFM->FWMC_f.PEMOD = EFM_MODE_READONLY;
    EFM_ErasePgmCmd(Disable);

    return enRet;
}

变量定义Ai执行语句之后,改为这样:

en_result_t EFM_OtpLock(uint32_t u32Addr)
{
	//DDL_ASSERT(IS_VALID_OTP_LOCK_ADDR(u32Addr));
    uint16_t u16Timeout = 0u;
    en_result_t enRet = Ok;
    DDL_ASSERT(IS_VALID_OTP_LOCK_ADDR(u32Addr));
	
    /* Enable program. */
    EFM_ErasePgmCmd(Enable);
    /* Set single program mode. */
    M4_EFM->FWMC_f.PEMOD = EFM_MODE_SINGLEPROGRAM;

    /* Lock the otp block. */
    *(uint32_t*)u32Addr = 0ul;

    while(1ul != M4_EFM->FSR_f.RDY)
    {
        u16Timeout++;
        if(u16Timeout > 0x1000u)
        {
            enRet = ErrorTimeout;
        }
    }

    EFM_ClearFlag(EFM_FLAG_EOP);
    /* Set read only mode. */
    M4_EFM->FWMC_f.PEMOD = EFM_MODE_READONLY;
    EFM_ErasePgmCmd(Disable);

    return enRet;
}

3.6 编译通过;

F460建立一个GPIO点灯例程的基础上修改完成,编译通过,下载成功,LED在欢快的闪烁!!!

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-03-10 22:45:28  更:2022-03-10 22:46:03 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 7:28:05-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码