stm32f105移植到gd32f305笔记

背景知识

stm32f105芯片和gd32f305芯片都有2个内部CAN,stm32f105芯片是CAN1和CAN2,gd32f305芯片是CAN0和CAN1,stm32f105芯片的CAN1和gd32f305芯片的CAN0是对应关系,stm32f105芯片的CAN2和gd32f305芯片的CAN1是对应关系。

为了描述方便和避免误解,如果没有特殊说明,用CANa来表述stm32f105芯片的CAN1和gd32f305芯片的CAN0,用CANb来表述stm32f105芯片的CAN2和gd32f305芯片的CAN1。用stm代称stm32f105芯片,用gd代称gd32f305芯片。

stm和gd对CAN寄存器的命名完全不同,但是寄存器的地址排列次序是一致的,并且寄存器内部的字段位置也一致。比如:
stm的CAN 主控制寄存器 (CAN_MCR,地址偏移量: 0x00),包含字段RESET、TTCM、ABOM、AWUM、NART、RFLM、TXFP、SLEEP、INRQ。
gd的CAN 控制寄存器 (CAN_CTL,地址偏移量: 0x00),包含字段DFZ(新增)、SWRST、TTC、ABOR、AWU、ARD、RFOD、TFO、SLPWMOD、IWMOD。

修改说明

STM_HAL库版本:2016。
所有的代码修改都在// zyb begin 和 // zyb end之间。
目前的代码修改兼容stm和gd。

修改一

现象描述

使用gd芯片,程序调用stm32f1xx_hal_can.c的HAL_CAN_Init函数返回错误。

原因分析

stm和gd在初始化后,位CAN_MCR.SLEEP都默认为1。

HAL_CAN_Init函数在运行代码SET_BIT(hcan->Instance->MCR, CAN_MCR_INRQ)后,会等待位CAN_MSR.INAK置1,如果等待时间超时,则HAL_CAN_Init函数返回错误。

stm在位CAN_MCR.INRQ被置1后,位CAN_MSR.INAK不受位MCR.SLEEP影响,也被置1;而gd只有在位CAN_MCR.SLEEP为0时,位CAN_MCR.INRQ被置1后,位CAN_MSR.INAK才能被置1。

解决思路

在HAL_CAN_Init函数调用代码SET_BIT(hcan->Instance->MCR, CAN_MCR_INRQ)前清零MCR.SLEEP为0。

修改内容

在HAL_CAN_MspInit函数的最后加上代码:

CLEAR_BIT(canHandle->Instance->MCR, CAN_MCR_SLEEP);

或者在调用HAL_CAN_Init函数前,调用HAL_CAN_WakeUp函数。

运行结果

stm和gd都能够正常初始化CAN。

修改二

现象描述

gd在连续调用stm32f1xx_hal_can.c中的HAL_CAN_AddTxMessage函数发送2包数据时,只能发送第1包数据,第2包数据无法发送到CAN总线上。

原因分析

2个芯片的文档描述有不同。
stm的CAN发送状态寄存器CAN_TSR的邮箱号CODE[1:0]字段描述:
当有至少1个发送邮箱为空时,邮箱号为下一个空的发送邮箱号。
当所有的发送邮箱都为空时,邮箱号为优先级最低的那个发送邮箱号。

对应的gd的CAN发送状态寄存器 (CAN_TSTAT)的邮箱号NUM[1:0]字段描述:
当发送 FIFO 不满时,NUM 表示下一个将要发送的邮箱号。
当发送 FIFO 满时,NUM 表示最后一个将要发送的邮箱号。

查看STM_HAL库的HAL_CAN_AddTxMessage函数,相关代码为:
transmitmailbox = (tsr & CAN_TSR_CODE) >> CAN_TSR_CODE_Pos;
查看gd32库的can_message_transmit函数,相关代码为:

   if(CAN_TSTAT_TME0 == (CAN_TSTAT(can_periph)&CAN_TSTAT_TME0)){
       mailbox_number = CAN_MAILBOX0;
   }else if(CAN_TSTAT_TME1 == (CAN_TSTAT(can_periph)&CAN_TSTAT_TME1)){
       mailbox_number = CAN_MAILBOX1;
   }else if(CAN_TSTAT_TME2 == (CAN_TSTAT(can_periph)&CAN_TSTAT_TME2)){
       mailbox_number = CAN_MAILBOX2;
   }else{
       mailbox_number = CAN_NOMAILBOX;
   }

解决思路

修改STM_HAL库的HAL_CAN_AddTxMessage函数中处理CODE[1:0]字段的代码,调整为和gd32库的can_message_transmit函数中类似的代码。

修改内容

把代码

	transmitmailbox = (tsr & CAN_TSR_CODE) >> CAN_TSR_CODE_Pos;

修改为如下代码:

	if(CAN_TSR_TME0 == (tsr & CAN_TSR_TME0))
	{
		transmitmailbox = 0;
	}else if(CAN_TSR_TME1 == (tsr & CAN_TSR_TME1))
	{
		transmitmailbox = 1;
	}else if(CAN_TSR_TME2 == (tsr & CAN_TSR_TME2))
	{
		transmitmailbox = 2;
	}else
	{
		transmitmailbox = 3;
	}

运行结果

stm和gd都能够连续发送2包CAN数据。

修改三

现象描述

同样的代码,stm能够正常发送和接收can数据,但是gd的CANa能成功发送数据,却接收不到CAN总线上的数据。

原因分析

查看2个芯片的文档。stm的CAN过滤器寄存器CAN_FMR的字段CAN2SB[5:0]和gd的CAN过滤器控制寄存器CAN_FCTL的字段HBC1F[5:0],是对应关系。stm和gd的文档描述基本一致。

CAN_FMR.AN2SB[5:0]的描述:
CAN2(CANb)过滤器单元开始位置。
CAN2SB[5:0]=28d,所有过滤器都能被CAN1(CANa)使用。
CAN2SB[5:0]=0d,所有过滤器都不能被CAN1(CANa)使用。

CAN_FCTL.HBC1F[5:0]的描述:
CAN1(CANb)过滤器单元起始位置。
这些位用来定义CAN1(CANb)过滤器起始位置。CAN0(CANa)可以用编号为0HBC1F-1过滤器,CAN1(CANb)可以用编号为HBC1F27过滤器。当这些位的值为0,CAN0(CANa)将没有过滤器可以使用。当这些位的值为28时,CAN1(CANb)将没有过滤器可以使用。

使用stm调试程序时,发现CAN_FMR.CAN2SB[5:0]被置为0,按照文档描述,CANa将接收不到数据,但实际运行程序却可以接收到数据。

使用gd调试程序时,发现CAN_FCTL.HBC1F[5:0]被置为0,按照文档描述,CANa将接收不到数据,实际运行程序也接收不到数据。

继续调试程序,发现2个芯片在上电复位后,CAN_FMR.CAN2SB[5:0]和CAN_FCTL.HBC1F[5:0]的初始值都为14(0x0E)。

继续分析代码,发现在调用HAL_CAN_ConfigFilter函数前,没有对sFilterConfig1.SlaveStartFilterBank赋值,因为sFilterConfig1被定义为全局变量,所以sFilterConfig1.SlaveStartFilterBank = 0,导致调用HAL_CAN_ConfigFilter函数后CAN_FMR.CAN2SB[5:0]被置为0。

结论:stm芯片的行为和文档描述不相符,可能是stm芯片的bug。

解决思路

在调用HAL_CAN_ConfigFilter函数前,添加相关代码初始化sFilterConfig1.SlaveStartFilterBank为正确的值。

修改内容

在调用HAL_CAN_ConfigFilter函数前,添加如下代码:sFilterConfig1.SlaveStartFilterBank = 14;

运行结果

stm和gd都能够正常收发CANa数据。

修改四

现象描述

调整了“修改三”的部分代码后,发现gd不能正常收发CANb数据。

原因分析

原代码中,没有调用HAL_CAN_ConfigFilter函数配置CANb的过滤器,估计是CAN_FMR.CAN2SB[5:0]被正确配置后,影响到了CANb的默认过滤器。

解决思路

添加配置CANb过滤器的相关代码。

修改内容

添加配置CANb过滤器的相关代码,并且把sFilterConfig2.FilterBank赋值为15,表示使用过滤器15,和sFilterConfig2.SlaveStartFilterBank = 14相匹配。

运行结果

stm和gd都能够正常收发CANb数据。

修改五

现象描述

使用gd,原程序在连续调用stm32f1xx_hal_can.c中的HAL_CAN_AddTxMessage函数发送4包数据时,只能成功发送第1、2、4包数据,第3包数据无法发送到CAN总线上。

原因分析

原代码中,发现在调用HAL_CAN_AddTxMessage函数前,程序会调用HAL_CAN_IsTxMessagePending函数判断当前发送邮箱是否为空(通过CAN_TSR.TMEx是否为1来判断),如果不为空,则继续调用HAL_CAN_IsTxMessagePending函数判断,直到当前发送邮箱为空或者超时计数到0为止,超时计数值初始总数为200。如果最后超时计数值到0,则调用HAL_CAN_AbortTxRequest函数终止当前邮箱的数据发送。

代码如下(已做简化):

	UINT32 timeout = 200;
	while (HAL_CAN_IsTxMessagePending(&hcan1, dockTxMailBox) == TRUE && (timeout--))
	{
	    if (timeout == 0)
	    {
	        HAL_CAN_AbortTxRequest(&hcan1, dockTxMailBox);
	    }
	}

使用stm调试,发现将超时计数值调整为<190,背板也出现和gd一样的情况,背板只能发送第1、2、4包数据;将超时计数值调整为190~300,程序会触发超时条件调用HAL_CAN_AbortTxRequest函数,但是能完整发送第1、2、3、4包数据;将超时计数值调整为>300,程序不会触发超时条件,说明当前邮箱的数据已经成功发送,也就不会调用HAL_CAN_AbortTxRequest函数终止当前邮箱的数据发送。

使用gd调试,发现将超时计数值调整为<255,背板只能发送第1、2、4包数据;将超时计数值调整为255~395,程序会触发超时条件调用HAL_CAN_AbortTxRequest函数,但是能完整发送第1、2、3、4包数据;将超时计数值调整为>395,程序不会触发超时条件,说明当前邮箱的数据已经成功发送,也就不会调用HAL_CAN_AbortTxRequest函数终止当前邮箱的数据发送。

根据上述分析和调试,得出异常原因:由于程序先判断当前发送邮箱是否为空和超时判断,条件满足再终止当前邮箱的数据发送,这个过程有一个时间差,就会出现如下描述的情况,在程序调用HAL_CAN_AbortTxRequest函数终止当前邮箱的数据发送前(通过置位CAN_TSR.ABRQx来终止),实际当前邮箱的数据正好刚刚发送完。使用stm,虽然程序会触发超时条件,但是因为上述情况,实际程序并没有真正的终止当前邮箱的数据发送,背板工作正常。使用gd,因为gd在同主频下的运行速度比stm快,原程序中200的超时计数值不能让程序在终止当前邮箱的数据发送前把数据完整的发送出去,也就是说HAL_CAN_AbortTxRequest函数起作用了,待发送的数据真正被终止了。

解决思路

原程序中的超时计数值200太小,刚好在临界范围内,根据测试的结果,使用gd超时计数值至少要设置成>400。

修改内容

在dcan_dock::can_tx_api函数中把UINT32 timeout = 200;修改成UINT32 timeout = 10000;
在dcan_pump2::can_tx_api函数中把UINT32 timeout = 500;修改成UINT32 timeout = 10000;
在canspi::transmit函数中把uint32_t timeout = 500;修改成uint32_t timeout = 10000;

这个修改并不完美,超时计数值没有考虑CAN波特率,芯片时钟频率和芯片厂家不同等因素。目前CAN使用的波特率是500kHz,考虑到以后可能会使用较小波特率,所以把超时计数定了个较大值10000。

运行结果

stm和gd都能够正常发送多包数据。

STM32F4 和 GD32F4 都是基于ARM Cortex-M4内核的微控制器系列,因此在移植这两个系列之间不会涉及到太多的硬件和指令集方面的差异。所以可以通过以下步骤将STM32F4移植GD32F4上: 1. 开发环境的准备:首先,需要下载并安装GD32的开发工具链和开发板的驱动程序,可在官方网站上获取。然后,将原来为STM32F4编写的代码和工程文件导入到GD32的开发环境中。 2. 底层驱动的替换:由于GD32F4和STM32F4在外设控制器的寄存器映射和配置上可能有一些差异,需要修改底层驱动层的相关代码。替换原来的STM32外设驱动代码为GD32外设驱动代码,并根据GD32的数据手册调整相关寄存器的配置。 3. 系统时钟的配置:STM32GD32的系统时钟配置方式可能有所不同,需要根据GD32的数据手册重新配置系统时钟。通常情况下,GD32的时钟配置方式与STM32相似,可以通过修改相关寄存器的值来实现。 4. 中断和中断向量表的处理:GD32的中断向量表可能与STM32不同,需要根据GD32的数据手册进行相应的修改。另外,如果在工程中使用了中断,需要将原来的中断服务函数与新的中断向量表进行对应。 5. 硬件资源的适配:GD32开发板上的引脚配置和STM32开发板上的可能有一些差异,需要根据实际情况进行适配。可以通过修改引脚映射和配置文件来实现。 6. 编译、调试和测试:进行移植后,需要重新编译和链接工程,并通过调试工具对代码进行调试。同时,还需要进行严格的测试来确保软硬件的兼容性和正常运行。 需要注意的是,尽管STM32F4和GD32F4在硬件和指令集上非常相似,但仍然存在一些差异和不兼容性。因此,在移植过程中需要仔细检查和调试代码,确保系统的稳定性和可靠性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值