软件移植注意事项 1.1系统方面的注意事项 1.1.1 HSE相关内容修改 在V3.x 的库,启动时间宏定义在xxx32f10x.h头文件中; 在 V3.0 以 前 的 库 , 其 启 动 时 间 宏 定 义 在 xxx32f10x_rcc.c中 (HSEStartUp_TimeOut); 修改前: //#define HSE_STARTUP_TIMEOUT ((uint16_t)0x0500) /*!< Time out for HSE start up */ 修改后: #define HSE_STARTUP_TIMEOUT ((uint16_t)0xFFFF) /*!< Time out for HSE start up */ 修改原因: GD和STM32的晶振部分电路设计有一定的差异,两者对外部高速晶振的参数要求也不一样,修改HSE_STARTUP_TIMEOUT宏定义可以保证晶振正常起振。当然你会在应用 中发现有一些应用不修改也能照常跑,这是由于晶振的参数差异造成了,为了保证程序的正常运行还是修改该宏定义。 1.1.2 代码执行速度方面的修改 GD32采用专利技术,提高了相同工作频率下的代码执行速度,带来了高性能的使用体验。这样一些在ST下面编写的程序如While或者是For循环的延时,移植到GD上面来肯定相应的延时会变短。所以如果客户的应用有用到这种延时方法的得根据实际情况进行一定的调整。GD的代码执行速度比ST更快,那么在客户的应用中如果有一些判断的结构不够严谨也可能会导致问题。 案例1:客户在软件中编写了一个延时函数如下: void delay(void) { u8 i; for(i=0;i<75;i++); } 通过实测相同的这一段代码: ST执行该函数的延时时间是7.4us GD执行该函数的延时时间是5.4us。 如果客户的应用对时间要求比较严格请不要忽略GD代码执行速度的问题,参数需要做一定的调整。 案例2: 客户采用IO模拟I2C他的查应答函数的编写如下 #defineSDA_Status( ) GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_1) void CheckACK(void) { cAcknowledge=TRUE if(SDA_Status()) { cAcknowledge=FalSE; } } 客户反馈这段代码在ST上面执行OK,但是在GD上面运行不正常,其实这是由于GD的执行速度更快,ACK信号还出来,语句就已经执行完成了。 建议客户修改代码: #define SDA_Status() GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_1) void CheckACK(void) { u8 ErrTimer=0; cAcknowledge=TRUE while(SDA_Status()) { ucErrTime++; if(ucErrTime>250) { cAcknowledge=FalSE; } } } 代码修改后客户的问题得以解决,使用ST没有问题是因为ST的代码执行速度没有GD的快,刚好客户的代码能满足他的应用,换了GD 以后由于代码执行速度更快,只能通过更严谨的逻辑来进行代码的移植。
1.1.3 BOOT管脚注意事项 BOOT0及BOOT1管脚在芯片复位时的电平状态决定了复位后从哪个区域开始执行程序。典型情况下,BOOT0需外接10K下拉电阻,就可以从Flash启动。如BOOT0悬空,则不能从Flash启动。 1.2GPIO方面说明 1.2.1 EXTI中断相应异常 如果EXTI配置好后关闭EXTI,IO有沿跳变,再次打开EXTI时,系统会响应EXTI关闭过程中的外部触发,(小容量存在该问题,大容量没有)。 软件可以参考以下例程设置IMR 屏蔽寄存器来使能中断 (这里以 EXTI 7 为例): 使用上升沿触发: { /* Clear Rising Falling edgeconfiguration */ EXTI->RTSR &= ~EXTI_Line7; /*Clear EXTI line configuration */ EXTI->IMR |= EXTI_Line7 ; EXTI->EMR |= EXTI_Line7 ; /* RisingFalling edge */ EXTI->RTSR |= EXTI_Line7; } 使用下降沿触发: { /* Clear Rising Falling edge configuration*/ EXTI->FTSR &= ~EXTI_Line7; /* Clear EXTI line configuration */ EXTI->IMR |= EXTI_Line7 ; EXTI->EMR |= EXTI_Line7 ; /* RisingFalling edge */ EXTI->FTSR |= EXTI_Line7; } 使用上升沿和下降沿同时触发: { /* ClearRising Falling edge configuration */ EXTI->RTSR &= ~EXTI_Line7; EXTI->FTSR &= ~EXTI_Line7; /* Clear EXTI line configuration */ EXTI->IMR|= EXTI_Line7 ; EXTI->EMR |= EXTI_Line7 ; /* Rising Falling edge */ EXTI->RTSR |= EXTI_Line7; EXTI->FTSR |= EXTI_Line7; }
1.2.2 PA8和低功耗关系 PA8管脚如果外接上拉电阻,会导致在standby模式下有较大的漏电流,会增加 standby模式下的功耗,但是对stop模式下的功耗无影响。因此如果要获得比较低的 功耗。PA8管脚要保持悬空或者是下拉,或者在进入standby模式之前,断开PA8管脚与外部的连接。 1.2.3 PB1和PB2关系 PB1设置成IPU IPDAF_PP,AF_OD四种模式的时候,PB2不受控。为了能正常使用 PB2,PB1必须配制成Out_PP, AIN, FLOATING; 1.2.4 PA8上电状态 当PA8设置为输出高电平时,开机的第一次翻转会比ST的慢2.5ms左右, 1.3定时器方面的说明 1.3.1 TIM 中断标志位清除问题 当TIM的Channel 配置成Input Capture mode时,GD32F103reading the TIMx_CCRx 寄存器不会自动清除TIMx_SR寄存器的CcxIF标志,该中断标志位需要软件清除。 1.3.2 TIM 输入捕获/正交编码配置问题 有客户反馈使用GD的MCU,用定时器工作在正交编码或者是输入捕获不能工作,同一程序ST的工作正常。检查客户的程序,发现客户编程的时候没有配置定时器的周期,而ST的定时器不配置定时器的周期的话会给出一个默认值,GD不会。在程序中加上配置定时器周期的语句就OK了。 TIM_TimeBaseStructure.TIM_Period = 0xffff; TIM_TimeBaseStructure.TIM_Prescaler =0; TIM_TimeBaseStructure.TIM_ClockDivision =0; TIM_TimeBaseStructure.TIM_CounterMode= TIM_CounterMode_Up; TIM_TimeBaseInit(TIMx,&TIM_TimeBaseStructure); 1.4 ADC方面的说明 1.4.1 ADC输入通道模式配置 使用GD的MCU的时候,输入通道必须配制成模拟输入的模式GPIO_Mode_AIN,配制成其他模式不能正常工作。 1.4.2 ADC时钟配置问题 使用GD的MCU的时候,需要ADC 的采样配置时钟(特别是小容量,一定要配置采样时钟),而且不能大于14M Hz。采样周期配置如下: RCC_ADCCLKConfig(RCC_PCLK2_Divx);
1.4.3 ADC输入阻抗和采样周期选择 从ST移植到GD,使用到ADC 的话需要根据具体情况相应的修改采样周期。具体参数见下表:
file:///C:/Users/Lenovo/AppData/Local/Temp/msohtmlclip1/01/clip_image002.jpg1.6 RTC方面的说明
1.6.1 RTC硬件方面问题 GD的RTC正常使用起来和ST的没有差别,但是客户使用的过程中经常会在设计硬件的 时候增加一个电阻或者是不加电容等问题,所以关于RTC方面的设计请严格参照下面的原理图:
1.7 SPI方面的说明 1.7.1 CLK线重复配置 有客户反馈当SPI处于主模式下,重复配置SPI的CLK线会引起内部计数器紊乱: 问题代码: GPIO->CRL&=0x000fffff; GPIO->CRL|=0xBBB00000; 上面这段代码是执行SPI 口的IO初始化,调用两次后会使CLK上面产生一个脉冲。引起内部计数器出错,ST的在SPI再次初始化的时候会将内部计数器清零,GD不会将内部计数器清零。 修改办法: vu32 temp ; temp=GPIOA->CFL; temp&=0x000fffff; temp|=0xbbb00000; GPIOA->CRL=temp; 先进行运算再去进行赋值,内部的SPI 计数器就不会因为CLK数据的变化引起误操作。 1.7.2 SPI 通信BSY标志位 在SPI程序编写的过程中,轮询使用BSY作为检测标志位,传送数据丢失或者是错误。这是因为GD的BSY标志位不是在写入DR后就置位的,而是有很小的一个延时后才置起的。传输过程中不要使用BSY作为每次传输的判断,使用TXE和 RXNE来进行判断。
1.7.3 SPI 控制寄存器1 (SPI_CR1 )配置流程 客户如果从低到高一位一位配置该寄存器会出现MODF的错误,经过排查是由于GD的MCU在SPE使能之前就开始检测是否有模式错误,而ST是在SPE使能之后,所以在MSTR写1之前要保证模式正确。SSM为0时保证外接高电平或者SSM和SSI都写1或者是把SSOE 打开。130\ 150没有该问题. 案例:BIDIMODE=0;RXONLY=0;MSTR=1;DFF=0;CPOL=0;CPHA=0;SSM=1; SSOE=1;TXEIE=1 ;BR=2;LSBFIRST=0;CRCPOLY=7;SPE=1; 这个顺序在ST上正常,在GD上出现MODF错误,解决的话可以将整个寄存器一次写入, 也可调整初始化顺序,同时加上SSI的配置。 1.7.4 SPI CLK时钟线配置 小容量的产品,CK线需要将IO配置成input_floating,才能正常工作,大容量不需要这样配置。 1.8 I2C方面的说明 1.8.1 查询法I2C寻址判断 在使用I2C编程的时候需要修改固件库stm32f10x_i2c.h中的两个宏定义 #define I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED ((uint32_t)0x00060082) #define I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED ((uint32_t)0x00070082) 修改为: #define I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED ((uint32_t)0x00060002) #define I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED ((uint32_t)0x00070002) 1.8.2 函数I2C_CheckEvent修改 使用V3.5.0之前的固件库需要修改I2C_CheckEvent函数。
修改前: ErrorStatusI2C_CheckEvent(I2C_TypeDef* I2Cx, uint32_t I2C_EVENT) { uint32_tlastevent = 0; uint32_tflag1 = 0, flag2 = 0; ErrorStatusstatus = ERROR; /*Check the parameters */ assert_param(IS_I2C_ALL_PERIPH(I2Cx)); assert_param(IS_I2C_EVENT(I2C_EVENT)); /*Read the I2Cx status register */ flag1 = I2Cx->SR1; flag2 = I2Cx->SR2; flag2 = flag2 << 16; /*Get the last event value from I2C status register */ lastevent = (flag1 | flag2) &FLAG_Mask; /*Check whether the last event contains the I2C_EVENT */ if(lastevent == I2C_EVENT) { /* SUCCESS: last event is equal toI2C_EVENT */ status = SUCCESS; } else { /* ERROR: last event is different fromI2C_EVENT */ status = ERROR; } /* Return status */ return status; } 修改后: ErrorStatusI2C_CheckEvent(I2C_TypeDef* I2Cx, uint32_t I2C_EVENT) { uint32_t lastevent = 0; uint32_t flag1 = 0, flag2 = 0; ErrorStatus status = ERROR; /* Check the parameters */ assert_param(IS_I2C_ALL_PERIPH(I2Cx)); assert_param(IS_I2C_EVENT(I2C_EVENT)); /*Read the I2Cx status register */ flag1 = I2Cx->SR1; flag2 = I2Cx->SR2; flag2 = flag2 << 16; /* Get the last event value from I2C statusregister */ lastevent =(flag1 | flag2) & FLAG_Mask; /* Check whether the last event contains theI2C_EVENT */ if ((lastevent & I2C_EVENT) ==I2C_EVENT) { /* SUCCESS: last event is equal to I2C_EVENT*/ status = SUCCESS; } else { /*ERROR: last event is different from I2C_EVENT */ status = ERROR; } /*Return status */ return status; } 1.9 USART方面的说明 1.9.1 USART连续发送数据问题 GD的MCU和ST的相比在连续发送的时候会多一个IDLE bit。对于客户的应用基本没有影响,只是会影响连续发送的时候的发送时间。 1.9.2 USART停止位问题 GD32 USART发送的时候只发送1 bit或2 bit停止位,如果配制成0.5bit则发送1bit。如果配制成1.5bit则发送2bit停止位。 2.10 Flash方面的说明 2.10.1 Flash操作修改要点 GD的Flash执行速度快,但是写操作慢,所以在对Flash操作的时 候需要修改下面几个函数: FLASH_StatusFLASH_EraseOptionBytes(void); FLASH_StatusFLASH_ProgramOptionByteData(uint32_t Address, uint8_t Data); FLASH_StatusFLASH_EnableWriteProtection(uint32_t FLASH_Pages); FLASH_StatusFLASH_ReadOutProtection(FunctionalState NewState);
在这四个函数写完key (FLASH->OPTKEYR = FLASH_KEY1; FLASH->OPTKEYR =FLASH_KEY2;) 后添加两个__nop()语句或者是增加 While( !(FLASH->CR & 0x200 ) );// Wait OPTWRE 语句来增加等待的时间。同时修改擦出和写的超时宏定义: #define EraseTimeout((uint32_t)0x000B0000) #defineProgramTimeout((uint32_t)0x00002000) 修改为: #define EraseTimeout((uint32_t)0x000FFFFF) #defineProgramTimeout((uint32_t)0x0000FFFF) 2.10.2 Flash起始地址 当写操作是,必须采用绝对地址,也就是0x08000000为首地址。而对于读操作,也可以用0x00000000作为首地址去读main flash 2.10.3 lash速度 HD容量以上芯大于256K 以上Flash的速度很慢。 需要手动调整链接脚本,让对速度敏感的数据、代码的链接地址位于256K前,对于ARM-MDK来说,就是编辑.sct分散加载文件 2.11 USB方面的说明 2.11.1 USB外设工作频率限制 有最低工作频率的要求,也就是APB1分频后的时钟必须大于12MHz,比如HCLK为56MHz,APB1 的最大分频系数为4,56/4 = 14MHz,可以正常工作。软件编写的时候要保证USB设置的时钟大于12M。 2.11.2 USB ESOF产生有点异常 应为esof 中断产生有点异常,所以需要修改中断屏蔽位: 将usb_conf.h中的 #define IMR_MSK (CNTR_CTRM | CNTR_WKUPM | CNTR_SUSPM | CNTR_ERRM | CNTR_SOFM \ | CNTR_ESOFM | CNTR_RESETM ) 改成 #define IMR_MSK (CNTR_CTRM | CNTR_WKUPM | CNTR_SUSPM | CNTR_ERRM | CNTR_SOFM \ | CNTR_RESETM ) 或者彻底点改成 #define IMR_MSK (CNTR_CTRM | CNTR_SOFM | CNTR_RESETM)
|