Foreword
主要是想用GD32F450替代STM32F429,GD32F4xx号称可以替代STM32F4xx,但是实际上可能有一些细节不同,这里做个详细对比。
网上有一个兼容性说明文档传播比较广泛,我也按图索骥先试了试
GD32F450和STM32F4xx兼容性说明.pdf
粗玩
直接用CubeMX 配置STM32F429,然后无论是SD卡,FATFS,还是FreeRTOS都可以做到烧上就能跑,就能用的程度,但是有一点这里只是普通的替代,核心频率也只用到168MHz。这里工程所有配置都是STM32F429的,一点GD都不带。
原功能级别的替代基本可行,有问题的地方在于如果想要用GD的200MHz,那就不一样了,有些细节不同
硬件引脚对比
| 引脚编号 | ST | GD | 
|---|---|---|
| 49 | NC | VCAP_1 | 
| 73 | NC | VCAP_2 | 
对于LQFP100来说,只有49,73是标识明显不同的,都是电源相关的内容,而他们二者本身电源上也有微小的耐压区别。实际上可能由于有些引脚的特殊功能、复用等情况,还有更多的不同,那要等我用过可能才会发现
从表面看,直接替换是没问题的。
内存映射对比
当然这里有可能是名字不同,但是功能上是相同的。GD为了避免侵权之类的,文档里搞了一堆保留什么的,然后外设的索引从0开始,而ST的从1开始,看的非常蛋疼。
EXMC部分跳过,由于没用过,具体地址如下
0xC000 0000 - 0x6FFF FFFF
ST的FSMC在GD这里直接没有,所以这部分地址就保留了
0xA000 1000 - 0xBFFF FFFF
在AHB2中,不同的地方非常多,也可以认为是GD做了阉割,去掉了一些外设。
但总的来说保留了 RNG、DCI和USBFS。
下面是AHB1中的不同点,主要是多2组IO,剩下的应该是名称上的差异
| 地址 | ST | GD | 
|---|---|---|
| 0x4002 B000 - 0x4002 BBFF | DMA2D | IPA | 
| 0x4002 3C00 - 0x4002 3FFF | Flash interface register | FMC | 
| 0x4002 2800 - 0x4002 2BFF | GPIOK | 无 | 
| 0x4002 2400 - 0x4002 27FF | GPIOJ | 无 | 
下面是APB2中的不同点
| 地址 | ST | GD | 
|---|---|---|
| 0x4001 6800 - 0x4001 6BFF | LCD-TFT | TLI | 
| 0x4001 5800 - 0x4001 5BFF | SAI1 | 无 | 
| 0x4001 2400 - 0x4001 2BFF | 无 | 
下面是APB1中的不同点
| 地址 | ST | GD | 
|---|---|---|
| 0x4000 C400 - 0x4000 C7FF | 无 | IREF | 
| 0x4000 6C00 - 0x4000 6FFF | 无 | CTC | 
| 0x4000 4000 - 0x4000 43FF | I2S3ext | I2S2_add | 
| 0x4000 3400 - 0x4000 37FF | I2S2ext | I2S1_add | 
SRAM对比
| 地址 | ST | GD | 大小 | 说明 | 
|---|---|---|---|---|
| 0x2000 0000 - 0x2001 BFFF | SRAM1 | SRAM0 | 112KB | |
| 0x2001 C000 - 0x2001 FFFF | SRAM2 | SRAM1 | 16KB | |
| 0x2002 0000 - 0x2002 FFFF | SRAM3 | SRAM2 | 64KB | |
| 0x2003 0000 - 0x2006 FFFF | 无 | ADDSRAM | 256KB | |
| 0x2007 0000 - 0x3FFF FFFF | 保留 | 
需要注意GD比ST多了256KB的内存
GD的TCMSRAM在ST中叫CCM,64KB,这块内存只能被DBUS访问。
boot 对比
boot上基本保持了一致
外设对比
外设的属性上不同,主要是外设的寄存器相关配置可能不同
系统配置寄存器
| 地址偏移 | ST | GD | 
|---|---|---|
| 0x04 | SYSCFG_PMC | SYSCFG_CFG1 | 
这个寄存器只有Ethernet的选择bit一样,ST还有一个ADCxDC2,而GD没有
Flash
GD的Flash不太一样,如果只有1M大小那就只有bank0,而没有bank1。就算2M或者3M,他的两个bank的大小还是不对称的。如果用到了升级备份之类的功能,那就要注意一下。
Flash中的额外区域,比如opt或者系统内置的boot块,这些大小也都有所不同
| 地址偏移 | ST | GD | 
|---|---|---|
| 0x00 | FLASH_ACR | FMC_WS | 
延迟状态寄存器,ST由这里多了好几个关于cache的控制位,而GD直接没有
GD和ST解锁Flash的key 都是0x45670123和0xCDEF89AB,只是GD为了规避写在了前面的说明里,而寄存器说明里啥都不写,真有你的
| 地址偏移 | ST | GD | 
|---|---|---|
| 0x0C | FLASH_SR | FMC_STAT | 
状态位中主要是ST的bit5不同,GD是保留,ST是写入没对齐的错误标志
| 地址偏移 | ST | GD | 
|---|---|---|
| 0xFC | FMC_WSEN | 
GD多一个FMC的状态寄存器,没啥大用
| 地址偏移 | ST | GD | 
|---|---|---|
| 0x100 | FMC_PID | 
GD多一个产品保留ID的寄存器
电源管理
电源这里有很大不同,ST有PVD,作为低电处理的模块,对应GD叫做LVD。
| 地址偏移 | ST | GD | 
|---|---|---|
| 0x00 | PWR_CR | PMU_CTL | 
bit13不同,GD没有这一位,ST是和ADC相关的配置
bit9不同,ST是用于设置flash进入断电模式,而GD没有
| 地址偏移 | ST | GD | 
|---|---|---|
| 0x04 | PWR_CSR1 | PMU_CS | 
bit8,ST保留了,GD是关于唤醒引脚的使能
复位与时钟管理
时钟是二者最大的不同。GD450可以跑到200Mhz,而且根据其兼容性说明文件,可以知道他专门为了跑200Mhz,给USB等设备的48Mhz专门给了一个设置,而对应的ST这里只有跑168的时候才能用48Mhz,跑满180的时候则是无法使用USB等设备
仔细看时钟配置发现,GD这里多给了一个内部时钟,这个IRC是48MHz的,但是和其他内部时钟一样,他的精度不高,1%,用在USB或者SD卡的时候这个误差太大了。所以需要校准一下,而这个校准简单说就是通过和外部晶振一起计数比较,然后算出来内部时钟应该慢多少或者快多少,所以GD比ST多了一个控制器,用于校准时钟。
CTC 时钟校准控制器
这个校准还好有一个一键硬件校准的,不然真的麻烦,所以如果要用最好是先进行一次时钟校准,然后再进行USB等通信操作。
对应的CTC的校准寄存器是GD独有的,ST没有这部分功能.
PLLSAI
PLLSAI是时钟这里最大的不同,他专门用来给USB和SDIO提供48M的时钟
    //如果这里PLLQ是48M直接用下面这句就行了
	rcu_pll48m_clock_config(RCU_PLL48MSRC_PLLQ);
	// 但是一般情况下都会选择跑满,那么PLLQ就不能用了,这里就切换成PLLSAIP
    rcu_pll48m_clock_config(RCU_PLL48MSRC_PLLSAIP);
    rcu_ck48m_clock_config(RCU_CK48MSRC_PLL48M);
    rcu_periph_clock_enable(RCU_USBFS);
| 地址偏移 | ST | GD | 
|---|---|---|
| 0x08 | RCC_CFGR | RCU_CFG0 | 
这个寄存器是一样的,但是中文版中有写错的地方,我对比看了下英文版这里是正确的

APB2PSC应该是有3位,也就是15:13的分频位
| 地址偏移 | ST | GD | 
|---|---|---|
| 0x10 | RCC_AHB1RSTR | RCU_AHB1RST | 
这里略有不同,因为ST多了两组IO,所以这里就多了对应的复位BIT10和9
| 地址偏移 | ST | GD | 
|---|---|---|
| 0x14 | RCC_AHB2RSTR | RCU_AHB2RST | 
这里也是一样,ST多了HASH,CRYP的功能,对应多了BIT5和4
| 地址偏移 | ST | GD | 
|---|---|---|
| 0x30 | RCC_AHB1ENR | RCU_AHB1EN | 
GPIO的问题,同上
| 地址偏移 | ST | GD | 
|---|---|---|
| 0x34 | RCC_AHB2ENR | RCU_AHB2EN | 
同上
后面还有一些GPIO和多出来的功能的不同,就不列出来了,都是对应的寄存器
| 地址偏移 | ST | GD | 
|---|---|---|
| 0x70 | RCC_BDCR | RCU_BDCTL | 
这里GD多了一位BIT3,是对晶振驱动力高低的备份
中文还有一处错误这里保留的应该是28和29

下面接着出错了

| 地址偏移 | ST | GD | 
|---|---|---|
| 0x84 | RCC_PLLI2SCFGR | RCU_PLLI2S | 
ST的BIT27:24是PLLI2SQ的,而GD由于没有SAI1直接保留了。同理造成下面的RCC_PLLSAICFGR (RCU_PLLSAI),RCC_DCKCFGR (RCU_CFG1)不同
| 地址偏移 | ST | GD | 
|---|---|---|
| 0x88 | RCC_PLLSAICFGR | RCU_PLLSAI | 
但是这里GD多了BIT16和17,用来处理PPSAIP的分频

这里可以看到,CK_PPLSAIVCO是来自于CK_ PLLSAIVCOSRC × PLLSAIN
CK_PLLSAIVCOSRC = CK_PLLSRC / PLLPSC
CK_PLLSAIVCO = CK_ PLLSAIVCOSRC × PLLSAIN
CK_PLLSAIP = CK_ PLLSAIVCO / PLLSAIP
CK_PLLSAIR = CK_ PLLSAIVCO / PLLSAIR
其中CK_ PLLSAIVCOSRC我们一般都配置成了1MHz,要配置48的话,就全靠PLLSAIN了。
这里需要注意一下PLLSAIN是不能设置为50MHz以下的,所以一般PPLSAIN设置为96
然后CK_PLLSAIVCO就是96MHz,PPLSAIP设置为00,对应2分频,那么得到的CK_PLLSAIP就是48MHz了
| 地址偏移 | ST | GD | 
|---|---|---|
| 0x8C | RCC_DCKCFGR | RCU_CFG1 | 
这里不同的主要是ST多了SAI1,PLLSAIDIVQ和PLLS2DIVQ
附加寄存器
再往下ST已经没有寄存器,剩下就是GD单独附加的寄存器了
| 地址偏移 | ST | GD | 
|---|---|---|
| 0xC0 | RCU_ADDCTL | 
RCU_ADDCTL主要是用来设置多出来的一个48M的时钟源,并且多出来的一个外部时钟IRC48M的也在这里控制
| 地址偏移 | ST | GD | 
|---|---|---|
| 0xCC | RCU_ADDINT | 
对应ICR48M的中断寄存器
| 地址偏移 | ST | GD | 
|---|---|---|
| 0xE0 | RCU_ADDAPB1RST | 
时钟校准和编程电流复位寄存器
| 地址偏移 | ST | GD | 
|---|---|---|
| 0xE4 | RCU_ADDAPB1EN | 
上面的使能寄存器
| 地址偏移 | ST | GD | 
|---|---|---|
| 0xE8 | RCU_ADDAPB1SPEN | 
上面的睡眠寄存器
| 地址偏移 | ST | GD | 
|---|---|---|
| 0x100 | RCU_VKEY | 
电源解锁寄存器
| 地址偏移 | ST | GD | 
|---|---|---|
| 0x134 | RCU_DSV | 
深度睡眠的寄存器,主要是设置深度睡眠下的内核电压值
总结一下独立设置USB和SDIO的48M时钟
// 配置SAI分频 构造48M时钟
rcu_pllsai_config(96, 2, ???, 2);
// 切换到SAIP
rcu_pll48m_clock_config(RCU_PLL48MSRC_PLLSAIP);
// 选择时钟源
rcu_ck48m_clock_config(RCU_CK48MSRC_PLL48M);
// 使能USB时钟
rcu_periph_clock_enable(RCU_USBFS);
额 我配置的时候发现一个错,实际手册里根本没有SAIQ的位,但是代码里却配置了,所以有错
/*!
    \brief      configure the PLLSAI clock 
    \param[in]  pllsai_n: the PLLSAI VCO clock multi factor
      \arg        this parameter should be selected between 50 and 500
    \param[in]  pllsai_p: the PLLSAI P output frequency division factor from PLL VCO clock
      \arg        this parameter should be selected 2,4,6,8
    \param[in]  pllsai_q: the PLLSAI Q output frequency division factor from PLL VCO clock
      \arg        this parameter should be selected between 2 and 15
    \param[in]  pllsai_r: the PLLSAI R output frequency division factor from PLL VCO clock
      \arg        this parameter should be selected between 2 and 7
    \param[out] none
    \retval     ErrStatus: SUCCESS or ERROR
*/
ErrStatus rcu_pllsai_config(uint32_t pllsai_n, uint32_t pllsai_p, uint32_t pllsai_q, uint32_t pllsai_r)
{
    /* check the function parameter */
这部分配置我看了官方的固件库或者例程,都找不到任何一个在200MHz下使用的情况,全都是直接配好了PLL48M,不存在这种单独配置的情况。
USB
由于USB一直出错,所以这里先对比一下看看是否有不同,USB太复杂了,里面这么多不同,最终影响库的使用到底有多少谁也不知道。
| 地址偏移 | ST | GD | 
|---|---|---|
| 0x0C | OTG_FS_GUSBCFG | USBFS_GUSBCS | 
BIT31 在ST这边是用来debug,GD则是保留
BIT6 在ST这里是总是1,用来,USB全速发送,但是GD保留
| 地址偏移 | ST | GD | 
|---|---|---|
| 0x010 | OTG_FS_GRSTCTL | USBFS_GRSTCTL | 
BIT31 在ST这边是AHB的状态,GD是保留
| 地址偏移 | ST | GD | 
|---|---|---|
| 0x01C | OTG_FS_GRSTCTL | USBFS_GRSTATR/USBFS_GRSTATP | 
这个寄存器分为Host模式和Device模式,在Device模式中有所不同
BIT24-21在ST中是帧个数,而GD直接没有,这个位是只有同步输出才有用
| 地址偏移 | ST | GD | 
|---|---|---|
| 0x024 | OTG_FS_GRXFSIZ | USBFS_GRFLEN | 
| 0x028 | OTG_FS_DIEPTXF0 | USBFS_HNPTFLEN _DIEP0TFLEN | 
这个里面Rx的FIFO最大深度在ST中是256,而GD中则是1024
同理,发送深度也是这种情况。不过在Device模式中,GD发送最大是140,而ST是256
| 地址偏移 | ST | GD | 
|---|---|---|
| 0x038 | OTG_FS_GCCFG | USBFS_GCCFG | 
BIT19和18 是Vbus比较使能的位,在ST这边是如果使用了就用,没用就没用。但是GD这里是不管你用没用都得置位,否则直接无法正常工作,代码如下
    USBx->GCCFG |= USB_OTG_GCCFG_VBUSBSEN;
    USBx->GCCFG |= USB_OTG_GCCFG_VBUSASEN;
| 地址偏移 | ST | GD | 
|---|---|---|
| 0x804 | OTG_FS_DCTL | USBFS_DCTL | 
BIT6-4里ST是测试模式,而GD保留
| 地址偏移 | ST | GD | 
|---|---|---|
| 0x808 | OTG_FS_DSTS | USBFS_DSTAT | 
BIT3在ST中不稳定误差的显示,而GD中保留
BIT0 在ST中没有明确说到底0是挂起还是非挂起,但是从代码里看到,1是挂起,0是没挂起
而GD这里是相反的,GD明确说了0是挂起状态,1是非挂起状态 ,一定要注意,库里这个地方设置的是相反的。
| 地址偏移 | ST | GD | 
|---|---|---|
| 0x810 | OTG_FS_DIEPMSK | USBFS_DIEPINTEN | 
BIT5 ST中是EP不匹配错误,GD保留
BIT13 ST中是NAK中断,而GD直接没有
| 地址偏移 | ST | GD | 
|---|---|---|
| 0x814 | OTG_FS_DOEPMSK | USBFS_DOEPINTEN | 
BIT5 ST中状态解析,而GD保留
BIT6 GD是连续setup包的中断,而ST中没有
BIT8-13 ST有而GD保留
| 地址偏移 | ST | GD | 
|---|---|---|
| 0x818 | OTG_FS_DAINT | USBFS_DAEPINT | 
| 0x81C | OTG_FS_DAINTMSK | USBFS_DAEPINTEN | 
| 0x0834 | OTG_FS_DIEPEMPMSK | USBFS_DIEPFEINTEN | 
这里ST无保留,而GD保留了一部分端点的中断位
| 地址偏移 | ST | GD | 
|---|---|---|
| 0x908+x*0x20 | OTG_FS_DIEPINTx | USBFS_DIEPxINTF | 
这里BIT13在ST是NAK,11是丢包状态,而GD则没有这几位
| 地址偏移 | ST | GD | 
|---|---|---|
| 0xB08+x*0x20 | OTG_FS_DOEPINTx | USBFS_DOEPxINTF | 
BIT5在ST是状态解析,而GD保留
BIT6在ST保留,GD中式连续setup包
BIT13在ST是NAK,而GD则没有
BIT11是丢包状态,而GD则没有
| 地址偏移 | ST | GD | 
|---|---|---|
| 0x910+x*0x20 | OTG_FS_DIEPTSIZx | USBFS_DIEPxLEN | 
BIT30-29在GD中是每帧多包数目,而ST没有
| 地址偏移 | ST | GD | 
|---|---|---|
| 0xE00 | OTG_FS_PCGCCTL | USBFS_PWRCLKCTL | 
BIT4 ST中多了物理挂起的选项,但是GD中没有
问题总结
目前已经发现的GD的问题
- SD时钟开启响应延迟较高
- USB和SDIO的48M时钟源配置有错
- 中文文档中存在错误,据说中文是从英文翻译过来的(我之前不确定他们优先中文还是英文,一起看的)
- 固件库例程真的不行(用个I2C还是GPIO模拟的,丢人不丢人?各种你想用的驱动例程里都是最菜的那种,就不能发挥一下外设的作用嘛)
- USB中的DSTAT和GCCFG寄存器和预期的不相同,直接影响了usb设备能否正常工作。
其他
之前有说过F7中的Timer DMA PWM中有bug,只能同时启动一路。
http://elmagnifico.tech/2020/06/03/Dshot-STM32-PWM-HAL/
这次看F4的库,发现这里这个判断修改了,之前F7这里判定的是Timer本身的状态,而这里则是判定每个channel的状态。
HAL_StatusTypeDef HAL_TIM_PWM_Start_DMA(TIM_HandleTypeDef *htim, uint32_t Channel, uint32_t *pData, uint16_t Length)
{
  uint32_t tmpsmcr;
  /* Check the parameters */
  assert_param(IS_TIM_CCX_INSTANCE(htim->Instance, Channel));
  /* Set the TIM channel state */
  if (TIM_CHANNEL_STATE_GET(htim, Channel) == HAL_TIM_CHANNEL_STATE_BUSY)
  {
    return HAL_BUSY;
  }
  else if (TIM_CHANNEL_STATE_GET(htim, Channel) == HAL_TIM_CHANNEL_STATE_READY)
  {
GD可以高达200MHz,但是实际使用的时候就会发现有些情况这个200MHz有点坑爹。比如DSHOT的频率和GD的时钟频率就匹配不上(3和10互质),怎么用都会出现时钟频率不理想。这种情况下只好降频,降到192MHz,这样各种时钟频率都处于一个比较ok的状态。而192还有一个好处,就是usb的频率都不需要切换到PLLSAI了,直接分频就能得到合适的48MHz。
有时候想想,发现这些板子的总时钟频率还真不能瞎选,可能你选的不合适,一味追求高,导致实际上有些地方分频怎么分也得不到合适的值,这时候就只能降频了。
Summary
目前只总结了这么多,后续随着使用继续更新。
还是想吐槽一下,GD还是不行,F4的固件库上次更新是2019年3月,2年了没有任何更新,这让开发者是啥感觉。
反观ST,F4最近一次更新是20年9月,F7最近一次更新是20年12月,人一年至少更新一次,虽然不是啥大更新,但是说明这玩意还有人维护啊。
F4和F7差异
最后GD的450还是放弃掉了,因为本来是想替代F7系列的,虽然CoreMark跑分上相差不是很大,但是实际应用的时候不只是跑分,中断响应时间也非常重要,而这种指标在跑分上看不出来,F4系列中断响应比F7慢很多,当然也有一些其他因素,比如cache这种高级货只有F7才有,比如我们系统开销比较高,F4跑不过来。最终导致,450不能满足我们的使用吧。
此文的更新大抵也就到这里了
Quote
https://www.cirmall.com/bbs/thread-95530-1-1.html
https://www.cnblogs.com/zwj412/p/10026393.html