打印

GD32替换STM32移植过程

[复制链接]
2077|23
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
慢醇|  楼主 | 2022-1-24 17:03 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
1. 硬件芯片移植
下面以 GD32F103RET6 替换 STM32F103RET6为例

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



使用特权

评论回复
沙发
慢醇|  楼主 | 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芯片的启动时间存在差异,需要对下面参数进行修改
搜索以下代码
#define HSE_STARTUP_TIMEOUT ((uint16_t)0x0500)
修改为:
#define HSE_STARTUP_TIMEOUT ((uint16_t)0xFFFF)

使用特权

评论回复
5
慢醇|  楼主 | 2022-1-25 15:18 | 只看该作者
2.2 增加DMA功能

下面以串口3为例

GD32替换STM32的最大问题就是串口收发问题,经常出现丢数据异常,使用DMA处理串口数据,可有效解决该问题。

使用特权

评论回复
6
慢醇|  楼主 | 2022-1-25 15:23 | 只看该作者
串口3与DMA初始化函数
#define USE_USART3_DMA_RX        1
char Usart3data[200];
u8 Usart3flag =0;
u8 usart3Count=0;

void USART3_Configuration(u32 BaudRate)      
{

    USART_InitTypeDef USART_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
                DMA_InitTypeDef DMA_InitStruct;       
       
    //打开usart3要使用的时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE);

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

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

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

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

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

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

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

    USART_DMACmd(USART3, USART_DMAReq_Rx, ENABLE);//开启串口DMA接收
    DMA_Cmd(DMA1_Channel3, ENABLE);     // 使能DMA通道               
#else
    USART_ITConfig(USART3, USART_IT_RXNE, ENABLE); // 开启串口接收中断       
#endif
//                USART_ClearFlag(USART3, USART_FLAG_TC);     /* 清除标志避免第一个字符丢失 */        // 使用GD32时,发送第一个数据前不要清除 USART_FLAG_TC(发送完成标志位)
    USART_Cmd(USART3, ENABLE);                  //使能串口
}

使用特权

评论回复
7
慢醇|  楼主 | 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);//等待发送结束
        }
}

使用特权

评论回复
8
慢醇|  楼主 | 2022-1-25 15:25 | 只看该作者
main函数
int main()
{

... //省略代码

    while(1)
    {
                                ... //省略代码
        if(Usart3flag==1) //接收完成
        {
                                                port_Index=3;
              CheckUartCmd(Usart3data);
                                                Usart3flag=0;
                                                memset(Usart3data,'\0',sizeof(Usart3data));//清空接收缓冲区
                                                DMA1_Channel3->CCR&=~(1<<0);                //关闭DMA接受中断
                                                DMA1_Channel3->CNDTR=sizeof(Usart3data);  //清空DMA数据计数器,重新计数下一帧数据
                                                DMA1_Channel3->CCR|=1<<0;  
                                                usart3Count=0;
        }
    }
}

使用特权

评论回复
9
gdszzyq| | 2022-2-6 17:24 | 只看该作者
慢醇 发表于 2022-1-25 15:17
由于GD芯片与ST芯片的启动时间存在差异,需要对下面参数进行修改

请教外部晶振起振超时时间起什么作用?如果我把超时时间都设置成0XFFFF在ST芯片下运行有没有什么问题,如果没问题那就可以替代了

使用特权

评论回复
10
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);
}

使用特权

评论回复
11
gdszzyq| | 2022-2-6 18:00 | 只看该作者
请问楼主我用的是STM32F103VBT6这个芯片,如果用GD32F103VBT6替换,除了要改变HSE_STARTUP_TIMEOUT这个参数外,还有没有其它问题,我是想直接用原来ST的程序,把这个参数都改成0XFFFF,两种芯片都用同一个程序,这样行不行,我用到串口,定时器的比较功能,PVD,FLASH,ADC,谢谢指教!

使用特权

评论回复
12
plsbackup| | 2022-2-13 09:37 | 只看该作者
gd32f103用stm32的库使用usb的时候需要修改哪些代码

使用特权

评论回复
13
gygp| | 2022-2-13 10:03 | 只看该作者
8MHZ晶振变成12MHZ可不可以把主频变成108

使用特权

评论回复
14
modesty3jonah| | 2022-2-13 13:17 | 只看该作者
GD32系列兼容STM32一系列吗?

使用特权

评论回复
15
hudi008| | 2022-2-13 13:26 | 只看该作者
gd32f130对应哪一块stm32

使用特权

评论回复
16
quickman| | 2022-2-13 13:35 | 只看该作者
stm32生成的程序能直接烧录在gd32上吗

使用特权

评论回复
17
kkzz| | 2022-2-13 13:44 | 只看该作者
GD32F130C8真的可以兼容ST的吗

使用特权

评论回复
18
fentianyou| | 2022-2-13 13:53 | 只看该作者
可以替代兼容STM32的吗

使用特权

评论回复
19
lihuami| | 2022-2-13 14:02 | 只看该作者
硬件I2C 到底是不是个坑

使用特权

评论回复
20
suzhanhua| | 2022-2-13 14:11 | 只看该作者
GD32F103VBT6支持FSMC功能吗?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

128

主题

1263

帖子

5

粉丝