GD32 介绍与 STM32 兼容性总结
一、 GD32 与 STM32 异同
1. 相同点
- 外围引脚定义: 同型号管脚定义相同
- Cortex M3 内核: STM32F103 内核 R1P1 版本,STM32F205 内核 R2P1, GD32 内核 R2P1 版本,内核修复 R1P1 的一些 bug
- 芯片内部寄存器, 外部 IP 寄存器地址 : 逻辑地址相同,主要基于 STM寄存器和物理地址, 正向研发.
- 函数库文件: 函数库相同
- 编译工具: 完全相同,如:keil MDK、IAR
- 型号命名方式: 完全相同
2. 外围硬件差异
- 电压范围(ADC): GD32F: 2.6-3.6V STM32F: 2.0-3.6V(外部电压) GD32F: 1.2V(内核电压)STM32F: 1.8V(内核电压)
- BOOT 管脚: Flash 程序运行时,BOOT0 在 STM32 上可悬空,GD32 必须外 下拉(从 Flash 运行,BOOT0 必须下拉地)
- ESD 参数: STM32 人体模式 2KV,空气模式 500V GD32 人体模式 4KV(内测 5KV),空气模式 10KV(内测 15KV)
3. 内部结构差异
- 启动时间: GD32 启动时间相同,因为 GD 运行稍快,需要延长上电时间 配置(2ms)
- 主频时钟: GD32F10 系列主频 1088MHZ STM32F10 系列主频 722MHZ
- Flash 擦除时间: GD32 是 60ms/page,STM 30ms/page
- FLASH 容量: GD32 最大容量 3M Byte
- SRAM 空间: GD32F103 系列、GD32F105\107SRAM 96K
- VB 外扩总线 FSMC:GD32 100PIN 配置总线输出,STM32 144PIN 并且 256k 以上 才配置总线输出
4. 功耗差异(以 128k 以下容量的作为参考)
- 睡眠模式 Sleep: GD32F: 12.4mA STM32F10X: 7.5mA
- 深度睡眠模式 Deep Sleep: GD32F: 1.4mA STM32F10X: 24uA
- 待机模式 Stand By: GD32F: 10.5uA STM32F10X: 3.4uA
- 运行功耗: GD32F: 32.4mA/72M STM32F10X: 52mA/72M
5. 内部 FLASH 区别
- ISP: 擦写时间相同STM32 不同,使用新版 ISP 软件
- IAP: 擦写时间相同,按字写入,按页擦除
- 存储寿命: 擦写10万次,数据保存 20年以上
- 加密特性: 除常规禁止读取和 96 位ID 除加密号码外,GD32 数据写入 Flash 具有连续存储逻辑地址和不连续物理地址的特点。
二、 GD32 介绍与兼容性分析
1. 系统
-
晶振振动的差异 描述 启动时间,GD32 与 STM32 启动时间为 22ms,实际上 GD 执行效率快,所 以 ST 的 HSE_STARTUP_TIMEOUT ((uint16_t)0x0500)是 2ms,但这个宏定义值 在 GD 时间更短,因此应增加此值的设置 解决方案 宏定义: #define HSE_STARTUP_TIMEOUT ((uint16_t)0x0500) 修改为: #define HSE_STARTUP_TIMEOUT ((uint16_t)0xFFFF) 注启动时间宏定义位置: 1、在 V3.X 的启动时间宏定义为 stm32f10x.h 头文件中 (路径:…\Libraries\CMSIS\CM3)。(库版本不同,目录也不同) 2、在 V3.0 以前的库,其启动时间宏定义在 stm32f10x_rcc.c 源文件中 (HSEStartUp_TimeOut) (路径:…\Libraries\STM32F10x_StdPeriph_Driver\src)。
-
有些客户使用有源晶振有问题GD32F发现103 小容量产品会在 MCU 的复 管脚一直把电平拉到 0.89V,电平不能保持在高电平 描述 是由于部分有源晶振动时间过快,复位信号尚未完成 解决方案 是在有源晶振的输入端和地面之前进行 30pf 电容
-
GD32 MCU 主频支持 108MHz 高性能,代码移植需要注意 描述 GD32 通过芯片内部增加缓存,提高了相同工作频率下的代码执行速度 高性能使用体验。 因此,如果代码有用, for 循环或 while 循环句准确定时,定时时间由 加快代码执行速度,缩短循环时间。Timer 定时器没有影响。
-
GD32F105/107 系列 MCU 配置为 108MHz 有何不同 通过 描述 Clock configuration register (RCC_CFGR) 中 PLLMUL[3:0],再结合第 29 位 PLLMUL[4]确定 5 位的位置PLL 倍频 系数,即通过软件配置定义 PLL 倍频系数, PLL 绝对没有输出频率 超过最高主频(108MHz)。
2. 内部 Flash
- 读保护用法设置芯片 描述 因 GD 的 Flash 是自己的专利技术,STM 的 Flash 是第三方提供的,所以 GD 的 Flash 和 STM 的 Flash 有一些差异。GD 的擦拭时间会长一点 解决方法 KEY 序列后,需要要阅读该位置并确认 key 已生效。 所以这里应该插入 While( ! (FLASH->CR & 0x / / Wait OPTWRE 或者可以简单插入 两个 NOP。 __NOP(); __NOP(); 在 ST 库,只有 FLASH_Status FLASH_EraseOptionBytes(void) FLASH_Status FLASH_ProgramOptionByteData(uint32_t Address,uint8_t Data) FLASH_Status FLASH_EnableWriteProtection(uint32_t FLASH_Pages) FLASH_Status FLASH_ReadOutProtection(FunctionalState NewState) 需要修改四个函数。
- IAP 在应用中编程 描述 GD由于自有 ,32 flash 0 访问顺序与 相同STM32 在 Flash 的 Erase 和 Program 上 有差异,GD32 的 Erase 和 Program 时间比 STM32 稍长,建议 Erase 和 Program 修改时间。 解决方法 #define EraseTimeout ((uint32_t)0x000B0000) #define ProgramTimeout ((uint32_t)0x00002000) 修改为: #define EraseTimeout ((uint32_t)0x000FFFFF) #define ProgramTimeout ((uint32_t)0x0000FFFF) 备注 : Erase 和 Program 时间 stm32f10x_flash.c 源 文件 中 (路径:…\Libraries\STM32F10x_StdPeriph_Driver\src)
- 用 IAR 下载配置 解决方案 批量生产时会先烧一个 USB 的 boot,这个 boot 自动运行后由上 位机软件烧写应用程序。boot 如果程序不能自动运行,则需要重新插拔 次电源。给生产带来一些麻烦。如果程序设置了,则无法自动操作程序 阅读保护需要等待 FLASH_CR 的第 9[OPTWRE]位为 1.如果没有位置,继续 执行会出错。ST 执行速度慢,程序执行到阅读 FLASH_CR 寄存器 位置 1,GD 执行速度比较快,程序运行到这个时候,这个位置还没有 1,因为 这需要 FLASH_ReadOutProtection 函数中添加了一些轮询,即 1 或添加 些延时。
3. ISP 烧写软件
- ISP 烧写建议使用官方烧写软件 描述 GD32 芯片内部 flash 同 STM32 有区别 解决方法 建议到 www.mcuisp.com 下载最新版本的 MCUISP。另外 GD32 也有专门的 烧写软件(GigaDevice MCU ISP Programmer) 可以到 http://bbs.21ic.com/gd32 论坛下载。 如果使用自制的 ISP 软件或脱机编程器,实现 ST 和 GD 完全兼容,建议修改 以下参数。 1、 页擦除等待超时时间增加至 300ms,整片擦除等待超时时间增加至 3s 左 右。 2、 字编程等待超时时间增加至 2ms,页编程等等超时时间增加至 300ms。 I/O 口
- IO 口外部中断使用方法 描述 在关闭期间,如果外部引脚有电平的变化,在使用 IMR 打开中断后会马上进 入中断服务程序。理论是打开中断前,不管管脚是否有电平的变化,都不会影 响到打开后的中断响应。 解决方法 所以解决方法就是通过禁用上升沿或者下降沿检测寄存器来开关中断,不能使 用 IMR 屏蔽寄存器。程序如下: EXTI->FTSR &= ~EXTI_Line3; //关闭沿检测,以达到关闭中断的 目的,下降沿使用 FTSR 寄存器,上升沿使用 RTSR 寄存器 EXTI->PR = EXTI_Line3; EXTI->FTSR |= EXTI_Line3;
- 在待机模式,PA8 引脚特殊设置 描述 在使用低功耗的情况下,PA8 会被 MCU 在内部被设置为地 PA8 复用为 MCU 内部频率输出,超低功耗设置时需要悬空 解决方法 在待机模式,PA8 悬空不用
- 低功耗下必须注意 描述 在使用低功耗情况下,把软件全部端口(A-F)时钟关掉,无论是否有该端口。
- 当有脉冲群冲击管脚 描述 需要在在进入中断后关闭中断
4. 定时器
- 定时器输入捕获模式需要软件清中断 描述 STM 定时器输入捕获模式默认能硬件清中断,GD 为了更加严格要求配置,需 要做软件清中断 解决方法 软件清除标志位
- 定时器向上脉冲计数模式设置 描述 定时器的用法差异 解决方法 脉冲计数模式下,装载值必须设置为比预期值大,否则不计数 在 ST 上如果重载值不设置(初始为 0)的时候,CNT 可以正常计数。 在 GD 上如果重载值不设置保持初始为 0 的时候,会因为重载值为零,即便是 来一个脉冲也会导致所有的寄存器复位从而不能正常计数。 型号 GD32F1 系列 MCU (Flash 256KB 及以上的型号)
- TIM、ADC 模块 描述 Timer、ADC 模块的触发信号宽度要求 解决方法 由于内部有高速和低速两条外围总线,Timer、ADC 模块和其他外设共同使用 这两个总线。GD32F103/101 系列 Flash 128KB 及以下的型号,Timer、ADC 等 模块识别触发信号的条件是触发信号宽度大于模块所在总线的时钟宽度。
5. 串口 USART
- USART 连续发送数据字节有空闲位 描述 字节间有空闲位 解决方法 对于一般的通讯来说,不会有影响,只对于一般在通讯上有特殊协议的,才会 产生数据不准确的情况 所以,特定情况,修改程序
6. I2C 总线
- 硬件 I2C 特殊配置 描述 GD 的 I2C 相对 STM 的来说要少一个标志位 解 决 方法 1、宏地址定义改变 #define I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED ((uint32_t)0x00060002) #define I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED ((uint32_t)0x00070002) 2、硬件 I2C 在会在向从机发送 7bits 地址完成后,从机还没来得及识别。(看客户 应用) 我们可以在发送完 7bits 后加个延时,让从机完全识别: I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Transmitter); { int i = 0xfff; while(i --); }
3、检测 ADDR 不能使用 I2C_CheckEvent 函数,因为他会清除 ADDR,可以使用 I2C_GetFlagStatus 函数。 就是把 while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); 改为 while(!I2C_GetFlagStatus(I2C1, I2C_FLAG_ADDR)); 4、还有个关于编程步骤的严谨性,跟 STM 想比,我们是先 Clear_ACK,再 Clear_ARRD。
7. ADC 采集
- ADC 采样设置 描述 ADC 启动 解决方法 分三个方面
- 当 ADON=0 时写入 1 后,需要等待一段时间 t_WAIT,如果用 ST 库的话 就在 ADC_CMD 后面加 20us 左右的延时。
- 如果采用中断获得采样数据后,需要软件清除中断。
8. SDIO
- SDIO DAT 3 pin 的在 1 bit bus mode 和 4 bit bus mode 下的配置 描述 1、 SDIO 在 1 bit bus mode 下,DAT 3 pin 是低电平,这样会导致 SD Card 进 入 SPI 模式。 原因:初始化失败的原因主要是因为 GD32 的芯片 SDIO 的 DAT3 口存在 BUG。 2、 在 4 位模式下,通过上面的方法,程序能正常初始化,但不能正常读写 SD 卡。 原因:因为 DAT3 口在前面已经配置成推挽输出,所以在 4 位模式下,不 能正常读下。 在调用 4 位模式前,把 DAT3 的端口配置成复用推挽输入即可解决问题。 解决方法 1、 1 bit bus mode 的解决方法:建议在 SDIO 使能之前,先把 SDIO DAT 3 pin 配置成推挽输出,并且要置成高电平,使 SDIO DAT 3 pin 保持高电 平即可 2、 4 bit bus mode 的解决方法:在调用 4 位模式前,把 DAT3 的端口配置成 复用输出即可解决问题。
- 程序在刚烧完后能正常读写 SD 卡,断电再上电后,SD 卡初始化失败,需要手动 复位一次后才正常 描述 在某些 SD 卡中,GD32 断电再上电,会引起 SD 卡上的时钟信号不正常,导致 SD 卡发送命令失败。 解决方法 在程序中,打开 SD 卡时钟后,增加一小段延时,以保证 SD 卡时钟信号稳定。 这个延时添加的地方:在 sdcard.c(即 SDIO 的配置文件中),然后在 SD_Error SD_Init(void)这个函数中找到 SDIO_DeInit();就在这个后面加个延时。 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE); SDIO_DeInit(); { int i = 0xffff; while(i --); }
10. USB
A. USB_OTG
- 客户使用 STM32 的 DFU 原工程时需要注意几点 解 决 方 法 1、 在 usb_istr.c 中,增加如下图红色字体语句 for (i=0;i<8;i++) EP[i] = _GetENDPOINT(i); for (i=0;i<8;i++) _SetENDPOINT(i, EP[i] & 0x7070); 2、 在 usb_conf.h 中,按照下图红色字体语句进行修改 #if defined(STM32L1XX_MD) || defined(STM32L1XX_HD)|| defined(STM32L1XX_MD_PLUS) #define INTERN_FLASH_SECTOR_ERASE_TIME 100 #define INTERN_FLASH_SECTOR_WRITE_TIME 104 #else #define INTERN_FLASH_SECTOR_ERASE_TIME 100 #define INTERN_FLASH_SECTOR_WRITE_TIME 100 3、把固件库中的 stm32f10x_flash.c 使用附件的进行替换。 4、 软件进行读保护位时需要选使用 FLASH_Unlock();函数 int main(void) { #if defined (USE_STM32L152D_EVAL) FLASH_Unlock(); FLASH_ClearFlag(FLASH_FLAG_OPTVERRUSR); #endif FLASH_Unlock(); FLASH_ReadOutProtection(ENABLE); FLASH_Lock();
- 部分 USB 兼容性 解 决 方 法
- 部分 U 盘有 3 个端点,数组越界导致 Itf_Desc 被清空,所以主机不能识别设备 类型。USBH_conf.h 文件的 USBH_MAX_NUM_ENDPOINTS 的定义由 2 改成 3 就可以了
将:#define USBH_MAX_NUM_ENDPOINTS 2 改为:#define USBH_MAX_NUM_ENDPOINTS 3
- 在 In 端点中断处理程序 USB_OTG_USBH_handle_hc_n_In_ISR 中,对于 NAK 中断, V1.0.0 版本的处理如下: else if (hcint.b.nak) { if(hcchar.b.eptype == EP_TYPE_INTR) { UNMASK_HOST_INT_CHH (num); USB_OTG_HC_Halt(pdev, num); CLEAR_HC_INT(hcreg , nak); } else if ((hcchar.b.eptype == EP_TYPE_CTRL)|| (hcchar.b.eptype == EP_TYPE_BULK)) { /* re-activate the channel */ hcchar.b.chen = 1; hcchar.b.chdis = 0; USB_OTG_WRITE_REG32(&pdev->regs.HC_REGS[num]->HCCHAR, hcchar.d32); } pdev->host.HC_Status = HC_NAK; }
而 V2.1.0 版本的 NAK 处理过程如下: else if (hcint.b.nak) { if(hcchar.b.eptype == EP_TYPE_INTR) { UNMASK_HOST_INT_CHH (num); USB_OTG_HC_Halt(pdev, num); } else if ((hcchar.b.eptype == EP_TYPE_CTRL)|| (hcchar.b.eptype == EP_TYPE_BULK)) { /* re-activate the channel */ hcchar.b.chen = 1; hcchar.b.chdis = 0; USB_OTG_WRITE_REG32(&pdev->regs.HC_REGS[num]->HCCHAR, hcchar.d32); } pdev->host.HC_Status[num] = HC_NAK; CLEAR_HC_INT(hcreg , nak); }
唯一的区别就是 CLEAR_HC_INT(hcreg , nak)的位置,在 V1.0.0 版本中对于 CTRL 和 BULK 端点的 NAK 中断没有清除 NAK,我们的芯片会因此产生多次 IN 传输的请求,导 致数据传输错 误。改为 V2.1.1 的写法后传输正常。(注意 HC_Status 在 V2.1.0 是数 组,在 V1.0.0 是单个数据,直接拷贝的话要去掉后面的[num]) B. USB 外设的工作频率有限制 描述 有最低工作频率的要求,也就是 APB1 分频后的时钟必须大于 12MHz,比如 HCLK 为 56MHz,APB1 的最大分频系数为 4,56/4 = 14MHz,可以正常工作。
11. SPI
- 输入与输出配置要求(STM32 不需要如此要求) 解 决 方法 GD32 在使用 SPI 时,IO 的配置必须严格遵守主从模式下的输入与输出配置,而 STM32 无此要求,相关代码如下: 主机模式下 IO 配置(主机以 SPI 为例): GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_7; GPIO_Init(GPIOA,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; GPIO_Init(GPIOA,&GPIO_InitStructure); 从机模式下 IO 配置(从机以 SPI2 为例): GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13|GPIO_Pin_15; GPIO_Init(GPIOB,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14; GPIO_Init(GPIOB,&GPIO_InitStructure); 3) 在 GD32 的 SPI 的时钟信号,空闲状态需要配置成高电平,以保证数据的稳定性, 具体代码如下:红色字体代码 解 决 方法 SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; SPI_InitStructure.SPI_Mode = SPI_Mode_Master; SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; SPI_InitStructure.SPI_CRCPolynomial = 7; SPI_Init(SPI1, &SPI_InitStructure); 4) 当作为从机时,在 GD32 中,时钟信号必须为 8 的整数倍。 例如:红色字体代码 解 决 方法 SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; SPI_InitStructure.SPI_Mode = SPI_Mode_Master; SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; SPI_InitStructure.SPI_CRCPolynomial = 7; SPI_Init(SPI1, &SPI_InitStructure); 5) 在 GD32 中,不能使用 SPI_I2S_FLAG_BSY 该位来判断 SPI 总线数据是否接收或发送 完成。
12. 看门狗
- 进入 STOP 模式前打开看门狗,通过 RTC 的 ALR 唤醒后,程序会不断被复位的现像 描述 IWDG 内部有个 Reload 信号,KEY 寄存器写 AAAA 会使其拉高,过一段时间自 动拉低。在拉底之前进入 STOP 状态会使 Reload 信号一直为高,等到退出 STOP 后也保持为高,之后再写 AAAA 没有办法让 Reload 产生上升沿,也就没办法更 新计数器了。 解决方法 进 STOP 之前不要 Reload,也可以调整下程序的顺序,把 IWDG 的配置放到 RTC 配置之前,效果是一样的。
编辑:Frank 2014.07.11 北京锐鑫同创科技有限公司 http://www.realsense.com.cn/ 北京总部: 北京市朝阳区麦子店西街 3 号新恒基国际大厦 7 层 电话:010-82418301 深圳分公司: 深圳市福田区天安数码城创新科技广场 B 座 1407 室 电话:0755-86177515 上海分公司: 上海市长宁区天山西路 165 号宜家坊广场 A 座 6 层 电话:021-62266095 邮箱:gd32@realsense.com.cn GD32 芯片及开发工具零售:gd32@taobao.com GD32 中国芯 QQ 群:91270935 GD32 支持: frank@realsense.com.cn hjc@realsense.com.cn 样品申请 Halo@realsense.com.cn