GD32F103学习笔记(2)——在GD32F103移植STM32F103代码

发布者:快乐飞翔最新更新时间:2025-02-08 来源: jianshu关键字:GD32F103  移植 手机看文章 扫描二维码
随时随地手机看文章

一、GD32与STM32区别

1.1 内部结构区别

1.1.1 内核

GD32采用二代的M3内核,STM32主要采用一代M3内核,下图是ARM公司的M3内核勘误表,GD使用的内核只有752419这一个BUG。

1.1.2 主频时钟

  • 使用HSE(高速外部时钟):GD32的主频最大108M,STM32的主频最大72M

  • 使用HSI(高速内部时钟):GD32的主频最大108M,STM32的主频最大64M

主频大意味着单片机代码运行的速度会更快,GD32的_NOP()时间比STM32更加短,所以不使用定时器做延时时要注意修改,项目中如果需要进行刷屏,开方运算,电机控制等操作,GD是一个不错的选择。

1.1.3 启动时间

GD32启动时间相同,由于GD运行稍快,需要延长上电时间配置(2ms)。

1.1.4 时序要求

GD32对时序要求严格,配置外设需要先打开时钟,否则可能导致外设无法配置成功;STM32的可以先配置再开时钟。

1.1.5 供电


GD32FSTM32F
外部电压2.6-3.6V2.0-3.6V
内核电压1.2V1.8V
  • 外部供电:GD32外部供电范围是2.6-3.6V,STM32外部供电范围是2.0-3.6V。GD32的供电范围比STM32相对要窄一点。

  • 内核电压:GD32内核电压是1.2V,STM32内核电压是1.8V。GD的内核电压比STM32的内核电压要低,所以GD的芯片在运行的时候运行功耗更低。

1.2 内部FLASH区别

1.2.1 Flash擦除时间

GD32的Flash是自主研发的,和STM32的不一样。

  • GD Flash执行速度:GD32 Flash中程序执行为0等待周期。

  • STM32 Flash执行速度:ST系统频率不访问Flash等待时间关系:0等待周期,当0

Flash擦除时间:GD32的Flash擦除时间要比STM32更长,官方给出的数据是这样的:GD32F103/101系列Flash 128KB 及以下的型号, Page Erase 典型值100ms, 实际测量60ms左右。对应的ST 产品Page Erase 典型值20~40ms。

1.2.2 Flash和RAM容量

GD32的Flash最大有3M,STM32最大只有1M。

1.3 功耗区别

功耗区别(以128k以下容量的作为参考)

模式GD32F10xSTM32F10x
睡眠模式 Sleep12.4mA7.5mA
深度睡眠模式 Deep Sleep1.4mA24uA
待机模式 Stand By10.5uA3.4uA
运行功耗32.4mA/72M52mA/72M

功耗上GD32的静态功耗要相对高一点。从上面的表可以看出GD的产品在相同主频情况下,GD的运行功耗比STM32小,但是在相同的设置下GD的停机模式、待机模式、睡眠模式比STM32还是要高的。

1.4 外围硬件区别

1.4.1 串口

GD在连续发送数据的时候每两个字节之间会有一个Bit的Idle,而STM32没有。
GD32的串口在发送的时候停止位只有1/2两种停止位模式。STM32有0.5/1/1.5/2四种停止位模式。


1.4.2 ADC

GD32的输入阻抗和采样时间的设置和STM32有一定差异,相同配置GD采样的输入阻抗相对来说要小。
具体情况见下表这是跑在72M的主频下,ADC的采样时钟为14M的输入阻抗和采样周期的关系:

1.4.3 FSMC

STM32只有100Pin以上的大容量(256K及以上)才有FSMC,GD32所有的100Pin 或 100Pin以上的都有FSMC。

1.4.4 SWD接口

GD32的SWD接口驱动能力比STM32弱,可以有如下几种方式解决:

  1. 线尽可能短一些;

  2. 降低SWD通讯速率;

  3. SWDIO接10k上拉,SWCLK接10k下拉。

1.4.5 BOOT0管脚

GD32的BOOT0必须接10K下拉或接GND,STM32可悬空。

1.4.6 RC复位电路

RC复位电路必须要有,否则MCU可能不能正常工作,STM32有时候可以不要。

二、硬件替换需要注意的地方

从上面的介绍中,我们可以看出,GD32F103系列和STM32F103系列是兼容的,但也需要一些注意的地方。

  • BOOT0必须接10K下拉或接GND,ST可悬空,这点很重要。

  • RC复位电路必须要有,否则MCU可能不能正常工作,ST的有时候可以不要。

  • 有时候发现用仿真器连接不上。因为GD的SWD接口驱动能力比ST弱,可以有如下几种方式解决:

    1. 线尽可能短一些;

    2. 降低SWD通讯速率;

    3. SWDIO接10k上拉,SWCLK接10k下拉。

  • 使用电池供电等,注意GD的工作电压,例如跌落到2.0V~2.6V区间,ST还能工作,GD可能无法启动或工作异常。

  • 在GD32F103小容量产品中使用有源晶振,发现会在MCU的复位管脚一直把电平拉到0.89V,电平不能保持在高电平。是由于部分有源晶振起振时间太快,复位信号还没有完成导致的。解决方法就是在有源晶振的输入端与地之前并上一个30pF电容。

三、使用ST标准库开发需要修改的地方

3.1 时序要求

GD32对时序要求严格,配置外设需要先打开时钟,否则可能导致外设无法配置成功;STM32的可以先配置再开时钟。


3.2 修改外部晶振启动时间

不用外部晶振可跳过这步。
由于GD与ST的启动时间存在差异,为了让GD MCU更准确复位,需要对下面参数进行修改。


在 stm32f10x.h 头文件中

将宏定义:

#define HSE_STARTUP_TIMEOUT ((uint16_t)0x0500)

修改为:

#define HSE_STARTUP_TIMEOUT ((uint16_t)0xFFFF)


3.3 修改主频

3.3.1 以72MHz运行

只需要修改上面提到的 HSE_STARTUP_TIMEOUT 把这个从 ((uint16_t)0x0500) 改为 ((uint16_t)0xFFFF)


3.3.2 以108MHz运行

  1. 打开 system_stm32f10x.c,将原有的宏注释掉,然后手动添加新的108MHz的宏

代码如下:

#define SYSCLK_FREQ_108MHz  108000000
  1. 因为改了宏,下面通过宏来给 SystemCoreClock 赋值也要修改

代码如下:

#elif defined SYSCLK_FREQ_108MHz

  uint32_t SystemCoreClock         = SYSCLK_FREQ_108MHz;       /*!< System Clock Frequency (Core Clock) */


  1. 然后还要修改通过宏来选择的函数,就是用来初始化系统时钟配置的,最主要的函数(这个函数是本来没有的,自己设置的)


代码如下:

#elif defined SYSCLK_FREQ_108MHz
  static void SetSysClockTo108(void);
  1. 同理,SetSysClock() 也要修改

代码如下:

#elif defined SYSCLK_FREQ_108MHz
  SetSysClockTo108();
  1. 最后实现108MHz的函数 SetSysClockTo108(),可以在文件最下面实现,注释掉上面一行的 #endif

代码如下:

#elif defined SYSCLK_FREQ_108MHz

/**

  * @brief  使用内部时钟倍频到108MHz 

  * @note   This function should be used only after reset.

  * @param  None

  * @retval None

  */

#define  RCC_CFGR_PLLMULL27                 ((uint32_t)0x08280000)

static void SetSysClockTo108(void)

{

    /* Enable Prefetch Buffer */

    FLASH->ACR |= FLASH_ACR_PRFTBE;


    /* Flash 2 wait state */

    FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);

    FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;    


 

    /* HCLK = SYSCLK */

    RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;

      

    /* PCLK2 = HCLK */

    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;

    

    /* PCLK1 = HCLK */

    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;



    /*  PLL configuration: PLLCLK = HSI * 27 = 108 MHz */

    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |

                                        RCC_CFGR_PLLMULL));

    RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLMULL27);



    /* Enable PLL */

    RCC->CR |= RCC_CR_PLLON;


    /* Wait till PLL is ready */

    while((RCC->CR & RCC_CR_PLLRDY) == 0)

    {

    }

    

    /* Select PLL as system clock source */

    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));

    RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;    


    /* Wait till PLL is used as system clock source */

    while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)

    {

    }

}

#endif


还没结束,这样的话可以实现108MHz,但会有串口波特率错误的BUG,还需要以下修改。


3.4 修改RCC文件

时钟改为108MHz后如果不修改RCC文件会导致串口不合适,需要修改 stm32f10x_rcc.c 文件。具体不懂可以参考GD的手册。

打开 stm32f10x_rcc.c,找到 RCC_GetClocksFreq() 函数


增加一段这样的代码就可以了


代码如下:

/**

  * @brief  Returns the frequencies of different on chip clocks.

  * @param  RCC_Clocks: pointer to a RCC_ClocksTypeDef structure which will hold

  *         the clocks frequencies.

  * @note   The result of this function could be not correct when using 

  *         fractional value for HSE crystal.  

  * @retval None

  */

void RCC_GetClocksFreq(RCC_ClocksTypeDef* RCC_Clocks)

{

  uint32_t tmp = 0, pllmull = 0, pllsource = 0, presc = 0;


#ifdef  STM32F10X_CL

  uint32_t prediv1source = 0, prediv1factor = 0, prediv2factor = 0, pll2mull = 0;

#endif /* STM32F10X_CL */


#if defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || defined (STM32F10X_HD_VL)

  uint32_t prediv1factor = 0;

#endif

    

  /* Get SYSCLK source -------------------------------------------------------*/

  tmp = RCC->CFGR & CFGR_SWS_Mask;

  

  switch (tmp)

  {

    case 0x00:  /* HSI used as system clock */

      RCC_Clocks->SYSCLK_Frequency = HSI_VALUE;

      break;

    case 0x04:  /* HSE used as system clock */

      RCC_Clocks->SYSCLK_Frequency = HSE_VALUE;

      break;

    case 0x08:  /* PLL used as system clock */


      /* Get PLL clock source and multiplication factor ----------------------*/

      pllmull = RCC->CFGR & CFGR_PLLMull_Mask;  //倍频系数 & 0x003C0000(取18~21)

      pllsource = RCC->CFGR & CFGR_PLLSRC_Mask; //时钟源

      

#ifndef STM32F10X_CL      

      pllmull = ( pllmull >> 18) + 2;   //看手册里面寄存器描述

    

      if (RCC->CFGR & 0x08000000)   //取27位

      {

          pllmull += 15;

      }

      

      if (pllsource == 0x00)

      {/* HSI oscillator clock divided by 2 selected as PLL clock entry */

        RCC_Clocks->SYSCLK_Frequency = (HSI_VALUE >> 1) * pllmull;

      }

      else

      {

 #if defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || defined (STM32F10X_HD_VL)

       prediv1factor = (RCC->CFGR2 & CFGR2_PREDIV1) + 1;

       /* HSE oscillator clock selected as PREDIV1 clock entry */

       RCC_Clocks->SYSCLK_Frequency = (HSE_VALUE / prediv1factor) * pllmull; 

 #else

        /* HSE selected as PLL clock entry */

        if ((RCC->CFGR & CFGR_PLLXTPRE_Mask) != (uint32_t)RESET)

        {/* HSE oscillator clock divided by 2 */

          RCC_Clocks->SYSCLK_Frequency = (HSE_VALUE >> 1) * pllmull;

        }

        else

        {

          RCC_Clocks->SYSCLK_Frequency = HSE_VALUE * pllmull;

        }

 #endif

      }

#else

      pllmull = pllmull >> 18;

      

      if (pllmull != 0x0D)

      {

         pllmull += 2;

      }

      else

      { /* PLL multiplication factor = PLL input clock * 6.5 */

        pllmull = 13 / 2; 

      }

            

      if (pllsource == 0x00)

      {/* HSI oscillator clock divided by 2 selected as PLL clock entry */

        RCC_Clocks->SYSCLK_Frequency = (HSI_VALUE >> 1) * pllmull;

      }

      else

      {/* PREDIV1 selected as PLL clock entry */

        

        /* Get PREDIV1 clock source and division factor */

        prediv1source = RCC->CFGR2 & CFGR2_PREDIV1SRC;

        prediv1factor = (RCC->CFGR2 & CFGR2_PREDIV1) + 1;

        

        if (prediv1source == 0)

        { /* HSE oscillator clock selected as PREDIV1 clock entry */

          RCC_Clocks->SYSCLK_Frequency = (HSE_VALUE / prediv1factor) * pllmull;          

        }

        else

        {/* PLL2 clock selected as PREDIV1 clock entry */

[1] [2]
关键字:GD32F103  移植 引用地址:GD32F103学习笔记(2)——在GD32F103移植STM32F103代码

上一篇:vscode + PlatformIO嵌入式芯片开发环境搭建
下一篇:ST-Link v2 下载 出现target dll has been cancelled 的错误的解决方法及详解

推荐阅读最新更新时间:2026-03-21 11:56

GD32F103移植STM32F103代码
使用相同FLASH和管脚数量相同的芯片,例如GDF103C8T6移植STM32F103C8T6程序。虽然两个款芯片的寄存器地址以及架构基本相同。但是需要注意的是GD32F10x主频是108兆,但是STM32F10x主频是72兆。所以需要针对以RCC时钟进行修改。 例如打开原子哥的ALIENTEK MINISTM32 实验8 PWM输出实验例程 先将芯片的选项进行修改 然后将STM32的启动文件替换成GD的启动文件,关于STM32启动,点击:详解STM32启动文件。 当然也可以不替换,我这里选择替换掉。 然后就想修改时钟相关配置 ①打开stm32f10x.h文件,找到定义 //#define HSE_STARTU
[单片机]
在<font color='red'>GD32F103</font><font color='red'>移植</font><font color='red'>STM32F103</font><font color='red'>代码</font>
GD32F103移植STM32的程序定时器开关
GD32F103移植STM32程序时,程序中有一段需要关闭定时器来保护变量不被修改,如下: TIM_Cmd( TIM4, DISABLE ); yen += coinBuf ; coinBuf =0; TIM_Cmd( TIM4, ENABLE ); 在STM32上运行没有问题,但放到GD32上运行不了,定时器起不来。需要改成如下关闭中断。 TIM_ITConfig(TIM4, TIM_IT_Update, DISABLE); yen += coinBuf ; coinBuf =0; TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE);
[单片机]
基于STM32F103C8T6单片机的RTC实时时钟原理及配置代码
学习STM32的RTC之前先了解一下UNIX时间戳 UNIX时间戳 Unix 时间戳(Unix Timestamp)定义为从UTC/GMT的1970年1月1日0时0分0秒开始所经过的秒数(不进位为时、天、月),不考虑闰秒 时间戳存储在一个秒计数器中,秒计数器为32位/64位的整型变量 世界上所有时区的秒计数器相同,不同时区通过添加偏移来得到当地时间 优点 1)使用秒数可以简化硬件电路,直接弄一个很大的秒寄存器,不需要再考虑年月日寄存器以及进位 2)计算时间间隔很方便,直接用两个秒数相减 3)存储方便,用一个很大的变量来就可以了 秒计数器以及伦敦时间和北京时间的对用关系如下所示: 直接搜索可以找到在线
[单片机]
基于<font color='red'>STM32F103</font>C8T6单片机的RTC实时时钟原理及配置<font color='red'>代码</font>
GD32F103学习笔记(1)——搭建环境、编译烧写
一、搭建环境 1.1 官方资料 GD32F10x 资料下载 1.2 安装Keil 5 官网下载: http://www2.keil.com/mdk5/ 百度网盘: https://pan.baidu.com/s/1T_eF5NDYeq38bR0cqjiZkw 提取码:562z 阿里云盘: https://www.aliyundrive.com/s/giDvR2ShJR9 1.3 下载SDK 官网下载: http://www.gd32mcu.com/download/down/document_id/180/path_type/1 百度网盘: https://pan.baidu.com/s/1vneR70WP9qm9S
[单片机]
gd32f103可以完全替代stm32f103
GD32F103是中国厂商GigaDevice推出的一款低成本、高性能的微控制器产品线。STM32F103是意法半导体(STMicroelectronics)的旗舰产品之一,享有良好的声誉和广泛的市场份额。两个系列都基于ARM Cortex-M3内核,因此在功能和性能上有一些相似之处。 一、技术特点比较: 1.1 处理器核心: GD32F103和STM32F103都采用了ARM Cortex-M3内核,因此在核心处理能力和指令集方面并无差异。 1.2 主频和性能: 两个系列都提供了多个型号,主频从72MHz到120MHz不等。但是需要注意的是,尽管在频率上存在一些差异,但两个系列的处理器都是32位的,因此在处理数据和执行指令方面具
[单片机]
错误解决:STM32F103串口1与串口3相同代码却结果不同
在前几天调试openmv时发现同样的代码串口1和串口3的结果却是不一样的,当时着实是把我坑了很久,怎么都找不到原因,用示波器看波形也是没有问题的,在Openedv网站上有位网友指出是我初始化代码的问题,在翻阅参考手册后终于发现了问题。 下列代码为我原本的初始化代码: #include sys.h #include usart.h #include led.h #include usart3.h int theta_err,rho_err; int main(void) { Stm32_Clock_Init(9); //=====系统时钟设置 delay_init(72); /
[单片机]
错误解决:<font color='red'>STM32F103</font>串口1与串口3相同<font color='red'>代码</font>却结果不同
STM32F103RCT6+USART3+UART5初始化代码
USART和UART的区别就是:USART支持同步收发,UART只支持异步收发 同步模式:USART 需要同步始终信号USART_CK,通常情况同步信号很少使用,因此一般的单片机UART和USART使用方式是一样的,都使用异步模式。 1 USART3初始化 void USART3_init(void) { GPIO_InitTypeDef GPIO_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE); //使能USART3,GPIOB时钟 RCC
[单片机]
STM32F103 Flash操作代码解析
/************************************************************************/ // !!!一定要记住!!!Flash寿命是有限的,别程序开着一直擦!!用到再擦 // !!!爱护Flash人人有责 // 必须先解锁Flash uint64_t data = 0; // 一页 1KB // stm32f103 Flash 建议使用页地址为:0x0807F000 // 寻址范围:0x0807F000 - 0x0807FFFF uint32_t *Address = (uint32_t*)0x08
[单片机]
小广播
最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

厂商技术中心

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2026 EEWORLD.com.cn, Inc. All rights reserved