首页 > 其他分享 >CH32V003在MRS中的初始化过程

CH32V003在MRS中的初始化过程

时间:2023-08-13 21:22:33浏览次数:37  
标签:初始化 word CH32V003 weak MRS IRQHandler DMA1 1b RCC

在MRS的默认配置中,在main函数执行之前,就已经执行了时钟的初始化配置程序,这部分程序被放在了一个名为system_ch32v00x.c的文件中,这个文件默认被加载到MRS的User目录下(可双击打开它)。在该文件中,最重要的一个函数就是SystemInit,它负责系统的初始化工作,其代码如下所示。 

void SystemInit (void)
{
  RCC->CTLR |= (uint32_t)0x00000001;
  RCC->CFGR0 &= (uint32_t)0xFCFF0000;
  RCC->CTLR &= (uint32_t)0xFEF6FFFF;
  RCC->CTLR &= (uint32_t)0xFFFBFFFF;
  RCC->CFGR0 &= (uint32_t)0xFFFEFFFF;
  RCC->INTR = 0x009F0000;
  SetSysClock();
} 

在末尾调用了一个设置系统时钟的函数SetSysClock,其代码如下。

static void SetSysClock(void)
{
#ifdef SYSCLK_FREQ_8MHz_HSI
    SetSysClockTo_8MHz_HSI();
#elif defined SYSCLK_FREQ_24MHZ_HSI
    SetSysClockTo_24MHZ_HSI();
#elif defined SYSCLK_FREQ_48MHZ_HSI
    SetSysClockTo_48MHZ_HSI();
#elif defined SYSCLK_FREQ_8MHz_HSE
    SetSysClockTo_8MHz_HSE();
#elif defined SYSCLK_FREQ_24MHz_HSE
    SetSysClockTo_24MHz_HSE();
#elif defined SYSCLK_FREQ_48MHz_HSE
    SetSysClockTo_48MHz_HSE();
#endif
}

从上可看出,该函数主要依据宏定义SYSCLK_FREQ的值来决定使用哪一个配置函数,并没有具体内容。这里不妨选取最后一个函数SetSysClockTo_48MHz_HSE(即使用外部晶振的48MHz主频模式)来展开讨论,其代码如下所示。

static void SetSysClockTo_48MHz_HSE(void)
{
    __IO uint32_t StartUpCounter = 0, HSEStatus = 0;

    /* Close PA0-PA1 GPIO function */
    RCC->APB2PCENR |= RCC_AFIOEN;
    AFIO->PCFR1 |= (1<<15);

    RCC->CTLR |= ((uint32_t)RCC_HSEON);

    /* Wait till HSE is ready and if Time out is reached exit */
    do
    {
        HSEStatus = RCC->CTLR & RCC_HSERDY;
        StartUpCounter++;
    } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));

    if ((RCC->CTLR & RCC_HSERDY) != RESET)
    {
        HSEStatus = (uint32_t)0x01;
    }
    else
    {
        HSEStatus = (uint32_t)0x00;
    }

    if (HSEStatus == (uint32_t)0x01)
    {
        /* Flash 0 wait state */
        FLASH->ACTLR &= (uint32_t)((uint32_t)~FLASH_ACTLR_LATENCY);
        FLASH->ACTLR |= (uint32_t)FLASH_ACTLR_LATENCY_1;

        /* HCLK = SYSCLK = APB1 */
        RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;

        /* PLL configuration: PLLCLK = HSE * 2 = 48 MHz */
        RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC));
        RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE_Mul2);

        /* Enable PLL */
        RCC->CTLR |= RCC_PLLON;
        /* Wait till PLL is ready */
        while((RCC->CTLR & RCC_PLLRDY) == 0)
        {
        }
        /* Select PLL as system clock source */
        RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW));
        RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;
        /* Wait till PLL is used as system clock source */
        while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08)
        {
        }
    }
    else
    {
        /*
         * If HSE fails to start-up, the application will have wrong clock
     * configuration. User can add here some code to deal with this error
         */
    }
}

以上就是MRS中系统初始化的具体流程,看起来是不是有些绕(仅为了方便开发者),能不能自己实现一个精简的初始化过程呢?答案是肯定的。以下就一个是非常精简的初始化代码实例。

void SetSysClockTo_48MHz_HSE(void)
{
    RCC->CFGR0 = 0;   //AHB时钟不分频
    RCC->APB2PCENR |= 0x00000001;  //使能I/O辅助功能模块时钟
    AFIO->PCFR1 |= (1<<15);  //引脚PA1&PA2重映射位,改为接外部晶振引脚
    RCC->CTLR |= 0x00010000;  //使能外部振荡器
    while(!(RCC->CTLR & 0x00020000));  //等待外部晶振稳定
    FLASH->ACTLR &= 0x00000003;
    FLASH->ACTLR |= 0x00000001; //设置FLASH等待
    RCC->CFGR0 |= 0x00010000;  //选择外部晶振
    RCC->CTLR |= 0x01000000;  //开启PLL
    while(!(RCC->CTLR & 0x02000000));  //等待PLL稳定
    RCC->CFGR0 &= ~0x00000003;
    RCC->CFGR0 |= 0x00000002;  //选择PLL作为系统时钟
}

上面的函数可直接放在main.c文件中,提供给main函数调用。为此,还可以移出默认在User目录下的系统配置文件system_ch32v00x.c及其头文件system_ch32v00x.h,只留下一个main.c文件,同时把头文件ch32v00x.h中的“#include <system_ch32v00x.h>”一句注释掉,让开发环境做到极简。但是,文件移出后编译会报错,原因是缺失了系统初始化函数SystemInit。如何解决?有两种方法。其一,把上面的函数名称改为“void SystemInit (void)”,让系统在复位后直接执行初始化,这就不需要在main函数中来调用它了。其二,更改系统在复位后的程序入口,直接执行main函数,这需要修改系统启动文件startup_ch32v00x.S。启动文件是用汇编写成的,下面是它的具体内容。 

    .section  .init, "ax", @progbits
    .globl  _start
    .align  2
_start:
    .option   norvc;
    j       handle_reset
    .word   0
    .word   NMI_Handler                  /* NMI Handler */
    .word   HardFault_Handler            /* Hard Fault Handler */
    .word   0
    .word   0
    .word   0
    .word   0
    .word   0
    .word   0
    .word   0
    .word   0
    .word   SysTick_Handler             /* SysTick Handler */
    .word   0
    .word   SW_Handler                  /* SW Handler */
    .word   0
    /* External Interrupts */
    .word   WWDG_IRQHandler             /* Window Watchdog */
    .word   PVD_IRQHandler              /* PVD through EXTI Line detect */
    .word   FLASH_IRQHandler            /* Flash */
    .word   RCC_IRQHandler              /* RCC */
    .word   EXTI7_0_IRQHandler           /* EXTI Line 7..0 */
    .word   AWU_IRQHandler              /* AWU */
    .word   DMA1_Channel1_IRQHandler       /* DMA1 Channel 1 */
    .word   DMA1_Channel2_IRQHandler       /* DMA1 Channel 2 */
    .word   DMA1_Channel3_IRQHandler       /* DMA1 Channel 3 */
    .word   DMA1_Channel4_IRQHandler       /* DMA1 Channel 4 */
    .word   DMA1_Channel5_IRQHandler       /* DMA1 Channel 5 */
    .word   DMA1_Channel6_IRQHandler       /* DMA1 Channel 6 */
    .word   DMA1_Channel7_IRQHandler       /* DMA1 Channel 7 */
    .word   ADC1_IRQHandler              /* ADC1 */
    .word   I2C1_EV_IRQHandler             /* I2C1 Event */
    .word   I2C1_ER_IRQHandler             /* I2C1 Error */
    .word   USART1_IRQHandler              /* USART1 */
    .word   SPI1_IRQHandler                /* SPI1 */
    .word   TIM1_BRK_IRQHandler            /* TIM1 Break */
    .word   TIM1_UP_IRQHandler             /* TIM1 Update */
    .word   TIM1_TRG_COM_IRQHandler        /* TIM1 Trigger and Commutation */
    .word   TIM1_CC_IRQHandler             /* TIM1 Capture Compare */
    .word   TIM2_IRQHandler                /* TIM2 */
    .option rvc;
    .section  .text.vector_handler, "ax", @progbits
    .weak   NMI_Handler
    .weak   HardFault_Handler
    .weak   SysTick_Handler
    .weak   SW_Handler
    .weak   WWDG_IRQHandler
    .weak   PVD_IRQHandler
    .weak   FLASH_IRQHandler
    .weak   RCC_IRQHandler
    .weak   EXTI7_0_IRQHandler
    .weak   AWU_IRQHandler
    .weak   DMA1_Channel1_IRQHandler
    .weak   DMA1_Channel2_IRQHandler
    .weak   DMA1_Channel3_IRQHandler
    .weak   DMA1_Channel4_IRQHandler
    .weak   DMA1_Channel5_IRQHandler
    .weak   DMA1_Channel6_IRQHandler
    .weak   DMA1_Channel7_IRQHandler
    .weak   ADC1_IRQHandler
    .weak   I2C1_EV_IRQHandler
    .weak   I2C1_ER_IRQHandler
    .weak   USART1_IRQHandler
    .weak   SPI1_IRQHandler
    .weak   TIM1_BRK_IRQHandler
    .weak   TIM1_UP_IRQHandler
    .weak   TIM1_TRG_COM_IRQHandler
    .weak   TIM1_CC_IRQHandler
    .weak   TIM2_IRQHandler
NMI_Handler:              1: j 1b
HardFault_Handler:        1: j 1b
SysTick_Handler:          1: j 1b
SW_Handler:               1: j 1b
WWDG_IRQHandler:          1: j 1b
PVD_IRQHandler:           1: j 1b
FLASH_IRQHandler:         1: j 1b
RCC_IRQHandler:           1: j 1b
EXTI7_0_IRQHandler:       1: j 1b
AWU_IRQHandler:           1: j 1b
DMA1_Channel1_IRQHandler: 1: j 1b
DMA1_Channel2_IRQHandler: 1: j 1b
DMA1_Channel3_IRQHandler: 1: j 1b
DMA1_Channel4_IRQHandler: 1: j 1b
DMA1_Channel5_IRQHandler: 1: j 1b
DMA1_Channel6_IRQHandler: 1: j 1b
DMA1_Channel7_IRQHandler: 1: j 1b
ADC1_IRQHandler:          1: j 1b
I2C1_EV_IRQHandler:       1: j 1b
I2C1_ER_IRQHandler:       1: j 1b
USART1_IRQHandler:        1: j 1b
SPI1_IRQHandler:          1: j 1b
TIM1_BRK_IRQHandler:      1: j 1b
TIM1_UP_IRQHandler:       1: j 1b
TIM1_TRG_COM_IRQHandler:  1: j 1b
TIM1_CC_IRQHandler:       1: j 1b
TIM2_IRQHandler:          1: j 1b
    .section  .text.handle_reset, "ax", @progbits
    .weak     handle_reset
    .align    1
handle_reset:
.option push
.option norelax
    la gp, __global_pointer$
.option pop
1:
    la sp, _eusrstack
2:
    /* Load data section from flash to RAM */
    la a0, _data_lma
    la a1, _data_vma
    la a2, _edata
    bgeu a1, a2, 2f
1:
    lw t0, (a0)
    sw t0, (a1)
    addi a0, a0, 4
    addi a1, a1, 4
    bltu a1, a2, 1b
2:
    /* clear bss section */
    la a0, _sbss
    la a1, _ebss
    bgeu a0, a1, 2f
1:
    sw zero, (a0)
    addi a0, a0, 4
    bltu a0, a1, 1b
2:
    li t0, 0x80
    csrw mstatus, t0  
    li t0, 0x3
    csrw 0x804, t0  
    la t0, _start
    ori t0, t0, 3
    csrw mtvec, t0  
    jal   SystemInit
    la t0, main
    csrw mepc, t0
    mret 

在系统复位后,程序指针从handle_reset的地方开始执行。这里只需要把下面的“jal SystemInit”一句(倒数第4行处)注释掉就可以了,不让程序指针跳转到SystemInit函数去,而是直接跳转到main函数去执行。 

标签:初始化,word,CH32V003,weak,MRS,IRQHandler,DMA1,1b,RCC
From: https://www.cnblogs.com/fxzq/p/17400177.html

相关文章

  • Netty源码学习1——NioEventLoopGroup的初始化
    系列文章目录和关于我零丶引入netty源码学习中,大家maybe都接触到如下的helloworld——netty客户端启动的demo:映入眼帘的第一个类就是NioEventLoopGroup,很多文章上来就是是Netty中的核心类,啥Channel,Pipeline,Context,Boostrap一通劈里啪啦,我看起来比较费劲。so本文不会上来就给......
  • SQL 语句创建数据库表时列字段的初始化值
    在SQL中,创建数据库表时可以指定每个列字段的初始值,这称为"默认值"(DefaultValue)。默认值是在插入新记录时,如果没有显式提供该列的值,则自动应用的值。当插入新行时,如果未提供该列的值,则数据库会使用默认值来填充该列。默认值对于确保数据完整性和提供默认选项非常有用。当插入新行......
  • 深入理解 Spring Bean 的生命周期与初始化过程
    SpringFramework是一个广泛使用的开发框架,它提供了强大的依赖注入和控制反转功能,同时也涉及了丰富的Bean生命周期管理。在本篇博客中,我们将深入探讨SpringBean的生命周期以及初始化过程,并通过代码示例演示每个阶段的实际调用。1.Bean生命周期阶段SpringBean的生命周期可......
  • CH32V003及其开发环境
    CH32V003是南京沁恒微电子股份有限公司推出的一颗工业级通用微控制器芯片(单片机)。它基于32位RISC-V指令集及架构设计,采用该公司自主开发的青稞V2A(QingKeV2)内核,基于RV32EC指令集,具有2级流水线,支持2级中断嵌套,支持2级硬件堆栈。支持48MHz系统主频,具有宽压(3.3/5V)、单线调试(SWDIO)、低......
  • CH32V003开发环境MRS配置
    MRS是MounRiver工作室采用开源项目Eclipse制作的一款易于使用的开发工具,它几乎是为WCH系列芯片量身定制的,相对于其他一些开发环境,它具有编译速度快,使用简洁方便,支持多种平台等特点,可访问MounRiver的官网(www.mounriver.com)下载最新版本。MRS的安装可全部采用默认选项进行,安装完成......
  • C++ 构造函数初始化:提高代码可读性和执行效率
    在C++中,构造函数是用来初始化对象数据成员的。一个对象在创建的时候,构造函数会被自动调用,以便为该对象的数据成员赋初值。传统的初始化方式是在构造函数内部对数据成员逐一进行初始化,这种方式虽然可行,但是代码复杂度高且效率低下。本文将介绍如何使用构造函数初始化列表来提高......
  • K8S 1.27.1版本初始化配置文件时报your configuration file uses an old API spec: "k
    现象:yourconfigurationfileusesanoldAPIspec:"kubeadm.k8s.io/v1beta2".Pleaseusekubeadmv1.22insteadandrun'kubeadmconfigmigrate--old-configold.yaml--new-confignew.yaml',whichwillwritethenew,similarspecusingan......
  • MRS大企业ERP流程实时数据湖加工最佳实践
    本文分享自华为云社区《MRS大企业ERP流程实时数据湖加工最佳实践》,作者:晋红轻。本文将以ERP流程实践为例介绍MRS实时数据湖方案的演进案例实践需求解析:业务描述AE表:会计分录表,主要记录财务相关信息,可用于成本核算等业务计算。为业务最主要的表,称驱动表。四通道表:实际为四个......
  • Java Map初始化赋值 Map初始化和Map赋值
    JavaMap初始化赋值原文链接:https://www.python100.com/html/105098.html一、Map初始化Map是Java中的一种数据结构,用于存储键值对。初始化Map有两种主要方法。第一种方法使用put方法手动为Map添加键值对;第二种方法使用静态代码块初始化Map。1.put方法手动添加键值对put方法......
  • MRS大企业ERP流程实时数据湖加工最佳实践
    本文分享自华为云社区《MRS大企业ERP流程实时数据湖加工最佳实践》,作者:晋红轻。本文将以ERP流程实践为例介绍MRS实时数据湖方案的演进案例实践需求解析:业务描述AE表:会计分录表,主要记录财务相关信息,可用于成本核算等业务计算。为业务最主要的表,称驱动表。四通道表:实际为四个门店业......