gd32f450 freertos移植,iap教程

1  freertos移植主要参考以下这篇文章

https://www.freesion.com/article/41971435876/

2 GD32F450+LAN8720A,#FreeRTOS_Plus_TCP 网络协议栈移植教程

https://blog.csdn.net/weixin_45775305/article/details/128643872

注意: 移植的时候注意phy地址是否和文中的一样。

3 基于串口ymodem的iap的程序升级主要参考以下这篇文章

【开源】串口YMODEM实现IAP程序升级(附工程源码)

​​​​​​【开源】串口YMODEM实现IAP程序升级(附工程源码)_ymodem工具_freemote的博客-CSDN博客
相较于原作者修改的地方在

(1) 

(2)使用gd32f450的flash的读写接口GDFLASH_Write();  flash的具体读写代码参考

立创梁山派GD32F450ZGT6--内部FLASH的读写_gd32f4 fmc_老怪.的博客-CSDN博客

4 基于tcp的iap的升级程序

首先要保证第2步骤中能ping通

tcp iap程序较大,故bootloader rom设置大一些,如图

主要关键代码如下:

实现了一个tcp服务器模型,ip 192.168.1.11,端口8088 ,打开一个网口调试助手,设置tcp client,5s内连接该tcp服务器,5s后,tcp server端若没有客户端链接,直接执行iap_load_app,跳转执行app,然后发送要烧写app的bin文件,发送完成后,发送 字符串 "send ok",tcp server端收到send ok,开始跳转,执行app程序,

#include "main.h"
#include "trng.h"

/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
 
/* FreeRTOS+TCP includes. */
#include "FreeRTOS_IP.h"
#include "FreeRTOS_Sockets.h"
#include "flash.h"
 

uint8_t ucMACAddress[ 6 ] = { configMAC_ADDR0, configMAC_ADDR1, configMAC_ADDR2, configMAC_ADDR3, configMAC_ADDR4, configMAC_ADDR5 };
uint8_t ucIPAddress[ 4 ] = { configIP_ADDR0, configIP_ADDR1, configIP_ADDR2, configIP_ADDR3 }; 
uint8_t ucNetMask[ 4 ] = { configNET_MASK0, configNET_MASK1, configNET_MASK2, configNET_MASK3 }; 
uint8_t ucGatewayAddress[ 4 ] = { configGATEWAY_ADDR0, configGATEWAY_ADDR1, configGATEWAY_ADDR2, configGATEWAY_ADDR3 }; 
uint8_t ucDNSServerAddress[ 4 ] = { configDNS_SERVER_ADDR0, configDNS_SERVER_ADDR1, configDNS_SERVER_ADDR2, configDNS_SERVER_ADDR3 }; 



//#define BOOT_REC_LEN 256*1024 //定义最大接收字节数
#define FLASH_APP1_ADDR 0x08080000

//uint8_t BOOT_RX_BUF[BOOT_REC_LEN] __attribute__ ((at(0X20021000)));//接收缓冲

uint32_t FlashDestination = FLASH_APP1_ADDR; /* Flash user program offset */
typedef  void  (*pAppFunction) (void);
pAppFunction application;
uint32_t iapbuf[512]; 	//2K字节缓存

void usart0_init(void);											 
void Delay (uint32_t count)
{
	uint32_t i,t;
	for (i=count;i>0;i--)
	{
		for(t=10000;t>0;t--);
	}
}			

uint32_t app_address;
void iap_load_app(uint32_t appxaddr)
{
  if (((*(__IO uint32_t*)FLASH_APP1_ADDR) & 0x2FFE0000) == 0x20000000) {
			app_address = *(__IO uint32_t*) (FLASH_APP1_ADDR + 4);
			application = (pAppFunction) app_address;
			__set_MSP(*(__IO uint32_t*) FLASH_APP1_ADDR);
			application();
	}
}

void jumpToApp(void)
{
//	USART_Cmd(USART6, DISABLE);//--__disable_irq()只是禁止CPU去响应中断,没有真正的去屏蔽中断的触发,
//	TIM_Cmd(TIM3, DISABLE); 

	if(((*(uint32_t*)(FLASH_APP1_ADDR+4))&0xFF000000)==0x08000000)//判断是否为0X08XXXXXX.
	{	 
		__disable_irq();
		__set_FAULTMASK(1);//关闭所有中断
	
		iap_load_app(FLASH_APP1_ADDR);//执行FLASH APP代码
	}
}


//appxaddr:应用程序的起始地址
//appbuf:应用程序CODE.
//appsize:应用程序大小(字节).
void iap_write_appbin(uint32_t appxaddr,uint8_t *appbuf,uint32_t appsize)
{
	uint32_t t;
	uint16_t i=0;
	uint32_t temp;
	uint32_t fwaddr=appxaddr;//当前写入的地址
	uint8_t *dfu=appbuf;
	for(t=0;t<appsize;t+=4)
	{						   
		temp=(uint32_t)dfu[3]<<24;   
		temp|=(uint32_t)dfu[2]<<16;    
		temp|=(uint32_t)dfu[1]<<8;
		temp|=(uint32_t)dfu[0];	  
		dfu+=4;//偏移4个字节
		iapbuf[i++]=temp;	    
		if(i==512)
		{
			i=0; 
			GDFLASH_Write(fwaddr,iapbuf,512);
			fwaddr+=2048;//偏移2048  512*4=2048
		}
	} 
	if(i)GDFLASH_Write(fwaddr,iapbuf,i);//将最后的一些内容字节写进去.  
}






/* The maximum time to wait for a closing socket to close. */
#define tcpechoSHUTDOWN_DELAY	( pdMS_TO_TICKS( 5000 ) )
 
// 服务器监听端口
#define tcpechoPORT_NUMBER		8088
 
uint16_t acceptTaskSize;
 
#if 1
static void vAcceptConnectionTask(void *parameters)
{
	int32_t lBytes, lSent, lTotalSent,packet_size ;
	Socket_t xConnectedSocket;
	//static const TickType_t xReceiveTimeOut = pdMS_TO_TICKS( 1000*5 );
	static const TickType_t xSendTimeOut = pdMS_TO_TICKS( 1000 );
	TickType_t xTimeOnShutdown;
	uint8_t *pucRxBuffer = NULL;
	uint32_t tmp=0;
	char cflag[]="send ok";
 
	xConnectedSocket = ( Socket_t ) parameters;
	//pucRxBuffer = ( uint8_t * ) pvPortMalloc( ipconfigTCP_MSS );
	static const TickType_t xReceiveTimeOut = portMAX_DELAY;
	pucRxBuffer = ( uint8_t * ) pvPortMalloc( 110 );
	
	if(pucRxBuffer != NULL)
	{
		FreeRTOS_setsockopt( xConnectedSocket, 0, FREERTOS_SO_RCVTIMEO, &xReceiveTimeOut, sizeof( xReceiveTimeOut ) );
		FreeRTOS_setsockopt( xConnectedSocket, 0, FREERTOS_SO_SNDTIMEO, &xSendTimeOut, sizeof( xReceiveTimeOut ) );
	
		for( ;; )
		{
			/* Zero out the receive array so there is NULL at the end of the string
			when it is printed out. */
			//memset( pucRxBuffer, 0x00, ipconfigTCP_MSS );
			memset( pucRxBuffer, 0x00, 110 );
	
			/* Receive data on the socket. */
			//lBytes = FreeRTOS_recv( xConnectedSocket, pucRxBuffer, ipconfigTCP_MSS, 0 );
			lBytes = FreeRTOS_recv( xConnectedSocket, pucRxBuffer, 100, 0 );
 
			/* If data was received, echo it back. */
			if( lBytes > 0 )
			{
				
				
				//memcpy(&BOOT_RX_BUF[tmp],pucRxBuffer,lBytes);
				tmp=tmp+lBytes;
				//printf("receive lBytes is %d\n\r",lBytes);
				//printf("receive tmp is %d\n\r",tmp);
				//lSent = 0;
				//lTotalSent = 0;
				if(!memcmp(pucRxBuffer,cflag,7)){
					printf("bin file receive is ok\n\r");
					break;
				}
				packet_size = lBytes/4+((lBytes%4)?1:0);
				GDFLASH_Write(FlashDestination,(unsigned int*)pucRxBuffer,packet_size);
				FlashDestination+=lBytes;
				

				
				
				
 			}
			else if(lBytes == 0 )
			{
				/* Socket closed? */
				//printf("receive timeout\n\r");
				printf("receive byte is %d\n\r",tmp);
				break;
			}
		}
		//iap_write_appbin(FLASH_APP1_ADDR,BOOT_RX_BUF,BOOT_REC_LEN);//更新FLASH代码
		jumpToApp();
		
	}
	/* Initiate a shutdown in case it has not already been initiated. */
	FreeRTOS_shutdown( xConnectedSocket, FREERTOS_SHUT_RDWR );
 
	/* Wait for the shutdown to take effect, indicated by FreeRTOS_recv()
	returning an error. */
	xTimeOnShutdown = xTaskGetTickCount();
	do
	{
		if( FreeRTOS_recv( xConnectedSocket, pucRxBuffer, ipconfigTCP_MSS, 0 ) < 0 )
		{
			break;
		}
	} while( ( xTaskGetTickCount() - xTimeOnShutdown ) < tcpechoSHUTDOWN_DELAY );
 
	/* Finished with the socket, buffer, the task. */
	vPortFree( pucRxBuffer );
	FreeRTOS_closesocket( xConnectedSocket );
 
	vTaskDelete( NULL );
}
 
static void vListeningConnectionTask(void *parameters)
{
	//printf("into vListeningConnectionTask\n\r");
	struct freertos_sockaddr xClient, xBindAddress;
	Socket_t xListeningSocket, xConnectedSocket;
	socklen_t xSize = sizeof( xClient );
	//static const TickType_t xReceiveTimeOut = portMAX_DELAY;
	static const TickType_t xReceiveTimeOut = pdMS_TO_TICKS( 1000*5 );
	const BaseType_t xBacklog = 20;
	
	xListeningSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP );
	configASSERT( xListeningSocket != FREERTOS_INVALID_SOCKET );
	
	FreeRTOS_setsockopt( xListeningSocket, 0, FREERTOS_SO_RCVTIMEO, &xReceiveTimeOut, sizeof( xReceiveTimeOut ) );
	
	
	xBindAddress.sin_port = tcpechoPORT_NUMBER;
	xBindAddress.sin_port = FreeRTOS_htons( xBindAddress.sin_port );
	FreeRTOS_bind( xListeningSocket, &xBindAddress, sizeof( xBindAddress ) );
	FreeRTOS_listen( xListeningSocket, xBacklog );
	
	//while(1)
	{
		xConnectedSocket = FreeRTOS_accept( xListeningSocket, &xClient, &xSize );
		configASSERT( xConnectedSocket != FREERTOS_INVALID_SOCKET );
		if(xConnectedSocket==NULL){
			printf("FreeRTOS_accept 5s timeout\n\r");
			jumpToApp();
		}
		printf("have client connect,start receive bin files\n\r");
		//xTaskCreate( vAcceptConnectionTask, "ClientInstance", acceptTaskSize, ( void * ) xConnectedSocket, tskIDLE_PRIORITY, NULL );
		vAcceptConnectionTask(( void * ) xConnectedSocket);
	}
	//while(1);
}
 
void vStartTCPServerTask(uint16_t taskSize, UBaseType_t priority)
{
	//printf("create TCPServerTask\n\r");
	xTaskCreate(vListeningConnectionTask, "TCPServerTask", taskSize, NULL, priority, NULL);
	acceptTaskSize = taskSize;
}
#endif


void start_task(void * pvParameters)
{
    printf("hello\r\n");
	while (1)
	{
		
		vTaskDelay(1000);
	}
}
void enet_inti_task(void * pvParameters)
{
    //printf("into enet_inti_task\n\r");
		trng_init();         //初始化随机数发生器,在FreeRTOS_IPInit之前
    FreeRTOS_IPInit( ucIPAddress, ucNetMask, ucGatewayAddress, ucDNSServerAddress, ucMACAddress ); /* 初始化网络栈*/
	  vTaskDelete(NULL);
}

int main(void)
{
	nvic_priority_group_set(NVIC_PRIGROUP_PRE4_SUB0);
	//uart0_init(115200);
	usart0_init();
	//printf("\n\rUSART printf example1112\n\r");
	
	xTaskCreate(enet_inti_task , "enet_inti_task" , 128, NULL , 12 , NULL);
	xTaskCreate(start_task , "start_task" , 128, NULL , 10 , NULL);
	vStartTCPServerTask(128,8);
	vTaskStartScheduler();			
	while(1)
	{
		printf("freertos error\r\n");
	}
}

void usart0_init(void)
{
    rcu_periph_clock_enable( RCU_GPIOA);

    /* enable USART clock */
    rcu_periph_clock_enable(RCU_USART0);

    /* connect port to USARTx_Tx */
    gpio_af_set(GPIOA,GPIO_AF_7, GPIO_PIN_9);

    /* connect port to USARTx_Rx */
    gpio_af_set(GPIOA, GPIO_AF_7, GPIO_PIN_10);

    /* configure USART Tx as alternate function push-pull */
    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP,GPIO_PIN_9);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_9);

    /* configure USART Rx as alternate function push-pull */
    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP,GPIO_PIN_10);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_10);

    /* USART configure */
    usart_deinit(USART0);
    usart_baudrate_set(USART0,115200U);
    usart_receive_config(USART0, USART_RECEIVE_ENABLE);
    usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);
    usart_enable(USART0);	
}
int fgetc(FILE *f)
{
		/* ???????? */
		while (!usart_flag_get(USART0, USART_FLAG_RBNE));
 
		return (int)usart_data_receive(USART0);
}

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
STM32和GD32都是基于ARM Cortex-M内核的微控制器。因此,我们可以通过移植的方式将STM32的应用程序移植GD32F450上运行。 移植的过程主要包括以下几个步骤: 1. 硬件兼容性的评估:首先需要评估STM32和GD32F450之间的硬件兼容性。包括引脚定义和功能,外设接口,时钟配置等。确保GD32F450能够满足STM32应用程序的硬件需求。 2. 代码移植:将STM32的应用程序代码移植GD32F450上。这需要根据GD32F450的器件文档和引脚定义对代码进行修改。例如,将与引脚相关的代码进行调整,确保外设的初始化和配置正确。 3. 外设适配:GD32F450和STM32之间可能存在一些外设差异。在移植过程中,需要对外设进行适配,确保GD32F450上的外设能够与STM32的应用程序正确交互。 4. 系统时钟配置:根据GD32F450的时钟配置要求,对应用程序的系统时钟进行调整。确保系统时钟的稳定性和准确性。 5. 编译和调试:对移植后的代码进行编译和调试。根据GD32F450开发工具和环境,对代码进行编译和烧录,然后通过调试工具对程序进行调试。 在移植过程中,需要对应用程序的硬件相关代码进行修改,以适配GD32F450的硬件和外设。同时还需注意时钟配置和系统初始化的差异,以确保移植后的应用程序能够在GD32F450上正常运行。 综上所述,将STM32的应用程序移植GD32F450主要涉及硬件兼容性评估、代码移植、外设适配、系统时钟配置和编译调试等步骤。通过仔细的修改和调试,我们可以成功地将STM32应用程序移植GD32F450上运行。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值