一、 GD32 与 STM32 异同 1. 相同点 1) 外围引脚定义: 相同型号的管脚定义相同 2) Cortex M3 内核: STM32F103 内核 R1P1 版本, STM32F205 内核 R2P1, GD32 内核 R2P1 版本,此内核修复了 R1P1 的一些 bug 3) 芯片内部寄存器, 外部 IP 寄存器地址 : 逻辑地址相同,主要是根据 STM32 的寄存器和物理地址, 做的正向研发. 4) 函数库文件: 函数库相同,优化需要更改头文件 5) 编译工具: 完全相同 例如:keil MDK、IAR 6) 型号命名方式: 完全相同 2. 外围硬件区别 1) 电压范围(ADC): GD32F: 2.6-3.6V STM32F: 2.0-3.6V(外部电压) GD32F: 1.2V(内核电压)STM32F: 1.8V(内核电压) 2) BOOT 0 管脚: Flash 程序运行时,BOOT0 在 STM32 上可悬空,GD32 必须外 部下拉(从 Flash 运行,BOOT0 必须下拉地) 3) ESD 参数: STM32 人体模式 2KV,空气模式 500V GD32 人体模式 4KV(内测 5KV),空气模式 10KV(内测 15KV) 3. 内部结构差别 1) 启动时间: GD32 启动时间相同,由于 GD 运行稍快,需要延长上电时间 配置(2ms) 2) 主频时钟: GD32F10 系列主频 108MHZ STM32F10 系列主频 72MHZ 3) Flash 擦除时间: GD32 是 60ms/page,STM 30ms/page 4) FLASH 容量: GD32 最大容量 3M Byte 5) SRAM 空间: GD32F103 系列、GD32F105\107 大容量系列 SRAM 96K 6) VB 外扩总线 FSMC:GD32 100PIN 配置总线输出,STM32 144PIN 并且 256k 以上 才配置总线输出 4. 功耗区别(以 128k 以下容量的作为参考) 1) 睡眠模式 Sleep: GD32F: 12.4mA STM32F10X: 7.5mA 2) 深度睡眠模式 Deep Sleep: GD32F: 1.4mA STM32F10X: 24uA 3) 待机模式 Stand By: GD32F: 10.5uA STM32F10X: 3.4uA 4) 运行功耗: GD32F: 32.4mA/72M STM32F10X: 52mA/72M 5. 内部 FLASH 区别 1) ISP: 擦写时间同 STM32 有差异,使用新版 ISP 软件 2) IAP: 擦写时间相同,按字写入,按页擦除 3) 存储寿命: 10 万次擦写,数据保存 20 年以上 4) 加密特性: 除了常规的禁止读出和 96 位 ID 号码加密之外,GD32 数据写入 Flash 时,具有存储逻辑地址连续,物理地址不连续的特性。 二、 GD32 介绍与兼容性详析 1. 系统 1) 晶振起振区别 描述 启动时间,GD32 与 STM32 启动时间都是 2ms,实际上 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)。 2) 部分客户使用有源晶振出现问题,在 GD32F103 小容量产品,发现会在 MCU 的复 位管脚一直把电平拉到 0.89V,电平不能保持在高电平 描述 是由于部分有源晶振起振时间太快,复位信号还没有完成导致的 解决方法 就是在有源晶振的输入端与地之前并上一个 30pf 电容 3) GD32 MCU 主频支持 108MHz 高性能,在代码移植方面需要注意事项 描述 GD32 通过芯片内部加大缓存,提高了相同工作频率下的代码执行速度,带来 了高性能的使用体验。 解决方法 因此如果代码有用到 for 循环或 while 循环语句做精确定时的,定时时间会由 于代码执行速度加快而使循环的时间变短。使用 Timer 定时器则没有影响。 4) GD32F105/107 系列 MCU 配置为 108MHz 有何不同 描述 通 过 Clock configuration register (RCC_CFGR) 中 , 第 21 : 18 位 为 PLLMUL[3:0],再结合第 29 位 PLLMUL[4]组成 5 位的位域来确定 PLL 倍频 系数,即通过软件配置来定义 PLL 的倍频系数,且 PLL 输出频率绝对不 得超过最高主频(108MHz)。 2. 内部 Flash 1) 芯片设置读保护用法 描述 由于 GD 的 Flash 是自己的专利技术,STM 的 Flash 是第三方提供的,所以 GD 的 Flash 和 STM 的 Flash 有些许差异。GD 的擦除时间会长一点 解决方法 在写完 KEY 序列以后,需要读该位,确认 key 已生效。 所以,这里应该插入 While( ! (FLASH->CR & 0x200 ) ); // 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在应用中编程 描述 GD32 由于自有 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) 3) 用 IAR 下载配置 解决方法 在批量生产的时候首先会烧写一个 USB 的 boot,这个 boot 自动运行后在由上 位机软件进行烧写应用程序。如果 boot 程序不能自动运行则需要重新插拔一 次电源。给生产造成一些麻烦。产生不能自动运行程序的原因是如果程序设置 读保护的话需要等待 FLASH_CR 的第 9[OPTWRE]位为 1.如果没有置位的话继续 执行就会出错。由于 ST 的执行速度慢,程序执行到读 FLASH_CR 寄存器的时候 该位已经置 1,GD 的执行速度比较快,程序运行到这的时候该位还没置 1,因 此需要在 FLASH_ReadOutProtection 函数里面添加一些轮询该位为 1 或者加一 些延时。 3. ISP 烧写软件 1) ISP 烧写,建议使用官方烧写软件 描述 GD32 芯片内部 flash 同 STM32 有区别 解决方法 建议到 www.mcuisp.com 下载最新版本的 MCUISP。另外 GD32 也有专门的 烧写软件(GigaDevice MCU ISP Programmer) 如果使用自制的 ISP 软件或脱机编程器,实现 ST 和 GD 完全兼容,建议修改 以下参数。 1、 页擦除等待超时时间增加至 300ms,整片擦除等待超时时间增加至 3s 左 右。 2、 字编程等待超时时间增加至 2ms,页编程等等超时时间增加至 300ms。 I/O 口 1) IO 口外部中断使用方法 描述 在关闭期间,如果外部引脚有电平的变化,在使用 IMR 打开中断后会马上进 入中断服务程序。理论是打开中断前,不管管脚是否有电平的变化,都不会影 响到打开后的中断响应。 解决方法 所以解决方法就是通过禁用上升沿或者下降沿检测寄存器来开关中断,不能使 用 IMR 屏蔽寄存器。程序如下: EXTI->FTSR &= ~EXTI_Line3; //关闭沿检测,以达到关闭中断的 目的,下降沿使用 FTSR 寄存器,上升沿使用 RTSR 寄存器 EXTI->PR = EXTI_Line3; EXTI->FTSR |= EXTI_Line3; 2) 在待机模式,PA8 引脚特殊设置 描述 在使用低功耗的情况下,PA8 会被 MCU 在内部被设置为地 PA8 复用为 MCU 内部频率输出,超低功耗设置时需要悬空 解决方法 在待机模式,PA8 悬空不用 3) 低功耗下必须注意 4) 当有脉冲群冲击管脚 描述 需要在在进入中断后关闭中断 描述 在使用低功耗情况下,把软件全部端口(A-F)时钟关掉,无论是否有该端口。 4. 定时器 1) 定时器输入捕获模式需要软件清中断 描述 STM 定时器输入捕获模式默认能硬件清中断,GD 为了更加严格要求配置,需 要做软件清中断 解决方法 软件清除标志位 2) 定时器向上脉冲计数模式设置 描述 定时器的用法差异 解决方法 脉冲计数模式下,装载值必须设置为比预期值大,否则不计数 在 ST 上如果重载值不设置(初始为 0)的时候,CNT 可以正常计数。 在 GD 上如果重载值不设置保持初始为 0 的时候,会因为重载值为零,即便是 来一个脉冲也会导致所有的寄存器复位从而不能正常计数。 型号 GD32F1 系列 MCU (Flash 256KB 及以上的型号) TIM、ADC模块 描述 Timer、ADC 模块的触发信号宽度要求 解决方法 由于内部有高速和低速两条外围总线,Timer、ADC 模块和其他外设共同使用 这两个总线。GD32F103/101 系列 Flash 128KB 及以下的型号,Timer、ADC 等 模块识别触发信号的条件是触发信号宽度大于模块所在总线的时钟宽度。 5.串口USART 1 USART连续发送数据字节有空闲位 描述 字节间有空闲位 解决方法 对于一般的通讯来说,不会有影响,只对于一般在通讯上有特殊协议的,才会 产生数据不准确的情况 所以,特定情况,修改程序 6. I2C 总线 1) 硬件 I2C 特殊配置 描述 GD 的 I2C 相对 STM 的来说要少一个标志位 解 决 方法 1、宏地址定义改变 #define I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED ((uint32_t)0x00060002) #define I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED 7.ADC采样 1) ADC采样设置 描述 ADC 启动 解决方法 分三个方面 1. 当 ADON=0 时写入 1 后,需要等待一段时间 t_WAIT,如果用 ST 库的话 就在 ADC_CMD 后面加 20us 左右的延时。 2. 如果采用中断获得采样数据后,需要软件清除中断。 8. SDIO 1) 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 的端口配置成 复用输出即可解决问题。 ((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。 2) 程序在刚烧完后能正常读写 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 --); } 9. USB A. USB_OTG 1) 客户使用STM32 的DFU 原工程时需要注意几点 解决方法 1、在usb_istr.c 中,增加如下图红色字体语句 for (i=0;i<8;i++) EP = _GetENDPOINT(i); for (i=0;i<8;i++) _SetENDPOINT(i, EP & 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(); 2) 部分 USB 兼容性 解决方法 1 部分 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 2. 在 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 外设的工作频率有限制 10. SPI 1) 输入与输出配置要求(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); 2) 在 GD32 的 SPI 的时钟信号,空闲状态需要配置成高电平,以保证数据的稳定性, 具体代码如下:红色字体代码 描述 有最低工作频率的要求,也就是 APB1 分频后的时钟必须大于 12MHz,比如 HCLK 为 56MHz,APB1 的最大分频系数为 4,56/4 = 14MHz,可以正常工作。 解 决 方法 SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; SPI_InitStructure.SPI_Mode = SPI_Mode_Master; 3) 当作为从机时,在 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); 4) 在GD32中,不能使用 SPI_I2S_FLAG_BSY该位来判断SPI总线数据是否接收或发送完成。 11. 看门狗 1) 进入STOP模式前打开看门狗,通过RTC的ALR唤醒后,程序会不断被复位的现像 描述 IWDG 内部有个 Reload 信号,KEY 寄存器写 AAAA 会使其拉高,过一段时间自 动拉低。在拉底之前进入 STOP 状态会使 Reload 信号一直为高,等到退出 STOP 后也保持为高,之后再写 AAAA 没有办法让 Reload 产生上升沿,也就没办法更 新计数器了。 解决方法 进 STOP 之前不要 Reload,也可以调整下程序的顺序,把 IWDG 的配置放到 RTC 配置之前,效果是一样的。 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);
|