zynq 裸机uart在线升级

zynq 裸机调试串口在线升级升级

  • 查看网上资料,一般都是利用网口给开发板升级,自己调试一个利用调试串口给开发板升级,升级过程中各种突发情况引起升级失败,防止变成板砖如何处理。
  • 开发板:zynq7020
  • spi flash型号:MT25QL128ABA(16MB)镁光)的flash、W25Q128J (华邦的)flash(这个flash正常烧录在vivado2018.3的环境可能程序起来不了,具体如何处理可以私信我)
  • 串口:波特率115200 一位停止位,没有校验位和起始位
  • 开发环境:vivado 2018.3 以及对应的SDK
  • 裸机升级文件:fsbl.elf, hello.bit,hello.elf一起在SDK中构建成一个BOOT.BIN

1.预防变成板砖的办法

  • multiboot机制
    2个boot bin文件放在flash的不同地址。
    可以修改multiboot register然后在软件里触发软复位,这样zynq-7000会重新从multiboot register指定的flash偏移地址去boot,multiboot register的值每加一,偏移地址增加32KB。multiboot register只能被POR reset清除。
    multiboot register: 0x0000C000
    Reboot status register: 0x60782000

  • 判断升级失败成功的办法
    在flash的末尾留一个四个字节的位置当着升级标志位,每次升级收到数据将标志位擦除,如果升级文件写到flash的数据经过校验成功后,给标志位写一个110的,每次上电启动的时候,在fsbl阶段就去读取flash中的标志位,如果读取的值等于110,代表上次升级成功,就重启跳转到multiboot register寄存器保存的地址启动升级后的BOOT.bin.

  • 如何保证接收数据的正确性
    对整个接收数的数据做CRC16校验,将CRC校验值放在最后,先将数据全部放在开发板的DDR中,对接收到的数据进行CRC校验,如果CRC校验成功,然后将数据写入flash中,再将数据读出来,和DDR中数据进行一个对比,保证数据百分百的正确,如果校验都成功了,再去改变flash中的标志位。

2.升级代码示例

  • 1、串口初始化
    修改xuartps_polled_example 模版代码
int Uart_Init(void){
	int Status;
	Status = UartPsInterExample(&Intc ,&UartPs, 
			UART_DEVICE_ID, UART_INT_IRQ_ID); 
	if(Status != XST_SUCCESS){
		xil_printf("uart Interrupt Example Test Failed\r\n);
		return XST_FAILURE;
	}
	
	printf("Successfully ran UART Interrupt Example Test\r\n);
	return XST_SUCCESS;
}

  • 2、串口中断处理
if(Event == XUARTPS_EVENT_RECV_DATA || Event ==  XUARTPS_EVENT_RECV_TOUT){
	TotalReceivedCount = EventData;
	if(EventData == 2 && msg_recv_stage == RECVING_MSG_HEAD){
		if(RecvBuffer[0] == 0x7B && RecvBuffer[1] == 0x7B){//准备升级
			printf("start recv file\r\n);
			msg_recv_state = RECV_UPDATE;
			memset((u8 *)DDR_UPDATE_PROGRESS, 0, RECV_MAX_LEN);
			XUartPs_Recv(&UartPs, (u8 *)DDR_UPDATE_PROGESS, RECV_MAX_LEN);//持续接收文件
		}
	}else{//其他错误数据
		memset(RecvBuffer, 0, sizeof(RecvBuffer);
		msg_recv_stage = NEED_RECV_MSG_HEAD;
	}
}else(EventData >2 && msg_recv_stage == RECV_UPDATE){//这个位置其实可以修改成其他串口接收方式
	if(*((u8 *)DDR_UPDATE_PROGESS + EventDate - 1) == 0x7D && *((u8 *)DDR_UPDATE_PROGESS + EventDate - 2) == 0x7D ){//如果接收到的数据长度和实际下发的长度相等,下发7D7D代表数据结束
		len = EventData - 2;
		msg_recv_stage = RECV_UPDATE_COMPLETE;
	}else{
		
			xil_printf("recv file len = %d\n", EventData);
			xil_printf("====> please send end flag \" 0x7D 0x7D \" \n);
		
	}
}
  • 3、写入flash和校验
int Write_To_Flash(void){
	1.先crc16校验数据,成功擦除,失败返回接收失败的应答
	 CRC = CRC_16(DATA, len);

	2.校验成功,擦除
	FlashErase(&Qspi, QSIFLASH_ADDRESS, page_count*PAGE_SIZE);
	
	3.写入flash
	FlashWrite(&Qspi, QSPIFLASH_ADDRESS, QSPIFLASH_ADDRSSS, PAGE_SIZE,4WRITE_CMD);

	4.读flash的值与存到ddr中的数据进行对,升级一定要多次校验,保证数据正确
	Flash_TO_DDR(&Qspi, QSPIFLASH_ADDRESS, len, READ_CMD, DDR_UPDATE_READ_ADDRESS);
	
	5.比较数据,改变标志位数据
	if(!strncmp((u8 *)DDR_UPDATE_PROGESS, (u8 *)DDR_UPDATE_READ_ADDRESS + 4, len){
		WriteBuffer[DATA_OFFSET] = 110;
		FlashWrite(&Qspi, QSPIFLASH_FLAG_ADDRESS, 1, READ_CMD);
		xil_printf("update success !!!\n");
	}else{
		xil_printf("update fail !!!\n");
		return -1;
	}
	return 0;
}
  • 4、开机校验
    开机校验的BOOT.bin程序也需要有能够升级的应用程序,升级失败后,可以通过校验程序升级。
    开机校验有两种方式一种是在fsbl阶段读取校验,第二种是应用程序中校验,具体的可以参考
    https://blog.youkuaiyun.com/weixin_41922484/article/details/104037513?spm=1001.2014.3001.5506

  • 5.网口升级
    网口升级和串口升级类似,以前实现过linux系统下通过上位机分别给同一个产品的Z7 和 K7两片flash升级,和串口的思想类似,在这里主要提供思路。如果需要源码可以私信我。

3、下期打算写一篇关与网口在线升级的文章

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值