ZYNQ 使用网口或串口实现程序保存或升级

一,ZYNQ使用网口实现BOOT.BIN在线升级

1,这个模块能使用的前提是在vivado工程中勾选FLASH配置和eth0或eth1支持(不然硬件不支持后面文件会报错)。无论是裸机还是带操作系统升级程序都需要勾选。

ZYNQ 使用网口或串口实现程序保存或升级_第1张图片

2,SDK裸机实现程序升级,进入需要使能 lwip 141库,并进行设置

ZYNQ 使用网口或串口实现程序保存或升级_第2张图片

3,use_axieth_on_zynq 和 use_emaclite_on_zynq 设为 0;修改 lwip_memory_options 设置,将 mem_size,memp_n_pbuf 这 2 个参数值设大,这样会提高 UDP 传输效率。修改 pbuf_options 设置,将 pbuf_pool_size 设大,增加可用的 pbuf 数量,这样同样会提高 UDP 传输效率。修改 tcp_options 设置,将 lwip_tcp 设置为 false,tcp_queue_ooseq 设为 0,关闭 tcp功能;配置如图:

ZYNQ 使用网口或串口实现程序保存或升级_第3张图片

4,此项不是必须设置的,如果为了提高升级效率可以进行配置。修改 temac_adapter_options 设置,将 n_rx_descriptors 和 n_tx_descriptors 参数设大。这样可以提高 zynq 内部 emac dma 的数据搬移效率:

ZYNQ 使用网口或串口实现程序保存或升级_第4张图片

5,使能 DHCP 功能,将 memory 空间尽可能设置大一些,增大缓存空间,提高效率,,前面已经设置过了

ZYNQ 使用网口或串口实现程序保存或升级_第5张图片

6,将qspi_update模块添加到SDK工程里面,里面包含了qspi.h和qspi.c头文件

qspi.h

#ifndef SRC_QSPI_H_
#define SRC_QSPI_H_
#include "xparameters.h"	/* SDK generated parameters */
#include "xqspips.h"		/* QSPI device driver */
#include "xil_printf.h"
#define QSPI_DEVICE_ID		XPAR_XQSPIPS_0_DEVICE_ID
#define WRITE_STATUS_CMD	0x01
#define WRITE_CMD		0x02
#define READ_CMD		0x03
#define WRITE_DISABLE_CMD	0x04
#define READ_STATUS_CMD		0x05
#define WRITE_ENABLE_CMD	0x06
#define FAST_READ_CMD		0x0B
#define DUAL_READ_CMD		0x3B
#define QUAD_READ_CMD		0x6B
#define BULK_ERASE_CMD		0xC7
#define	SEC_ERASE_CMD		0xD8
#define READ_ID			0x9F
#define COMMAND_OFFSET		0 /* FLASH instruction */
#define ADDRESS_1_OFFSET	1 /* MSB byte of address to read or write */
#define ADDRESS_2_OFFSET	2 /* Middle byte of address to read or write */
#define ADDRESS_3_OFFSET	3 /* LSB byte of address to read or write */
#define DATA_OFFSET		4 /* Start of Data for Read/Write */
#define DUMMY_OFFSET		4 /* Dummy byte offset for fast, dual and quad
				     reads */
#define DUMMY_SIZE		1 /* Number of dummy bytes for fast, dual and
				     quad reads */
#define RD_ID_SIZE		4 /* Read ID command + 3 bytes ID response */
#define BULK_ERASE_SIZE		1 /* Bulk Erase command size */
#define SEC_ERASE_SIZE		4 /* Sector Erase command + Sector address */
#define OVERHEAD_SIZE		4
#define SECTOR_SIZE		0x10000
#define NUM_SECTORS		0x100
#define NUM_PAGES		0x10000
#define PAGE_SIZE		256
#define PAGE_COUNT		16
#define TEST_ADDRESS		0x00055000
#define UNIQUE_VALUE		0x05
#define MAX_DATA		PAGE_COUNT * PAGE_SIZE
int update_qspi(XQspiPs *QspiInstancePtr, u16 QspiDeviceId, unsigned int TotoalLen, char *FlashDataToSend) ;
#endif /* SRC_QSPI_H_ */
/***************************** Include Files *********************************/
#include "qspi.h"
#include "xtime_l.h"
#include "stdio.h"
/**************************** Type Definitions *******************************/

/***************** Macros (Inline Functions) Definitions *********************/

/************************** Function Prototypes ******************************/
void FlashWriteEnable(XQspiPs *QspiPtr);

void FlashWriteDisable(XQspiPs *QspiPtr) ;

void FlashErase(XQspiPs *QspiPtr, u32 Address, u32 ByteCount);

void FlashWrite(XQspiPs *QspiPtr, u32 Address, u32 ByteCount, u8 Command);

void FlashRead(XQspiPs *QspiPtr, u32 Address, u32 ByteCount, u8 Command);

int FlashReadID(void);

void print_percent(int percent) ;

/************************** Variable Definitions *****************************/
XQspiPs QspiInstance;

/*
 * The following variables are used to read and write to the flash and they
 * are global to avoid having large buffers on the stack
 */
u8 ReadBuffer[PAGE_SIZE + DATA_OFFSET + DUMMY_SIZE];
u8 WriteBuffer[PAGE_SIZE + DATA_OFFSET];
int update_qspi(XQspiPs *QspiInstancePtr, u16 QspiDeviceId, unsigned int TotoalLen, char *FlashDataToSend)
{
	int Status;
	int i ;
	unsigned int HasSendNum = 0 ;
	unsigned int WriteAddr = 0 ;
	unsigned int HasRecvNum = 0 ;
	unsigned int ReadAddr = 0 ;
	XTime TimerStart, TimerEnd;
	float elapsed_time ;

	int PercentCurr = -1 ;
	int PercentLast = -1 ;

	XQspiPs_Config *QspiConfig;

	/*
	 * Initialize the QSPI driver so that it's ready to use
	 */
	QspiConfig = XQspiPs_LookupConfig(QspiDeviceId);
	if (NULL == QspiConfig) {
		return XST_FAILURE;
	}

	Status = XQspiPs_CfgInitialize(QspiInstancePtr, QspiConfig,
			QspiConfig->BaseAddress);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}
	XQspiPs_SetOptions(QspiInstancePtr, XQSPIPS_MANUAL_START_OPTION |
			XQSPIPS_FORCE_SSELECT_OPTION |
			XQSPIPS_HOLD_B_DRIVE_OPTION);
	XQspiPs_SetClkPrescaler(QspiInstancePtr, XQSPIPS_CLK_PRESCALE_8);
	XQspiPs_SetSlaveSelect(QspiInstancePtr);


	FlashReadID();
	printf("Performing Erase Operation...\r\n") ;
	XTime_SetTime(0) ;
	XTime_GetTime(&TimerStart) ;
	FlashErase(QspiInstancePtr, 0, TotoalLen);
	XTime_GetTime(&TimerEnd) ;
	printf("100%%\r\n") ;
	elapsed_time = ((float)(TimerEnd-TimerStart))/((float)COUNTS_PER_SECOND) ;
	printf("INFO:Elapsed time = %.2f sec\r\n", elapsed_time) ;
	printf("Erase Operation Successful.\r\n") ;
	printf("Performing Program Operation...\r\n") ;
	XTime_SetTime(0) ;
	XTime_GetTime(&TimerStart) ;
	do
        {
		PercentCurr = (int)(((float)HasSendNum/(float)TotoalLen)*10) ;
		if (PercentCurr != PercentLast)
			print_percent(PercentCurr) ;
		PercentLast = PercentCurr ;
		if ((HasSendNum+PAGE_SIZE) > TotoalLen)
		{
			for (i = 0 ; i < PAGE_SIZE ; i++)
			{
				if (i >= TotoalLen-HasSendNum)
				{
					WriteBuffer[DATA_OFFSET + i] = 0 ;
				}
				else
				{
		WriteBuffer[DATA_OFFSET + i] = (u8)(FlashDataToSend[HasSendNum+i]);
				}
			}
			FlashWrite(QspiInstancePtr, WriteAddr, PAGE_SIZE, WRITE_CMD);
			printf("100%%\r\n") ;
			XTime_GetTime(&TimerEnd) ;
			elapsed_time = (float)(TimerEnd-TimerStart)/(COUNTS_PER_SECOND) ;
			printf("INFO:Elapsed time = %.2f sec\r\n", elapsed_time) ;
			printf("Program Operation Successful.\r\n") ;
			HasSendNum+= PAGE_SIZE ;
		}
		else
		{
			for (i = 0 ; i < PAGE_SIZE ; i++)
			{
				WriteBuffer[DATA_OFFSET + i] = (u8)(FlashDataToSend[HasSendNum+i]);
			}
			FlashWrite(QspiInstancePtr, WriteAddr, PAGE_SIZE, WRITE_CMD);
			HasSendNum+= PAGE_SIZE ;
			WriteAddr+= PAGE_SIZE ;
		}
	}while(HasSendNum < TotoalLen) ;
	HasSendNum = 0 ;
	WriteAddr = 0 ;
	printf("Performing Verify Operation...\r\n") ;
	memset(ReadBuffer, 0x00, sizeof(ReadBuffer));
	XTime_SetTime(0) ;
	XTime_GetTime(&TimerStart) ;
	do{
		PercentCurr = (int)(((float)HasRecvNum/(float)TotoalLen)*10) ;

		if (PercentCurr != PercentLast)
			print_percent(PercentCurr) ;

		PercentLast = PercentCurr ;
		if ((HasRecvNum+PAGE_SIZE) > TotoalLen)
		{
			FlashRead(QspiInstancePtr, ReadAddr, PAGE_SIZE, FAST_READ_CMD);
			for (i = 0 ; i < TotoalLen-HasRecvNum; i++)
			{
				if (ReadBuffer[DATA_OFFSET + DUMMY_SIZE+i] != (u8)(FlashDataToSend[HasRecvNum+i]))
				{
					printf("Verify data error, address is 0x%x\tSend Data is 0x%x\tRead Data is 0x%x\r\n",			ReadAddr+i+1,FlashDataToSend[HasRecvNum+i], ReadBuffer[DATA_OFFSET + DUMMY_SIZE+i]) ;
					break ;
				}
			}
			HasRecvNum+= PAGE_SIZE ;
			printf("100%%\r\n") ;
			XTime_GetTime(&TimerEnd) ;
			elapsed_time = (float)(TimerEnd-TimerStart)/(COUNTS_PER_SECOND) ;
			printf("INFO:Elapsed time = %.2f sec\r\n", elapsed_time) ;
			printf("Verify Operation Successful.\r\n") ;
		}
		else
		{
			FlashRead(QspiInstancePtr, ReadAddr, PAGE_SIZE, FAST_READ_CMD);
			for (i = 0 ; i < PAGE_SIZE ; i++)
			{
				if (ReadBuffer[DATA_OFFSET + DUMMY_SIZE+i] != (u8)(FlashDataToSend[HasRecvNum+i]))
				{
					printf("Verify data error, address is 0x%x\tSend Data is 0x%x\tRead Data is 0x%x\r\n",
							ReadAddr+i+1,FlashDataToSend[HasRecvNum+i], ReadBuffer[DATA_OFFSET + DUMMY_SIZE+i]) ;
					break ;
				}
			}
			HasRecvNum+= PAGE_SIZE ;
			ReadAddr+= PAGE_SIZE ;
		}
	}while(HasRecvNum < TotoalLen) ;
	HasRecvNum = 0 ;
	ReadAddr = 0 ;
	return XST_SUCCESS;
}

void FlashWrite(XQspiPs *QspiPtr, u32 Address, u32 ByteCount, u8 Command)
{
	u8 WriteEnableCmd = { WRITE_ENABLE_CMD };
	u8 ReadStatusCmd[] = { READ_STATUS_CMD, 0 };  /* must send 2 bytes */
	u8 FlashStatus[2];
	XQspiPs_PolledTransfer(QspiPtr, &WriteEnableCmd, NULL,sizeof(WriteEnableCmd));
	WriteBuffer[COMMAND_OFFSET]   = Command;
	WriteBuffer[ADDRESS_1_OFFSET] = (u8)((Address & 0xFF0000) >> 16);
	WriteBuffer[ADDRESS_2_OFFSET] = (u8)((Address & 0xFF00) >> 8);
	WriteBuffer[ADDRESS_3_OFFSET] = (u8)(Address & 0xFF);
	XQspiPs_PolledTransfer(QspiPtr, WriteBuffer, NULL,
			ByteCount + OVERHEAD_SIZE);
	while (1) 
        {
		XQspiPs_PolledTransfer(QspiPtr, ReadStatusCmd, FlashStatus,
				sizeof(ReadStatusCmd));
		if ((FlashStatus[1] & 0x01) == 0) 
                {
			break;
		}
	}
}
void FlashRead(XQspiPs *QspiPtr, u32 Address, u32 ByteCount, u8 Command)
{
	WriteBuffer[COMMAND_OFFSET]   = Command;
	WriteBuffer[ADDRESS_1_OFFSET] = (u8)((Address & 0xFF0000) >> 16);
	WriteBuffer[ADDRESS_2_OFFSET] = (u8)((Address & 0xFF00) >> 8);
	WriteBuffer[ADDRESS_3_OFFSET] = (u8)(Address & 0xFF);

	if ((Command == FAST_READ_CMD) || (Command == DUAL_READ_CMD) ||
			(Command == QUAD_READ_CMD)) 
        {
		ByteCount += DUMMY_SIZE;
	}
	XQspiPs_PolledTransfer(QspiPtr, WriteBuffer, ReadBuffer,ByteCount + OVERHEAD_SIZE);
}
void FlashErase(XQspiPs *QspiPtr, u32 Address, u32 ByteCount)
{
	u8 WriteEnableCmd = { WRITE_ENABLE_CMD };
	u8 ReadStatusCmd[] = { READ_STATUS_CMD, 0 };  /* must send 2 bytes */
	u8 FlashStatus[2];
	int Sector;
	unsigned int EraseSecNum ;
	int PercentCurr = -1 ;
	int PercentLast = -1 ;
	if (ByteCount == (NUM_SECTORS * SECTOR_SIZE)) 
        {
		XQspiPs_PolledTransfer(QspiPtr, &WriteEnableCmd, NULL,
				sizeof(WriteEnableCmd));
		WriteBuffer[COMMAND_OFFSET]   = BULK_ERASE_CMD;
		XQspiPs_PolledTransfer(QspiPtr, WriteBuffer, NULL,
				BULK_ERASE_SIZE);
		while (1) 
                {
			XQspiPs_PolledTransfer(QspiPtr, ReadStatusCmd,
					FlashStatus,
					sizeof(ReadStatusCmd));
			if ((FlashStatus[1] & 0x01) == 0) 
                        {
				xil_printf("Bulk Erase Done!\r\n") ;
				break;
			}
		}

		return;
	}
	EraseSecNum = ((ByteCount / SECTOR_SIZE) + 1) ;
	xil_printf("Erase Size is %u Bytes\r\n", EraseSecNum*SECTOR_SIZE) ;
	for (Sector = 0; Sector < EraseSecNum ; Sector++) 
        {
		PercentCurr = (int)(((float)Sector/(float)EraseSecNum)*10) ;
		if (PercentCurr != PercentLast)
			print_percent(PercentCurr) ;
		PercentLast = PercentCurr ;
		XQspiPs_PolledTransfer(QspiPtr, &WriteEnableCmd, NULL,sizeof(WriteEnableCmd));
		WriteBuffer[COMMAND_OFFSET]   = SEC_ERASE_CMD;
		WriteBuffer[ADDRESS_1_OFFSET] = (u8)(Address >> 16);
		WriteBuffer[ADDRESS_2_OFFSET] = (u8)(Address >> 8);
		WriteBuffer[ADDRESS_3_OFFSET] = (u8)(Address & 0xFF);
		XQspiPs_PolledTransfer(QspiPtr, WriteBuffer, NULL,SEC_ERASE_SIZE);
		while (1) 
                {
			XQspiPs_PolledTransfer(QspiPtr, ReadStatusCmd,
					FlashStatus,
					sizeof(ReadStatusCmd));
			if ((FlashStatus[1] & 0x01) == 0) 
                        {
				break;
			}
		}

		Address += SECTOR_SIZE;
	}
}
int FlashReadID(void)
{
	int Status;

	WriteBuffer[COMMAND_OFFSET]   = READ_ID;
	WriteBuffer[ADDRESS_1_OFFSET] = 0x23;		/* 3 dummy bytes */
	WriteBuffer[ADDRESS_2_OFFSET] = 0x08;
	WriteBuffer[ADDRESS_3_OFFSET] = 0x09;
	Status = XQspiPs_PolledTransfer(&QspiInstance, WriteBuffer, ReadBuffer,RD_ID_SIZE);
	if (Status != XST_SUCCESS) 
        {
		return XST_FAILURE;
	}
	xil_printf("FlashID=0x%x 0x%x 0x%x\n\r", ReadBuffer[1], ReadBuffer[2],ReadBuffer[3]);
	return XST_SUCCESS;
}


void print_percent(int percent)
{
	switch(percent)
	{
	case 0 : xil_printf("0%%..") ; break ;
	case 1 : xil_printf("10%%..") ; break ;
	case 2 : xil_printf("20%%..") ; break ;
	case 3 : xil_printf("30%%..") ; break ;
	case 4 : xil_printf("40%%..") ; break ;
	case 5 : xil_printf("50%%..") ; break ;
	case 6 : xil_printf("60%%..") ; break ;
	case 7 : xil_printf("70%%..") ; break ;
	case 8 : xil_printf("80%%..") ; break ;
	case 9 : xil_printf("90%%..") ; break ;
	case 10 : xil_printf("100%..") ; break ;
	default : break ;
	}
}

 7,主函数中加入文件

(1)在主函数main.ct中添加头文件#include "src/qspi_update/qspi.h"

然后再主函数外面添加下列定义:

static struct udp_pcb *udp8080_pcb = NULL;//PS端软件端口号

unsigned int ReceivedCount = 0 ;

unsigned int StartUpdate = 0;//程序升级标志

struct ip_addr target_addr;//接收来自电脑的目标IP地址

#define MAX_FLASH_LEN   32*1024*1024

char FlashRxBuffer[MAX_FLASH_LEN] ;

XQspiPs QspiInstance;

#define IP_ADDR_ANY         ((ip_addr_t *)&ip_addr_any)//绑定IP地址

(2)在主函数添加udp判断函数:udp_recive(void *arg, struct udp_pcb *pcb, struct pbuf *p_rx,struct ip_addr *addr, u16_t port)

用来判断上位机或网口助手发过来得是否是升级程序BOOT.BIN文件,如果是,就将升级程序标志位置1,准备升级

void udp_recive(void *arg, struct udp_pcb *pcb, struct pbuf *p_rx,struct ip_addr *addr, u16_t port)
{
    char *pData;
    if (p_rx != NULL)
    {
        pData = (char *) p_rx->payload;
        int udp_len = p_rx->len ;
        if (udp_len == 6 && !(memcmp("update", p_rx->payload, 6)))
        {
            xil_printf("Received Size is %u Bytes\r\n", ReceivedCount) ;
            xil_printf("Initialization done, programming the memory\r\n") ;
            StartUpdate = 1 ;
        }
        else
        {
            memcpy(&FlashRxBuffer[ReceivedCount], pData, udp_len);
            ReceivedCount += udp_len ;
        }
        pbuf_free(p_rx);
    }
}

(3)主函数main.c中加入:

 udp8080_pcb = udp_new();
 udp_bind(udp8080_pcb, IP_ADDR_ANY, 8080);
 udp_recv(udp8080_pcb, udp_recive, 0);
 IP4_ADDR(&target_addr, 192,168,0,223);//上位机IP
while(1)
{
   xemacif_input(echo_netif);
   if (StartUpdate)
  {
  int Status = update_qspi(&QspiInstance, QSPI_DEVICE_ID, ReceivedCount, FlashRxBuffer) ;
  if (Status != XST_SUCCESS)
  xil_printf("Write Flash Error!\r\n") ;
  else
  {
     StartUpdate = 0 ;
     ReceivedCount = 0;
  }
 }
}

8,run as或debug 加载该程序程序(zynq ps ip设为192.168.0.16):

IP4_ADDR(&(echo_netif->ip_addr), 192, 168,   0, 16);

IP4_ADDR(&(echo_netif->netmask), 255, 255, 255,  0);

IP4_ADDR(&(echo_netif->gw),      192, 168,   0,  1);

此时从cmd中能ping通192.168.0.16就说明加载的程序已经运行起来了可以开始升级

ZYNQ 使用网口或串口实现程序保存或升级_第6张图片

9,SDK程序升级,使用网口助手发送:

 (1)选择UDP协议类型,填入电脑本地的IP地址和端口号(自己定一个),填入ZYNQ PS端的IP地址192.168.0.16和端口号8080;点击启用文件数据源,从文件夹中选择要升级的文件BOOT.bin并打开,最后点击发送直到发送完成;

ZYNQ 使用网口或串口实现程序保存或升级_第7张图片

(2)去掉启用文件数据源,然后从网口助手输入“update”字符串,最后点击发送ZYNQ主控收到字符串就会拉高标志位,然后执行程序升级,然后等一段时间等待升级完成。

ZYNQ 使用网口或串口实现程序保存或升级_第8张图片

(3)重启板子电源,然后从cmd ping 192.168.0.10(新程序BOOT.bin的IP),能ping通,说明新程序裸机升级到ZYNQ成功;

ZYNQ 使用网口或串口实现程序保存或升级_第9张图片

二,使用串口串口升级并将BOOT.bin存入SD卡

1,vivado配置:勾选flash和sd和uart

ZYNQ 使用网口或串口实现程序保存或升级_第10张图片

ZYNQ 使用网口或串口实现程序保存或升级_第11张图片

2,sdk端 C代码

(1)sd.c

/*
 * sd.c
 *
 *  Created on: 2021年8月3日
 *      Author: wangjie
 */
#include 
#include "xparameters.h"
#include "xsdps.h"
#include "ff.h"

static FATFS SD_Dev; // File System instance
char *SD_Path = "0:/";  //  string pointer to the logical drive number
FIL gfile;
int SD_init()
{
	FRESULT result;
	//-----------------------mount dev------------------------
	result = f_mount(&SD_Dev,SD_Path, 0);
	if (result != 0) {
		return XST_FAILURE;
	}
	return XST_SUCCESS;
}

int SD_read(char *FileName,u8 *DestinationAddress,u32 ByteLength)
{
	FIL file;
	FRESULT result;
	UINT BytesRd;
	result = f_open(&file,FileName,FA_READ);
	if(result)
	{
		return XST_FAILURE;
	}
	result = f_lseek(&file, 0);
	if(result)
	{
		return XST_FAILURE;
	}
	result = f_read(&file, (void*)DestinationAddress,ByteLength,&BytesRd);
	if(result)
	{
		return XST_FAILURE;
	}
	result = f_close(&file);
	if(result)
	{
		return XST_FAILURE;
	}
	return XST_SUCCESS;
}


int SD_write(u8 *SourceAddress,u32 ByteLength)
{
	FRESULT result;
	UINT BytesWr;
	INT oft = 0;
	/*result = f_open(&file,FileName,FA_OPEN_ALWAYS |FA_WRITE);
	if(result)
	{
		return XST_FAILURE;
	}*/
	oft = f_tell(&gfile);
	if(oft < 0)
	{
		return XST_FAILURE;
	}
	//result = f_lseek(&file, 0);
	result = f_lseek(&gfile,oft);
	if(result)
	{
		return XST_FAILURE;
	}
	//result = f_write(&file,(void*) SourceAddress,ByteLength,&BytesWr);
	result = f_write(&gfile,(void*) SourceAddress,ByteLength,&BytesWr);
	if(result)
	{
		return XST_FAILURE;
	}
	/*result = f_close(&file);
	if(result)
    {
		return XST_FAILURE;
	}*/
	return XST_SUCCESS;
}

void SD_END()
{
	f_close(&gfile);
}

int SD_main(char *file_name)
{
	FRESULT result;
	//char FileName[32] = "src.bin"; // name of the log
	//memset(&gfile,0,sizeof(FIL));
	SD_init();
	//result = f_open(&gfile,FileName,FA_CREATE_ALWAYS |FA_WRITE);
	result = f_open(&gfile,file_name,FA_CREATE_ALWAYS |FA_WRITE);
	if(result)
	{
		return XST_FAILURE;
	}
	return 0;
}

(2)main升级代码


#include 
#include "types.h"
#include "qspi_g128_flash.h"
#include "uartps_intr.h"
#include "sd.h"

#define UP_FRM_MAX_LEN	4112

#define CRC32_POLYNOMIAL  0xEDB88320L

#define FRM_HEAD_LEN 12
#define FRM_CRC_LEN 4

#define FILE_BASE_ADDR		0x10000000
#define READ_BASE_ADDR		0x11000000
#define WRITE_BASE_ADDR		0x12000000

#define BIN_SYNC1    0xAA
#define BIN_SYNC2    0x44
#define BIN_SYNC3    0x12

#define LOG_MSG_ID_UPGRADE     1000

int8u *p_file;
int8u *p_rd_buf;
int8u *p_wr_buf;

volatile int32u file_cnt = 0;

/***********************************************************************
Function name   : CRC32Value
Description     : Calculate 32bit CRC
Input parameter :
Output parameter:
Date            : 2018.04.26
Author          :
***********************************************************************/
static int32u CRC32Value(int32u i)
{
	int32s j = 0;
	int32u ulCRC = 0;
	ulCRC = i;
    
	for (j = 8; j > 0; j--)
	{
		if(ulCRC & 1)
			ulCRC = (ulCRC >> 1) ^ CRC32_POLYNOMIAL;
		else
			ulCRC >>= 1;
	}
    
	return ulCRC;
}

int32u CalculateBlockCRC32(int32u ulCount, int8u *ucBuffer) 
{
	int32u ulTemp1 = 0;
	int32u ulTemp2 = 0;
	int32u ulCRC = 0;
    
	while (ulCount-- != 0)
	{
		ulTemp1 = (ulCRC >> 8) & 0x00FFFFFFL;
		ulTemp2 = CRC32Value(((int)ulCRC ^ *ucBuffer++) & 0xff);
		ulCRC = ulTemp1 ^ ulTemp2;
	}
    
	return(ulCRC);
}

static void ReturnBinCommand(int8u *p_buf, int16u msg_len)
{
    int32u temp_len = 0;
    int32u crc32 = 0;
    
    //32-bit CRC
    temp_len = FRM_HEAD_LEN + msg_len;
    crc32 = CalculateBlockCRC32(temp_len, p_buf);
    memcpy(p_buf + temp_len, &crc32, 4);
    temp_len += 4;

	XUartPs_Send(&UartPs, p_buf,temp_len);
}


/***********************************************************************
Function name   : CreateBinaryHead
Description     : 
Input parameter :
Output parameter:
Date            : 2018.05.17
Author          :
***********************************************************************/
static int32u CreateBinaryHead2(int8u *buf, int16u msg_id, int16u msg_len)
{
    int8u msg_type = 0;
    //Message header
    buf[0] = BIN_SYNC1;
    buf[1] = BIN_SYNC2;
    buf[2] = BIN_SYNC3;
    //Length of the header
    buf[3] = FRM_HEAD_LEN; 
    //Message ID number
    buf[4] = msg_id & 0xFF;
    buf[5] = msg_id >> 8;
    //Message Type
    buf[6] = msg_type | 0x80;
    buf[7] = 0;
    //Message Length
    buf[8] = msg_len & 0xFF;   
    buf[9] = msg_len >> 8;
	buf[10] = 0;   
    buf[11] = 0;
    return TRUE;
}

static void SendUpgradeResult(int8u stage, int8u result)
{
    int16u msg_len = 2;
    int8u temp_buf[64] = {0};
    memset(temp_buf, 0, sizeof(temp_buf));
    CreateBinaryHead2(temp_buf, LOG_MSG_ID_UPGRADE, msg_len);
    temp_buf[FRM_HEAD_LEN] = 1;//stage;
    temp_buf[FRM_HEAD_LEN + 1] = result;
    ReturnBinCommand(temp_buf, msg_len);
}

int8u update_checksyncserial(void *p_buf,int32u idx,int32u *p_len,int32u len)
{
	int8u *buf = NULL;
	int32u dat_len = 0;
	int32u file_type = 0;
	int32u frm_total = 0;
	int32u frm_num = 0;
	int32u i,j;
	int8u tmp_buf[UP_FRM_MAX_LEN] = {0};
	int8u ret = FALSE;
	int32u calc_crc = 0;
	int32u read_crc = 0;
	int32u oft = 0;
	if(!p_buf)
	{
		return FALSE;
	}
	buf = p_buf;

	//if(idx >= BUFFER_SIZE - UP_FRM_MAX_LEN)
	{
		for(i = 0;i < len;i++)
		{
			j = (idx+i)%BUFFER_SIZE;
			tmp_buf[i] = buf[j];
		}
		buf = tmp_buf;
	}

	if ((buf[0] == 0xaa) && (buf[1] == 0x44) && (buf[2] == 0x12) && (buf[3] == 0xc))
	{
		file_type = (buf[4]<<8)|buf[5];
		dat_len = (buf[6]<<8)|buf[7];
		frm_total = (buf[8]<<8)|buf[9];
		frm_num = (buf[10]<<8)|buf[11];
		*p_len = dat_len+FRM_HEAD_LEN+FRM_CRC_LEN;
		//SendUpgradeResult(buf[FRM_HEAD_LEN], 0);
		if(frm_num > frm_total)
		{
			ret = FALSE;
		}
		else
		{
			if ((dat_len != UP_FRM_MAX_LEN - FRM_HEAD_LEN - FRM_CRC_LEN) && (frm_num < frm_total))
			{
				ret = FALSE;
			}
			else
			{
				oft = FRM_HEAD_LEN + dat_len;
				calc_crc = CalculateBlockCRC32(oft,buf);
				read_crc = (buf[oft] << 24)|(buf[oft+1] << 16)|(buf[oft+2] << 8)|buf[oft+3];
				if(calc_crc != read_crc)
				{
					ret = FALSE;
				}
				else
				{
					memcpy(p_file + file_cnt, &buf[FRM_HEAD_LEN],dat_len);
					file_cnt += dat_len;

					SD_write(&buf[FRM_HEAD_LEN],dat_len);
					if(frm_num == frm_total)
					{
						SD_END();
						update_flash(p_file, p_rd_buf, p_wr_buf, file_cnt);
					}
					SendUpgradeResult(buf[FRM_HEAD_LEN],dat_len);

					ret = TRUE;
				}
			}
		}		
	}
	
	return ret;
}

int32s update_main(void)
{
	int32s len,i;
	int32u r_len = 0;
	while(UpdateReadCnt != UpdateWriteCnt)
	{
		len = (UpdateWriteCnt + BUFFER_SIZE - UpdateReadCnt)%BUFFER_SIZE;
		//if(len >= UP_FRM_MAX_LEN)
		if(len > 0)
		{
			if(update_checksyncserial(RecvUpdateBuf,UpdateReadCnt,&r_len,len))
			{
				UpdateReadCnt = (UpdateReadCnt+r_len)%BUFFER_SIZE;
			}
			else
			{
				UpdateReadCnt = (UpdateReadCnt+1)%BUFFER_SIZE;
				printf("update err:%d,%d\n",UpdateWriteCnt,UpdateReadCnt);
			}
		}
		else
		{
			break;
		}
	}
	return 0;
}

void update_init()
{
	p_file = (int8u *)FILE_BASE_ADDR;
    p_rd_buf = (int8u *)READ_BASE_ADDR;
    p_wr_buf = (int8u *)WRITE_BASE_ADDR;
}

三,附录:ZYNQ带系统实现程序升级:

使用TFTP从PC机将需要升级的文件传输到系统替换原来的新程序,在系统中使用脚本自动运行程序,就算升级完成。

你可能感兴趣的:(arm开发,fpga开发)