GD32替换STM32移植过程

[复制链接]
2566|23
 楼主| 慢醇 发表于 2022-1-24 17:03 | 显示全部楼层 |阅读模式
1. 硬件芯片移植
下面以 GD32F103RET6 替换 STM32F103RET6为例

硬件上使用对应的GD32芯片替换STM32,如使用 GD32F103RET6 替换 STM32F103RET6,其引脚数与引脚定义都是一样的
到兆易创新官网 - 资料下载 - 对应系列芯片 - 应用软件 - 找到GD32F1x0_Addon_V3.1.0.rar,解压安装

6838261ee6b5c5fd1c.png

 楼主| 慢醇 发表于 2022-1-24 17:05 | 显示全部楼层
3. 更换算法文件(.FLM)到Keil 的Flash文件夹中(Keil_v5\ARM\Flash)
资源下载:GD32F10xxx Keil IDE Config.rar
 楼主| 慢醇 发表于 2022-1-25 15:15 | 显示全部楼层
2. 软件配置
2.1 修改外部晶振起振超时时间
不用外部晶振可跳过此步
 楼主| 慢醇 发表于 2022-1-25 15:17 | 显示全部楼层
由于GD芯片与ST芯片的启动时间存在差异,需要对下面参数进行修改
  1. 搜索以下代码
  2. #define HSE_STARTUP_TIMEOUT ((uint16_t)0x0500)
  3. 修改为:
  4. #define HSE_STARTUP_TIMEOUT ((uint16_t)0xFFFF)

 楼主| 慢醇 发表于 2022-1-25 15:18 | 显示全部楼层
2.2 增加DMA功能

下面以串口3为例

GD32替换STM32的最大问题就是串口收发问题,经常出现丢数据异常,使用DMA处理串口数据,可有效解决该问题。
 楼主| 慢醇 发表于 2022-1-25 15:23 | 显示全部楼层
串口3与DMA初始化函数
  1. #define USE_USART3_DMA_RX        1
  2. char Usart3data[200];
  3. u8 Usart3flag =0;
  4. u8 usart3Count=0;

  5. void USART3_Configuration(u32 BaudRate)      
  6. {

  7.     USART_InitTypeDef USART_InitStructure;
  8.     GPIO_InitTypeDef GPIO_InitStructure;
  9.     NVIC_InitTypeDef NVIC_InitStructure;
  10.                 DMA_InitTypeDef DMA_InitStruct;       
  11.        
  12.     //打开usart3要使用的时钟
  13.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
  14.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE);

  15.     //配置串口TX作为推挽复用端口
  16.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
  17.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  18.     GPIO_InitStructure.GPIO_Mode =  GPIO_Mode_AF_PP;
  19.     GPIO_Init(GPIOB, &GPIO_InitStructure);

  20.     //配置串口RX作为浮空输入
  21.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
  22.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  23.     GPIO_InitStructure.GPIO_Mode =  GPIO_Mode_IN_FLOATING;
  24.     GPIO_Init(GPIOB, &GPIO_InitStructure);

  25.     //配置NVIC
  26.     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);  //一个抢占优先级,3个从优先级
  27.     NVIC_InitStructure.NVIC_IRQChannel =USART3_IRQn; //和库函数手册不一样
  28.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;     //主优先级
  29.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;            //从优先级
  30.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能中断通道
  31.     NVIC_Init(&NVIC_InitStructure);

  32.     //配置USART
  33.     USART_InitStructure.USART_BaudRate = BaudRate;        //波特率
  34.     USART_InitStructure.USART_WordLength = USART_WordLength_8b;        //数据位
  35.     USART_InitStructure.USART_StopBits = USART_StopBits_1;        //停止位
  36.     USART_InitStructure.USART_Parity = USART_Parity_No;        //奇偶校验
  37.     USART_InitStructure.USART_HardwareFlowControl =USART_HardwareFlowControl_None;         //数据流控制
  38.     USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;        //模式
  39.     USART_Init(USART3, &USART_InitStructure);        //写入结构体
  40. //    USART_Cmd(USART3, ENABLE);  //使能usart3

  41.     USART_ITConfig(USART3,USART_IT_PE,ENABLE);
  42.     USART_ITConfig(USART3, USART_IT_RXNE,ENABLE);   //打开usart3的接收中断
  43.     USART_ClearFlag(USART3,USART_IT_RXNE);          //清除中断标志
  44. //    USART_ClearFlag(USART3, USART_FLAG_TC);     // 清标志
  45.                

  46. /********************************以下是对DMA的参数初始化**********************************/
  47. #if USE_USART3_DMA_RX               
  48.           USART_ITConfig(USART3, USART_IT_IDLE, ENABLE); // 开启串口3空闲中断                
  49.                 DMA_DeInit(DMA1_Channel3);
  50.                 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);  // DMA1时钟初始化
  51.    
  52.     // RX DMA1 ??5
  53.     DMA_InitStruct.DMA_BufferSize = sizeof(Usart3data);                              // 传输的数据大小
  54.     DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC;                                    // 外设作为数据的来源
  55.     DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;                                          // 不使能M TO M传输
  56.     DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)Usart3data;                        // 设置DMA源地址:串口数据寄存器
  57.     DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;                // 内存数据单元
  58.     DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;                        // 外设地址不增
  59.     DMA_InitStruct.DMA_Mode = DMA_Mode_Normal;                                  // DMA模式一次或者循环模式
  60.                 //DMA_InitStruct.DMA_Mode = DMA_Mode_Circular;                              // DMA模式一次或者循环模式
  61.     DMA_InitStruct.DMA_PeripheralBaseAddr = USART3_BASE + 0x04;                 // 设置DMA源地址:串口数据寄存器地址
  62.     DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;    // 外设数据单元
  63.     DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;   // 外设地址不增加
  64.     DMA_InitStruct.DMA_Priority = DMA_Priority_High;                            // 优先级为中

  65.     // 配置DMA通道     
  66.     DMA_Init(DMA1_Channel3, &DMA_InitStruct);     
  67.     // 清除DMA所有标志
  68.     DMA_ClearFlag(DMA1_FLAG_TC3);
  69.     DMA_ITConfig(DMA1_Channel3, DMA_IT_TE,ENABLE);

  70.     USART_DMACmd(USART3, USART_DMAReq_Rx, ENABLE);//开启串口DMA接收
  71.     DMA_Cmd(DMA1_Channel3, ENABLE);     // 使能DMA通道               
  72. #else
  73.     USART_ITConfig(USART3, USART_IT_RXNE, ENABLE); // 开启串口接收中断       
  74. #endif
  75. //                USART_ClearFlag(USART3, USART_FLAG_TC);     /* 清除标志避免第一个字符丢失 */        // 使用GD32时,发送第一个数据前不要清除 USART_FLAG_TC(发送完成标志位)
  76.     USART_Cmd(USART3, ENABLE);                  //使能串口
  77. }
 楼主| 慢醇 发表于 2022-1-25 15:24 | 显示全部楼层
串口3中断服务函数
void USART3_IRQHandler(void)                        //串口1中断服务程序
{
        u8 Res;
       
#if USE_USART3_DMA_RX       
        if(USART_GetITStatus(USART3, USART_IT_IDLE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)    读取接收中断标志位后自动清零接收中断标志位
        {      
                        Receice_DataPack(3);
                        Res = USART3->SR;
                        Res = USART3->DR;
        }
#else
#endif
}

#define USART_RX_BUFF_SIZE 200
void Receice_DataPack(uint8_t channel)
{
        //接收到的数据长度
        uint32_t buff_length;
        u32 i;
        static uint8_t byteindex = 0;
        switch(channel)
        {
                case 3:
                {
                                //获取这一帧数据个数
                                buff_length = USART_RX_BUFF_SIZE - DMA_GetCurrDataCounter(DMA1_Channel3);
                               
                                for(;byteindex < buff_length;byteindex++)
                                {
                                       
                                        Putch(USART3,Usart3data[byteindex]);
                                }//回显处理
                                byteindex = buff_length;
                                if(Usart3data[buff_length-1] == '\r' ||Usart3data[buff_length-1] == '\n') //接收到了一帧完整的命令
                                {
                                        Usart3flag = 1;//接收到空行的命令
                                        Putch(USART3,'\n');//MAC下不发送新行会覆盖输入
                                        byteindex = 0;
                                        if(Usart3data[buff_length-1] == '\n' || Usart3data[buff_length-1] == '\r')//去掉接受数据中尾部的回车换行符
                                        {
                                                Usart3data[buff_length-1] = 0;
                                        }
                                        if(Usart3data[buff_length-2] == '\r')
                                        {
                                                Usart3data[buff_length-2] = 0;
                                        }
                                        return;
                                }
                                if(buff_length >= 50)
                                {
                                        byteindex = 0;
                                        DMA1_Channel3->CCR&=~(1<<0);                //关闭DMA接受中断               
                                        DMA1_Channel3->CNDTR=USART_RX_BUFF_SIZE;  //清空DMA数据计数器,重新计数下一帧数据                       
                                        DMA1_Channel3->CCR|=1<<0;                        
                                }                       
                        break;                       
                }
                default: break;
                }

}

void  Putch(USART_TypeDef* USARTx,u8 k) // 回显函数
{
        if(k == '\n')
        {
                USART_SendData(USARTx,'\r');
                while(USART_GetFlagStatus(USARTx,USART_FLAG_TC)!=SET);//等待发送结束
                USART_SendData(USARTx,'\n');
                while(USART_GetFlagStatus(USARTx,USART_FLAG_TC)!=SET);//等待发送结束
        }
        else if(k == '\b')//接收到
        {
                USART_SendData(USARTx,'\b');
                while(USART_GetFlagStatus(USARTx,USART_FLAG_TC)!=SET);//等待发送结束
                USART_SendData(USARTx,' ');
                while(USART_GetFlagStatus(USARTx,USART_FLAG_TC)!=SET);//等待发送结束
                USART_SendData(USARTx,'\b');
                while(USART_GetFlagStatus(USARTx,USART_FLAG_TC)!=SET);//等待发送结束               
        }
        else
        {
                while(USART_GetFlagStatus(USARTx,USART_FLAG_TC)!=SET);//等待发送结束
                USART_SendData(USARTx,k);
                //while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);//等待发送结束
        }
}

 楼主| 慢醇 发表于 2022-1-25 15:25 | 显示全部楼层
main函数
  1. int main()
  2. {

  3. ... //省略代码

  4.     while(1)
  5.     {
  6.                                 ... //省略代码
  7.         if(Usart3flag==1) //接收完成
  8.         {
  9.                                                 port_Index=3;
  10.               CheckUartCmd(Usart3data);
  11.                                                 Usart3flag=0;
  12.                                                 memset(Usart3data,'\0',sizeof(Usart3data));//清空接收缓冲区
  13.                                                 DMA1_Channel3->CCR&=~(1<<0);                //关闭DMA接受中断
  14.                                                 DMA1_Channel3->CNDTR=sizeof(Usart3data);  //清空DMA数据计数器,重新计数下一帧数据
  15.                                                 DMA1_Channel3->CCR|=1<<0;  
  16.                                                 usart3Count=0;
  17.         }
  18.     }
  19. }
gdszzyq 发表于 2022-2-6 17:24 | 显示全部楼层
慢醇 发表于 2022-1-25 15:17
由于GD芯片与ST芯片的启动时间存在差异,需要对下面参数进行修改

请教外部晶振起振超时时间起什么作用?如果我把超时时间都设置成0XFFFF在ST芯片下运行有没有什么问题,如果没问题那就可以替代了
gdszzyq 发表于 2022-2-6 17:54 | 显示全部楼层
ST的HSE_STARTUP_TIMEOUT这个参数是0x0500,如果我把它设成0XFFFF有没有问题呢?我看了下用到这个参数的函数以下这几个:RCC_WaitForHSEStartUp(void),SetSysClockToHSE(void),void SetSysClockTo24(void),void SetSysClockTo36(void)....我查了下我只用到RCC_WaitForHSEStartUp(void)这个函数,判断外部时钟是否正常,不正常则启用内部时钟。而看了这个函数把HSE_STARTUP_TIMEOUT设大好象没问题,最多就是如果外部时钟故障等待时间长了点而已,请问还有其它问题吗?附上这个函数。
ErrorStatus RCC_WaitForHSEStartUp(void)
{
  __IO uint32_t StartUpCounter = 0;
  ErrorStatus status = ERROR;
  FlagStatus HSEStatus = RESET;
  
  /* Wait till HSE is ready and if Time out is reached exit */
  do
  {
    HSEStatus = RCC_GetFlagStatus(RCC_FLAG_HSERDY);
    StartUpCounter++;  
  } while((StartUpCounter != HSE_STARTUP_TIMEOUT) && (HSEStatus == RESET));
  
  if (RCC_GetFlagStatus(RCC_FLAG_HSERDY) != RESET)
  {
    status = SUCCESS;
  }
  else
  {
    status = ERROR;
  }  
  return (status);
}
gdszzyq 发表于 2022-2-6 18:00 | 显示全部楼层
请问楼主我用的是STM32F103VBT6这个芯片,如果用GD32F103VBT6替换,除了要改变HSE_STARTUP_TIMEOUT这个参数外,还有没有其它问题,我是想直接用原来ST的程序,把这个参数都改成0XFFFF,两种芯片都用同一个程序,这样行不行,我用到串口,定时器的比较功能,PVD,FLASH,ADC,谢谢指教!
plsbackup 发表于 2022-2-13 09:37 | 显示全部楼层
gd32f103用stm32的库使用usb的时候需要修改哪些代码
gygp 发表于 2022-2-13 10:03 | 显示全部楼层
8MHZ晶振变成12MHZ可不可以把主频变成108
modesty3jonah 发表于 2022-2-13 13:17 | 显示全部楼层
GD32系列兼容STM32一系列吗?
hudi008 发表于 2022-2-13 13:26 | 显示全部楼层
gd32f130对应哪一块stm32
quickman 发表于 2022-2-13 13:35 | 显示全部楼层
stm32生成的程序能直接烧录在gd32上吗
kkzz 发表于 2022-2-13 13:44 | 显示全部楼层
GD32F130C8真的可以兼容ST的吗
fentianyou 发表于 2022-2-13 13:53 | 显示全部楼层
可以替代兼容STM32的吗
lihuami 发表于 2022-2-13 14:02 | 显示全部楼层
硬件I2C 到底是不是个坑
suzhanhua 发表于 2022-2-13 14:11 | 显示全部楼层
GD32F103VBT6支持FSMC功能吗?
您需要登录后才可以回帖 登录 | 注册

本版积分规则

134

主题

1382

帖子

6

粉丝
快速回复 在线客服 返回列表 返回顶部