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)
四個函數需要修改。
????2) 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)可以到http://bbs.21ic.com/gd32?論壇下載。如果使用自制的ISP 軟件或脫機編程器,實現ST 和GD 完全兼容,建議修改以下參數:
????1、 頁擦除等待超時時間增加至300ms,整片擦除等待超時時間增加至3s 左右。
????2、 字編程等待超時時間增加至2ms,頁編程等等超時時間增加至300ms。
4.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) 低功耗下必須注意
????描述:在使用低功耗情況下,把軟件全部端口(A-F)時鐘關掉,無論是否有該端口。
4) 當有脈沖群沖擊管腳
????描述:需要在在進入中斷后關閉中斷。
5. 定時器
????1) 定時器輸入捕獲模式需要軟件清中斷
????描述:STM 定時器輸入捕獲模式默認能硬件清中斷,GD 為了更加嚴格要求配置,需要做軟件清中斷 。
????解決方法:軟件清除標志位。
????2) 定時器向上脈沖計數模式設置
????描述:定時器的用法差異。
????解決方法:脈沖計數模式下,裝載值必須設置為比預期值大,否則不計數在ST 上如果重載值不設置(初始為0)的時候,CNT 可以正常計數。 在GD 上如果重載值不設置保持初始為0 的時候,會因為重載值為零,即便是來一個脈沖也會導致所有的寄存器復位從而不能正常計數。
????3) TIM、ADC 模塊
????描述:Timer、ADC 模塊的觸發信號寬度要求。
????解決方法:由于內部有高速和低速兩條外圍總線,Timer、ADC 模塊和其他外設共同使用這兩個總線。GD32F103/101 系列Flash 128KB 及以下的型號,Timer、ADC 等模塊識別觸發信號的條件是觸發信號寬度大于模塊所在總線的時鐘寬度。
6. 串口USART
????1) USART 連續發送數據字節有空閑位
????描述:字節間有空閑位。

????解決方法:對于一般的通訊來說,不會有影響,只對于一般在通訊上有特殊協議的,才會產生數據不準確的情況所以,特定情況,修改程序。
7. I2C 總線
????1) 硬件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。
8. ADC 采集
????1) ADC 采樣設置
????描述:ADC 啟動
????解決方法:
????1. 當ADON=0 時寫入1 后,需要等待一段時間t_WAIT,如果用ST 庫的話就在ADC_CMD 后面加20us 左右的延時。
????2. 如果采用中斷獲得采樣數據后,需要軟件清除中斷。
9. 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 的端口配置成復用輸出即可解決問題。
????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 --);
}
10. USB
????A. USB_OTG
????1) 客戶使用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();
????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 外設的工作頻率有限制
????描述:有最低工作頻率的要求,也就是APB1 分頻后的時鐘必須大于12MHz,比如HCLK 為56MHz,APB1 的最大分頻系數為4,56/4 = 14MHz,可以正常工作。
11. 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);
????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. 看門狗
????1) 進入STOP 模式前打開看門狗,通過RTC 的ALR 喚醒后,程序會不斷被復位的現像
????描述:IWDG 內部有個Reload 信號,KEY 寄存器寫AAAA 會使其拉高,過一段時間自動拉低。在拉底之前進入STOP 狀態會使Reload 信號一直為高,等到退出STOP 后也保持為高,之后再寫AAAA 沒有辦法讓Reload 產生上升沿,也就沒辦法更新計數器了。
????解決方法:進STOP 之前不要Reload,也可以調整下程序的順序,把IWDG 的配置放到RTC配置之前,效果是一樣的。