GD32移植STM32工程(因为懒,所以移植)

news2024/11/24 18:51:47

文章目录

  • 一、前言
  • 二、差异性
  • 三、软件移植部分
    • 1.前期准备
      • 1.1 安装GD32固件库
      • 1.2 选择所用芯片
    • 2.修改程序
      • 2.1 启动时间(内部时钟可不改)
      • 2.2 主频
        • 2.2.1 系统时钟配置
        • 2.2.2 108MHz宏定义
          • 第一处
          • 第二处
          • 第三处
          • 第四处
          • 第五处
        • 2.2.3 串口
        • 2.2.4 FLASH
  • 四、总结


一、前言

在一个慵懒的日子里,我因为不想花费太多时间和精力,直接将原来为STM32编写的工程进行了修改,使其适用于GD32工程。这个过程并不复杂,只需要对一些特定的代码进行替换和调整,以适应GD32的硬件架构和指令集。然而,由于我对STM32和GD32之间的差异了解不够深入,这个过程也让我犯了一些错误。最终,经过一番努力,我终于成功地将工程从STM32移植到了GD32。

经过这次移植的经历,我深刻体会到了GD32和STM32之间的差异,并积累了一定的经验。因此,我决定将这次移植的经验分享出来,希望能够帮助更多的人在面对类似移植问题时能够更加顺利地完成移植工作。

在这里插入图片描述

二、差异性

MCUSTM32F103VCT6GD32F103VCT6
内核Cortex-M3内核Cortex-M3内核
程序存储容量256KB256KB
RAM总容量48KB48KB
GPIO端口数量8080
工作电压范围2V~3.6V2.6V~3.6V
内核的供电电压1.2V1.8V
CPU最大主频72MHz108MHz
程序存储器类型FLASHFLASH
工作温度范围-40℃~+85℃-40℃~+85℃
ADC(位数)12bit12bit
DAC(位数)12bit12bit

三、软件移植部分

这里我使用的GD芯片是GD32F103VCT6,移植的程序来源自STM32F103VCT6,采用的是STM32的标准库。

1.前期准备

1.1 安装GD32固件库

进入兆易创新GD32 MCU官网下载keil支持包,下载完成后双击进行安装。
在这里插入图片描述

1.2 选择所用芯片

这里我用的是keil5,所以我选择安装 GigaDevice.GD32F10x_DFP.2.1.0 pack Keil5 在线支持包,安装完成后点击keil的魔术棒会出现GD32F10x Series。

在这里插入图片描述

最后,选择我们需要的MCU型号,前期准备工作完成,接下来开始移植程序。

在这里插入图片描述

2.修改程序

2.1 启动时间(内部时钟可不改)

HSE_STARTUP_TIMEOUT是用于定义外部高速时钟(HSE)启动的超时时间。我用的是内部时钟,所以也可以不改。

代码如下(示例):

/**
 * @brief In the following line adjust the External High Speed oscillator (HSE) Startup 
   Timeout value 
   */
#define HSE_STARTUP_TIMEOUT   ((uint16_t)0xFFFF) /*!< Time out for HSE start up */ //STM32 0x0500

2.2 主频

2.2.1 系统时钟配置

通过上面的差异性比较,我们知道GD32的最高主频为108MHZ,那么在STM32工程中要有哪些修改呢?

请接着往下看

1.在SystemClock_Config系统时钟配置函数中选择我们需要的时钟,这里用的是内部时钟HSI,有同学可能对底下这个宏定义 #define RCC_PLLMul_27 ((uint32_t)0x08280000)感到疑惑,下面就解释下。

根据官方GD32F10x User Manual 2.6版本用户手册的资料显示(中文P84-P87,英文P87-P91),要配置108MHZ,PLL时钟倍频因子需要配置为PLL源时钟x27,由于我们在RCC_PLLConfig函数选择RCC_PLLSource_HSI_Div2,HSI刚好是8MHZ,一半的HSI是4MHZ,4x27=108MHZ

PLLMF[3:0]为第21位到18位,(PLL源时钟 x 27)为11010,第一个1其实是第27位,所以时钟配置寄存器 0(RCU_CFG0)最后的值为0x0000 1000 0010 1000 XXXX(补零)=0x08280000

在这里插入图片描述
代码如下(示例):

 #define RCC_PLLMul_27                   ((uint32_t)0x08280000)
 
/*******************************************************************************
 * 函数名:SystemClock_Config
 * 描述  :系统时钟配置
 * 输入  :void
 * 输出  :void
 * 调用  :初始化
 * 备注  :
*******************************************************************************/
void SystemClock_Config(void)
{
  /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration -----------------------------*/   
  /* RCC system reset(for debug purpose) */
  RCC_DeInit();
  /* Enable HSI */
  RCC_HSICmd(ENABLE);
  /* Wait till HSI is ready */
  while (RCC_GetFlagStatus(RCC_FLAG_HSIRDY) == RESET)
  {}
  /* Enable Prefetch Buffer */
  FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
  /* Flash 2 wait state */
  FLASH_SetLatency(FLASH_Latency_2);
  /* HCLK = SYSCLK */
  RCC_HCLKConfig(RCC_SYSCLK_Div1); 
  /* PCLK2 = HCLK */
  RCC_PCLK2Config(RCC_HCLK_Div1); 
  /* PCLK1 = HCLK/2 */
  RCC_PCLK1Config(RCC_HCLK_Div2);
#ifdef STM32F10X_CL
  /* Configure PLLs *********************************************************/
  /* PLL2 configuration: PLL2CLK = (HSI / 2) * 4 = 16 MHz */
  RCC_PREDIV2Config(RCC_PREDIV2_Div2);
  RCC_PLL2Config(RCC_PLL2Mul_4);
  /* Enable PLL2 */
  RCC_PLL2Cmd(ENABLE);
  /* Wait till PLL2 is ready */
  while (RCC_GetFlagStatus(RCC_FLAG_PLL2RDY) == RESET)
  {}
  /* PLL configuration: PLLCLK = (PLL2 / 5) * 9 = 72 MHz */ 
  RCC_PREDIV1Config(RCC_PREDIV1_Source_PLL2, RCC_PREDIV1_Div5);
  RCC_PLLConfig(RCC_PLLSource_PREDIV1, RCC_PLLMul_9);
#else
  /* PLLCLK = 4MHz * 27 = 72 MHz */
  RCC_PLLConfig(RCC_PLLSource_HSI_Div2, RCC_PLLMul_27); // HSI is divided by 2 to have 4MHz then multiply by 27 to have 108MHz
#endif
  /* Enable PLL */ 
  RCC_PLLCmd(ENABLE);
  /* Wait till PLL is ready */
  while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
  {
  }
  /* Select PLL as system clock source */
  RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
  /* Wait till PLL is used as system clock source */
  while(RCC_GetSYSCLKSource() != 0x08)
  {
  }
}
2.2.2 108MHz宏定义

在system_stm32f10x.c文件中找到SYSCLK_FREQ_72MHz的位置,一共有5处,全部注释掉,并且换成SYSCLK_FREQ_108MHz。

代码如下(示例):

第一处
#if defined (STM32F10X_LD_VL) || (defined STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
/* #define SYSCLK_FREQ_HSE    HSE_VALUE */
 #define SYSCLK_FREQ_24MHz  24000000
#else
/* #define SYSCLK_FREQ_HSE    HSE_VALUE */
/* #define SYSCLK_FREQ_24MHz  24000000 */ 
/* #define SYSCLK_FREQ_36MHz  36000000 */
/* #define SYSCLK_FREQ_48MHz  48000000 */
/* #define SYSCLK_FREQ_56MHz  56000000 */
/* #define SYSCLK_FREQ_72MHz  72000000 */
   #define SYSCLK_FREQ_108MHz  108000000
#endif
第二处
/*******************************************************************************
*  Clock Definitions
*******************************************************************************/
#ifdef SYSCLK_FREQ_HSE
  uint32_t SystemCoreClock         = SYSCLK_FREQ_HSE;        /*!< System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_24MHz
  uint32_t SystemCoreClock         = SYSCLK_FREQ_24MHz;        /*!< System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_36MHz
  uint32_t SystemCoreClock         = SYSCLK_FREQ_36MHz;        /*!< System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_48MHz
  uint32_t SystemCoreClock         = SYSCLK_FREQ_48MHz;        /*!< System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_56MHz
  uint32_t SystemCoreClock         = SYSCLK_FREQ_56MHz;        /*!< System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_72MHz
  uint32_t SystemCoreClock         = SYSCLK_FREQ_72MHz;        /*!< System Clock Frequency (Core Clock) */
	#elif defined SYSCLK_FREQ_108MHz
  uint32_t SystemCoreClock         = SYSCLK_FREQ_108MHz;        /*!< System Clock Frequency (Core Clock) */
#else /*!< HSI Selected as System Clock source */
  uint32_t SystemCoreClock         = HSI_VALUE;        /*!< System Clock Frequency (Core Clock) */
#endif
第三处
#ifdef SYSCLK_FREQ_HSE
  static void SetSysClockToHSE(void);
#elif defined SYSCLK_FREQ_24MHz
  static void SetSysClockTo24(void);
#elif defined SYSCLK_FREQ_36MHz
  static void SetSysClockTo36(void);
#elif defined SYSCLK_FREQ_48MHz
  static void SetSysClockTo48(void);
#elif defined SYSCLK_FREQ_56MHz
  static void SetSysClockTo56(void);  
#elif defined SYSCLK_FREQ_72MHz
  static void SetSysClockTo72(void);
#elif defined SYSCLK_FREQ_108MHz
  static void SetSysClockTo108(void);	
#endif
第四处
/**
  * @brief  Configures the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers.
  * @param  None
  * @retval None
  */
static void SetSysClock(void)
{
#ifdef SYSCLK_FREQ_HSE
  SetSysClockToHSE();
#elif defined SYSCLK_FREQ_24MHz
  SetSysClockTo24();
#elif defined SYSCLK_FREQ_36MHz
  SetSysClockTo36();
#elif defined SYSCLK_FREQ_48MHz
  SetSysClockTo48();
#elif defined SYSCLK_FREQ_56MHz
  SetSysClockTo56();  
#elif defined SYSCLK_FREQ_72MHz
  SetSysClockTo72();
#elif defined SYSCLK_FREQ_108MHz
  SetSysClockTo108();
#endif 
}
第五处
#elif defined SYSCLK_FREQ_108MHz
/**
  * @brief  Sets System clock frequency to 72MHz and configure HCLK, PCLK2 
  *         and PCLK1 prescalers. 
  * @note   This function should be used only after reset.
  * @param  None
  * @retval None
  */
static void SetSysClockTo108(void)
{
  __IO uint32_t StartUpCounter = 0, HSEStatus = 0;  
  /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/    
  /* Enable HSE */    
  RCC->CR |= ((uint32_t)RCC_CR_HSEON); 
  /* Wait till HSE is ready and if Time out is reached exit */
  do
  {
    HSEStatus = RCC->CR & RCC_CR_HSERDY;
    StartUpCounter++;  
  } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
  if ((RCC->CR & RCC_CR_HSERDY) != RESET)
  {
    HSEStatus = (uint32_t)0x01;
  }
  else
  {
    HSEStatus = (uint32_t)0x00;
  }  
  if (HSEStatus == (uint32_t)0x01)
  {
    /* 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/2 */
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;
#ifdef STM32F10X_CL
    /* Configure PLLs ------------------------------------------------------*/
    /* PLL2 configuration: PLL2CLK = (HSE / 5) * 8 = 40 MHz */
    /* PREDIV1 configuration: PREDIV1CLK = PLL2 / 5 = 8 MHz */        
    RCC->CFGR2 &= (uint32_t)~(RCC_CFGR2_PREDIV2 | RCC_CFGR2_PLL2MUL |
                              RCC_CFGR2_PREDIV1 | RCC_CFGR2_PREDIV1SRC);
    RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 |
                             RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5);  
    /* Enable PLL2 */
    RCC->CR |= RCC_CR_PLL2ON;
    /* Wait till PLL2 is ready */
    while((RCC->CR & RCC_CR_PLL2RDY) == 0)
    {
    }    
    /* PLL configuration: PLLCLK = PREDIV1 * 9 = 72 MHz */ 
    RCC->CFGR &= (uint32_t)~(RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL);
    RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 | 
                            RCC_CFGR_PLLMULL9); 
#else    
    /*  PLL configuration: PLLCLK = HSE/2 * 27 = 108 MHz */
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |
                                        RCC_CFGR_PLLMULL));
    RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSI_Div2 | RCC_CFGR_PLLMULL27);
#endif /* STM32F10X_CL */

    /* 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)
    {
    }
  }
  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 */
  }
}
#endif
2.2.3 串口

一开始我改完时钟108MHZ,试了串口,然后发现乱码,后面查了资料,才知道在stm32f10x_rcc.c文件中RCC_GetClocksFreq函数要新增以下代码。

if(RCC->CFGR & 0x08000000)这行代码用于检查RCC->CFGR寄存器中特定位(第27位)的值。如果该位为1,就会执行pllmull += 15;,即将pllmull变量的值增加15,变成27倍频刚好对赢上面的108MHZ。

代码如下(示例):

/**
  * @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;
      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 */          
          /* Get PREDIV2 division factor and PLL2 multiplication factor */
          prediv2factor = ((RCC->CFGR2 & CFGR2_PREDIV2) >> 4) + 1;
          pll2mull = ((RCC->CFGR2 & CFGR2_PLL2MUL) >> 8 ) + 2; 
          RCC_Clocks->SYSCLK_Frequency = (((HSE_VALUE / prediv2factor) * pll2mull) / prediv1factor) * pllmull;                         
        }
      }
#endif /* STM32F10X_CL */ 
      break;
    default:
      RCC_Clocks->SYSCLK_Frequency = HSI_VALUE;
      break;
  }
  /* Compute HCLK, PCLK1, PCLK2 and ADCCLK clocks frequencies ----------------*/
  /* Get HCLK prescaler */
  tmp = RCC->CFGR & CFGR_HPRE_Set_Mask;
  tmp = tmp >> 4;
  presc = APBAHBPrescTable[tmp];
  /* HCLK clock frequency */
  RCC_Clocks->HCLK_Frequency = RCC_Clocks->SYSCLK_Frequency >> presc;
  /* Get PCLK1 prescaler */
  tmp = RCC->CFGR & CFGR_PPRE1_Set_Mask;
  tmp = tmp >> 8;
  presc = APBAHBPrescTable[tmp];
  /* PCLK1 clock frequency */
  RCC_Clocks->PCLK1_Frequency = RCC_Clocks->HCLK_Frequency >> presc;
  /* Get PCLK2 prescaler */
  tmp = RCC->CFGR & CFGR_PPRE2_Set_Mask;
  tmp = tmp >> 11;
  presc = APBAHBPrescTable[tmp];
  /* PCLK2 clock frequency */
  RCC_Clocks->PCLK2_Frequency = RCC_Clocks->HCLK_Frequency >> presc;
  /* Get ADCCLK prescaler */
  tmp = RCC->CFGR & CFGR_ADCPRE_Set_Mask;
  tmp = tmp >> 14;
  presc = ADCPrescTable[tmp];
  /* ADCCLK clock frequency */
  RCC_Clocks->ADCCLK_Frequency = RCC_Clocks->PCLK2_Frequency / presc;
}
2.2.4 FLASH

因为GD的Flash是自己的专利技术,而ST的Flash则是由第三方提供的,所以,当进行Flash取值操作时,GD32F10X芯片可以达到零等待周期的响应时间,而ST芯片则需要等待两个周期。另一方面,GD芯片的Flash擦除和编程时间可能会比ST芯片长一些。

所以针对这个不同需要增加两个空循环__NOP();指令进行等待。

代码如下(示例):

/**
  * @brief  Erases the FLASH option bytes.
  * @note   This functions erases all option bytes except the Read protection (RDP). 
  * @note   This function can be used for all STM32F10x devices.
  * @param  None
  * @retval FLASH Status: The returned value can be: FLASH_ERROR_PG,
  *         FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT.
  */
FLASH_Status FLASH_EraseOptionBytes(void)
{
  uint16_t rdptmp = RDP_Key;
  FLASH_Status status = FLASH_COMPLETE;
  /* Get the actual read protection Option Byte value */ 
  if(FLASH_GetReadOutProtectionStatus() != RESET)
  {
    rdptmp = 0x00;  
  }
  /* Wait for last operation to be completed */
  status = FLASH_WaitForLastOperation(EraseTimeout);
  if(status == FLASH_COMPLETE)
  {
    /* Authorize the small information block programming */
    FLASH->OPTKEYR = FLASH_KEY1;
    FLASH->OPTKEYR = FLASH_KEY2;    
    __NOP();
    __NOP();    
    /* if the previous operation is completed, proceed to erase the option bytes */
    FLASH->CR |= CR_OPTER_Set;
    FLASH->CR |= CR_STRT_Set;
    /* Wait for last operation to be completed */
    status = FLASH_WaitForLastOperation(EraseTimeout);    
    if(status == FLASH_COMPLETE)
    {
      /* if the erase operation is completed, disable the OPTER Bit */
      FLASH->CR &= CR_OPTER_Reset;       
      /* Enable the Option Bytes Programming operation */
      FLASH->CR |= CR_OPTPG_Set;
      /* Restore the last read protection Option Byte value */
      OB->RDP = (uint16_t)rdptmp; 
      /* Wait for last operation to be completed */
      status = FLASH_WaitForLastOperation(ProgramTimeout);
      if(status != FLASH_TIMEOUT)
      {
        /* if the program operation is completed, disable the OPTPG Bit */
        FLASH->CR &= CR_OPTPG_Reset;
      }
    }
    else
    {
      if (status != FLASH_TIMEOUT)
      {
        /* Disable the OPTPG Bit */
        FLASH->CR &= CR_OPTPG_Reset;
      }
    }  
  }
  /* Return the erase status */
  return status;
}

除了FLASH_EraseOptionBytes函数外,还有下面三个函数也需要增加 __NOP();

FLASH_Status FLASH_ProgramOptionByteData(uint32_t Address, uint8_t Data);
FLASH_Status FLASH_EnableWriteProtection(uint32_t FLASH_Pages);
FLASH_Status FLASH_ReadOutProtection(FunctionalState NewState);

GD芯片的Flash擦除和编程时间可能会比ST芯片长一些,所以把擦除和编程时间变长些。

/* Delay definition */   
#define EraseTimeout          ((uint32_t)0x000fffff)//0x000B0000   
#define ProgramTimeout        ((uint32_t)0x0000ffff)//0x00002000

四、总结

今天是STM32到GD32的工程移植经验分享,附件是移植好的工程。感谢你的观看,谢谢!

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1326990.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

c语言错误总结

函数 A:void类型函数可以 B&#xff1a;不需要&#xff0c;如果return 不返回任何值&#xff0c;函数会在return语句执行后终止执行&#xff0c;后面的语句不会执行 C&#xff1a;对的 D&#xff1a;不可能&#xff0c;return只能返回一个数据 A:函数不一定有返回值 B:可以…

php伪协议 [NISACTF 2022]easyssrf

打开题目 我们直接用 file:/// 协议读取看看flag文件 file:///flag 点击curl得到回响 得到提示告诉我们应该看看提示文件 file:///fl4g 跟着去访问了一下 再跟着去访问 从代码中我们可以看出 get传参file&#xff0c;我们用stristr检测file参数里面是否含有file&#xff…

企业需要哪些数字化管理系统?

企业需要哪些数字化管理系统&#xff1f; ✅企业引进管理系统肯定是为了帮助整合和管理大量的数据&#xff0c;从而优化业务流程&#xff0c;提高工作效率和生产力。 ❌但是&#xff0c;如果各个系统之间不互通、无法互相关联数据的话&#xff0c;反而会增加工作量和时间成本…

Qt之QWidget 自定义倒计时器

简述 Qt提供的带进度显示的只有一个QProgresBar,这个控件要么是加载进度从0~100%,要么是持续的两边滚动;而我想要是倒计时的效果,所以QProgresBar并不满足要求,而Qt重写控件相对于MFC来说简直是轻而易举,所以就整了两种不同的倒计时控件; 效果 代码 QPushButton的绘制部…

边缘计算有哪些常用场景?TSINGSEE边缘AI视频分析技术行业解决方案

随着ChatGPT生成式人工智能的爆发&#xff0c;AI技术在业界又掀起一波新浪潮。值得关注的是&#xff0c;边缘AI智能也在AI人工智能技术进步的基础上得到了快速发展。IDC跟踪报告数据显示&#xff0c;2021年我国的边缘计算服务器整体市场规模达到33.1亿美元&#xff0c;预计2020…

2023最新版JavaSE教程——第11天:常用类和基础API

目录 一、字符串相关类之不可变字符序列&#xff1a;String1.1 String的特性1.2 String的内存结构1.2.1 概述1.2.2 练习类型1&#xff1a;拼接1.2.3 练习类型2&#xff1a;new1.2.4 练习类型3&#xff1a;intern() 1.3 String的常用API-11.3.1 构造器1.3.2 String与其他结构间的…

Spring统一数据返回格式处理String类型出错解析

Spring 统一数据返回格式是使用 Spring 进行开发时很常用的一个功能&#xff0c;但是当其处理返回类型原先为 String 类型的时候就会出错报错&#xff0c;需要我们额外对 String 类型进行处理。 例如&#xff1a;现在我开发一个项目&#xff0c;项目中我想要统一返回下述的 Res…

作业--day35

练习数据库命令 1> 创建一个工人信息库&#xff0c;包含工号&#xff08;主键&#xff09;、姓名、年龄、薪资&#xff1b; 2> 添加三条工人信息&#xff08;可以完整信息&#xff0c;也可以非完整信息&#xff09;&#xff1b; 3> 修改某一个工人的薪资&#xff08;…

深度学习14—注意力机制与自注意力机制

注&#xff1a;以下均为个人学习笔记&#xff0c;发布只为方便学习阅读&#xff0c;若觉侵权&#xff0c;请联系删除&#xff01;&#xff01; 1.李沐老师课堂学习理解笔记 1.1 随意线索和不随意线索 1.2 注意力机制 通过注意力池化层来有偏向性的选择某些输入。 1.3 注意力…

【QT】C++/Qt使用Qt自带工具windeployqt打包

基本操作 运行项目debug或者release 将运行后的可执行文件单独放到一个文件夹中 根据项目使用的kits来选择Qt的打包工具 打开工具后移动到exe文件夹下执行windeployqt xxx.exe 预览图 问题 打包后再其他电脑上运行出现下图错误 将自己电脑的这个文件拷到可执行文件夹中既…

构建高效持久层:深度解析 MyBatis-Plus(02)

目录 引言1. 逻辑删除1.1 概述1.2 逻辑删除的优势1.3.为什么使用逻辑删除1.4 综合案例 2. 乐观锁和悲观锁2.1.什么是乐观锁和悲观锁2.2.乐观锁和悲观锁的区别2.3.综合案例 3. 分页插件总结 引言 在现代软件开发中&#xff0c;数据库操作是不可或缺的一环。为了提高系统的性能、…

网络通信day5作业

1> 使用select完成TCP客户端程序 客户端: #include<myhead.h>#define FPORT 9999 #define FIP "192.168.125.130"#define KPORT 6666 #define KIP "192.168.125.130"int main(int argc, const char *argv[]) {//创建套接字文件描述符int cfd…

关于EasyExcel 合并单元格方法该如何实现

在做一个业务的导出&#xff0c;目前遇到一个需求&#xff0c;如下图&#xff1a; import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.Head; import com.alibaba.excel.write.handler.CellWriteHandler; import com.alibaba.excel.write.metad…

美好蕴育润康真的对孕妇好吗?有效吗?

在孕期&#xff0c;孕妇的营养摄入对于胎儿的健康发育至关重要。因此&#xff0c;选择一款合适的孕期营养补充品成为了许多孕妇关注的焦点。美好蕴育润康作为一款备受推崇的孕期营养补充品&#xff0c;究竟是否真的对孕妇有益&#xff0c;是否有效呢&#xff1f; 首先&#xff…

数据治理与大模型一体化实践

引言: 大模型落地到当前这个阶段&#xff0c;核心关注点还是领域大模型&#xff0c;而领域大模型落地的前提在于两点&#xff1a;需求端&#xff0c;对当前应用的降本增效以及新应用的探索&#xff1b;供给端&#xff0c;训练技术已经有较高的成熟度。 专家介绍&#xff1a; …

【C语言】指针详解(一)

目录 1.内存和地址 1.1内存 1.2如何理解编址 2.指针变量和地址 2.1取地址操作符&#xff08;&&#xff09; 2.2指针变量和解引用操作符&#xff08;*&#xff09; 2.2.1指针变量 2.2.2拆解指针类型 2.2.3解引用操作符 2.3指针变量大小 1.内存和地址 1.1内存 在讲内…

HarmonyOS引导页登陆页以及tabbar的代码说明1

效果 以下代码是东拼西凑出来的。只是为了个人熟悉一下相关模块的使用&#xff1a; 用的知识点&#xff1a; Resouces 此部分分内容可以在项目中找到&#xff1a; resources/base/element/color.json 为项目着色配置&#xff0c;当然也可以正接在代码里写 float.json 为相关…

如何实现免费无限流量云同步笔记软件Obsidian?

目录 前言 如何实现免费无限流量云同步笔记软件Obsidian&#xff1f; 一、简介 软件特色演示&#xff1a; 二、使用免费群晖虚拟机搭建群晖Synology Drive服务&#xff0c;实现局域网同步 1 安装并设置Synology Drive套件 2 局域网内同步文件测试 三、内网穿透群晖Synol…

上海三思立体育苗系统Vertical X打造“不见光”人工农场

最早的人工育苗可追溯到农耕文明的起源。 人类通过筛选种子、选择播种时机和使用肥料等方式&#xff0c;达到提升产量的效果。随着农业技术发展&#xff0c;育苗床和育苗盆等工具的出现&#xff0c;育苗系统初见雏形。 现代温室育苗技术的应用&#xff0c;给育苗提供了相对更…

为Raspberry Pi OS(Bookworm)设置固定IP

新版的RPI OS采用NetworkManager管理网络&#xff0c;之前/etc/dhcpcd.conf默认找不见了。不过&#xff0c;我们可以使用命令行进行。以我的WIFI为例&#xff0c;演示下如何设置固定IP。 第一步&#xff0c;找到WIFI的内部名称&#xff1a; sudo nmcli -p connection show 注…