ZYNQ软件复位重启、程序跳转的实现方法(Multiboot)

一、参考资料

UG585中26章Reset System

Zynq 7020 multiboot升级与备份

多bin应用切换操作

zynq使用software reset(软复位)实现重加载

Zynq-7000 AP SoC Boot - Multiboot Tech Tip

二、增加FSBL的调试信息

在这里插入图片描述
启动过程的调试信息如下:

Xilinx First Stage Boot Loader
Release 2016.4  Jan 19 2020-16:55:11
Devcfg driver initialized
Silicon Version 3.1
Boot mode is QSPI
Single Flash Information
FlashID=0x1 0x2 0x19
SPANSION 256M Bits
QSPI is in single flash connection
QSPI Init Done
Flash Base Address: 0xFC000000
Reboot status register: 0x60782000
Multiboot Register: 0x0000C000
Image Start Address: 0x00000000
Partition Header Offset:0x00000C80
Partition Count: 3
Partition Number: 1
Header Dump
Image Word Len: 0x000F6EC0
Data Word Len: 0x000F6EC0
Partition Word Len:0x000F6EC0
Load Addr: 0x00000000
Exec Addr: 0x00000000
Partition Start: 0x000065D0
Partition Attr: 0x00000020
Partition Checksum Offset: 0x00000000
Section Count: 0x00000001
Checksum: 0xFFD14B7E
Bitstream
In FsblHookBeforeBitstreamDload function
PCAP:StatusReg = 0x40000A30
PCAP:device ready
PCAP:Clear done
Level Shifter Value = 0xA
Devcfg Status register = 0x40000A30
PCAP:Fabric is Initialized done
PCAP register dump:
PCAP CTRL 0xF8007000: 0x4C00E07F
PCAP LOCK 0xF8007004: 0x0000001A
PCAP CONFIG 0xF8007008: 0x00000508
PCAP ISR 0xF800700C: 0x0802000B
PCAP IMR 0xF8007010: 0xFFFFFFFF
PCAP STATUS 0xF8007014: 0x00005A30
PCAP DMA SRC ADDR 0xF8007018: 0x00100001
PCAP DMA DEST ADDR 0xF800701C: 0xFFFFFFFF
PCAP DMA SRC LEN 0xF8007020: 0x000F6EC0
PCAP DMA DEST LEN 0xF8007024: 0x000F6EC0
PCAP ROM SHADOW CTRL 0xF8007028: 0xFFFFFFFF
PCAP MBOOT 0xF800702C: 0x0000C000
PCAP SW ID 0xF8007030: 0x00000000
PCAP UNLOCK 0xF8007034: 0x757BDF0D
PCAP MCTRL 0xF8007080: 0x30800100

DMA Done !

FPGA Done !
In FsblHookAfterBitstreamDload function
Partition Number: 2
Header Dump
Image Word Len: 0x00002002
Data Word Len: 0x00002002
Partition Word Len:0x00002002
Load Addr: 0x00100000
Exec Addr: 0x00100000
Partition Start: 0x000FD490
Partition Attr: 0x00000010
Partition Checksum Offset: 0x00000000
Section Count: 0x00000001
Checksum: 0xFFCFC8F8
Application
Handoff Address: 0x00100000
In FsblHookBeforeHandoff function
SUCCESSFUL_HANDOFF
FSBL Status = 0x1
Hello World

三、如何实现软件复位

1.原理

各种复位方法的影响:
在这里插入图片描述
其中的系统软件复位:在这里插入图片描述
其中涉及到:PSS_RST_CTRL[SOFT_RST]

参见附录B.28 1607页

在这里插入图片描述

在这里插入图片描述
因此,向寄存器PSS_RST_CTRL[SOFT_RST]写入1,即可实现复位。

2. 实验步骤

测试代码如下:

#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xil_io.h"
#include "sleep.h"

#define PSS_RST_CTRL_REG 0xF8000200 //PSS_RST_CTRL寄存器,绝对地址,
#define SLCR_UNLOCK_ADDR 0xF8000008 //SLCR_UNLOCK寄存器,绝对地址,
#define UNLOCK_KEY 0xDF0D //使能码
#define PSS_RST_MASK 0x01 //复位码

void PsSoftwareReset(void)
{
	Xil_Out32(SLCR_UNLOCK_ADDR, UNLOCK_KEY); //写使能
	Xil_Out32(PSS_RST_CTRL_REG, PSS_RST_MASK); //复位
}

int main()
{
	init_platform();
	print("Hello World\r\n");
	sleep(5);
	PsSoftwareReset();
	cleanup_platform();
	return 0;
}

实验现象:可以看到周期性重启。

Xilinx First Stage Boot Loader
Release 2016.4  Jan 19 2020-16:55:11
Devcfg driver initialized
Silicon Version 3.1
Boot mode is QSPI
Single Flash Information
FlashID=0x1 0x2 0x19
SPANSION 256M Bits
QSPI is in single flash connection
QSPI Init Done
Flash Base Address: 0xFC000000
Reboot status register: 0x60782000
Multiboot Register: 0x0000C000
Image Start Address: 0x00000000
Partition Header Offset:0x00000C80
Partition Count: 3
Partition Number: 1
Header Dump
Image Word Len: 0x000F6EC0
Data Word Len: 0x000F6EC0
Partition Word Len:0x000F6EC0
Load Addr: 0x00000000
Exec Addr: 0x00000000
Partition Start: 0x000065D0
Partition Attr: 0x00000020
Partition Checksum Offset: 0x00000000
Section Count: 0x00000001
Checksum: 0xFFD14B7E
Bitstream
In FsblHookBeforeBitstreamDload function
PCAP:StatusReg = 0x40000A30
PCAP:device ready
PCAP:Clear done
Level Shifter Value = 0xA
Devcfg Status register = 0x40000A30
PCAP:Fabric is Initialized done
PCAP register dump:
PCAP CTRL 0xF8007000: 0x4C00E07F
PCAP LOCK 0xF8007004: 0x0000001A
PCAP CONFIG 0xF8007008: 0x00000508
PCAP ISR 0xF800700C: 0x0802000B
PCAP IMR 0xF8007010: 0xFFFFFFFF
PCAP STATUS 0xF8007014: 0x00000A30
PCAP DMA SRC ADDR 0xF8007018: 0x00100001
PCAP DMA DEST ADDR 0xF800701C: 0xFFFFFFFF
PCAP DMA SRC LEN 0xF8007020: 0x000F6EC0
PCAP DMA DEST LEN 0xF8007024: 0x000F6EC0
PCAP ROM SHADOW CTRL 0xF8007028: 0xFFFFFFFF
PCAP MBOOT 0xF800702C: 0x0000C000
PCAP SW ID 0xF8007030: 0x00000000
PCAP UNLOCK 0xF8007034: 0x757BDF0D
PCAP MCTRL 0xF8007080: 0x30800100

DMA Done !

FPGA Done !
In FsblHookAfterBitstreamDload function
Partition Number: 2
Header Dump
Image Word Len: 0x00002002
Data Word Len: 0x00002002
Partition Word Len:0x00002002
Load Addr: 0x00100000
Exec Addr: 0x00100000
Partition Start: 0x000FD490
Partition Attr: 0x00000010
Partition Checksum Offset: 0x00000000
Section Count: 0x00000001
Checksum: 0xFFCFC8F8
Application
Handoff Address: 0x00100000
In FsblHookBeforeHandoff function
SUCCESSFUL_HANDOFF
FSBL Status = 0x1
Hello World

Xilinx First Stage Boot Loader
Release 2016.4  Jan 19 2020-16:55:11
Devcfg driver initialized
Silicon Version 3.1
Boot mode is QSPI
Single Flash Information
FlashID=0x1 0x2 0x19
SPANSION 256M Bits
QSPI is in single flash connection
QSPI Init Done
Flash Base Address: 0xFC000000
Reboot status register: 0x60782000
Multiboot Register: 0x0000C000
Image Start Address: 0x00000000
Partition Header Offset:0x00000C80
Partition Count: 3
Partition Number: 1
Header Dump
Image Word Len: 0x000F6EC0
Data Word Len: 0x000F6EC0
Partition Word Len:0x000F6EC0
Load Addr: 0x00000000
Exec Addr: 0x00000000
Partition Start: 0x000065D0
Partition Attr: 0x00000020
Partition Checksum Offset: 0x00000000
Section Count: 0x00000001
Checksum: 0xFFD14B7E
Bitstream
In FsblHookBeforeBitstreamDload function
PCAP:StatusReg = 0x40000A30
PCAP:device ready
PCAP:Clear done
Level Shifter Value = 0xA
Devcfg Status register = 0x40000A30
PCAP:Fabric is Initialized done
PCAP register dump:
PCAP CTRL 0xF8007000: 0x4C00E07F
PCAP LOCK 0xF8007004: 0x0000001A
PCAP CONFIG 0xF8007008: 0x00000508
PCAP ISR 0xF800700C: 0x0802000B
PCAP IMR 0xF8007010: 0xFFFFFFFF
PCAP STATUS 0xF8007014: 0x00007A30
PCAP DMA SRC ADDR 0xF8007018: 0x00100001
PCAP DMA DEST ADDR 0xF800701C: 0xFFFFFFFF
PCAP DMA SRC LEN 0xF8007020: 0x000F6EC0
PCAP DMA DEST LEN 0xF8007024: 0x000F6EC0
PCAP ROM SHADOW CTRL 0xF8007028: 0xFFFFFFFF
PCAP MBOOT 0xF800702C: 0x0000C000
PCAP SW ID 0xF8007030: 0x00000000
PCAP UNLOCK 0xF8007034: 0x757BDF0D
PCAP MCTRL 0xF8007080: 0x30800100

DMA Done !

FPGA Done !
In FsblHookAfterBitstreamDload function
Partition Number: 2
Header Dump
Image Word Len: 0x00002002
Data Word Len: 0x00002002
Partition Word Len:0x00002002
Load Addr: 0x00100000
Exec Addr: 0x00100000
Partition Start: 0x000FD490
Partition Attr: 0x00000010
Partition Checksum Offset: 0x00000000
Section Count: 0x00000001
Checksum: 0xFFCFC8F8
Application
Handoff Address: 0x00100000
In FsblHookBeforeHandoff function
SUCCESSFUL_HANDOFF
FSBL Status = 0x1
Hello World

四、Multiboot机制

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

1.原理

  1. Golden Image Search
    当没有有效头部时,BOOTROM会每32KB搜索一次有效头部。这个机制虽然慢,但是可靠。

  2. BootROM Multiboot
    当BOOTROM发现一个有效头部,之后跳转到FSBL,FSBL可以加载Multiboot register的值,之后触发一个软件复位。软件复位之后,BOOTROM将会使用Multiboot register中的地址去读取BOOTROM header。这个机制可以用来:用户想去运行自检程序,之后跳转到真正的应用程序。

  3. FSBL Fallback
    从一个error恢复之后,FSBL会做出Fallback,并使BOOTROM去加载另外一个映像(golden image)。FSBL更新Multiboot register的值,并产生软件复位,使BOOTROM加载运行另外一个可用的映像。其中,FSBL fallback发生,可以有软件复位,也可以没有软件复位。(可以参考UG821)

2. 涉及到的两个寄存器

Reboot status register: 0x60782000
Multiboot Register: 0x0000C000

1.UG585 1620页 Register (slcr) REBOOT_STATUS
此寄存器不会发生改变,直到重新上电复位,复位值:0x00400000,也正好代表上电复位。
在这里插入图片描述
在这里插入图片描述
2. UG585 1159页 Register (devcfg) XDCFG_MULTIBOOT_ADDR_OFFSET
此寄存器用来记录上一次的启动地址,开机会复位。
在这里插入图片描述

3.实验一

① 创建FSBL_1应用程序。设置FSBL_DEBUG flag。
在这里插入图片描述
② 修改FSBL_1工程中的main()函数如下:

/*
 * FSBL handoff to valid handoff address or
 * exit in JTAG
 */
//FsblHandoff(HandoffAddress);
/*
* Should not come over here
*/
OutputStatus(ILLEGAL_RETURN);
FsblFallback();

③ 编译,生成了FSBL_1.elf。
在这里插入图片描述
④ 创建Hello_World_1应用程序,修改代码如下,编译生成Hello_World_1.elf。

#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"

int main()
{
    init_platform();

    print("Hello World from Image 1 at address 0x0000_0000\r\n");

    cleanup_platform();
    return 0;
}

⑤ 创建FSBL_2应用程序。设置FSBL_DEBUG flag。编译生成FSBL_2.elf。

⑥ 创建创建Hello_World_2应用程序,修改代码如下,编译生成Hello_World_2.elf。

#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "sleep.h"

int main()
{
    init_platform();
    while(1)
    {
    	print("my Hello World from Image 2 at address 0x0004_0000\r\n");
    	sleep(1);
    }
    cleanup_platform();
    return 0;
}

全部的工程目录如下:
在这里插入图片描述
⑦ 使用FSBL_1.elf 和 Hello_World_1.elf 打包生成Hello_World_1.bin。

⑧ 使用FSBL_2.elf 和 Hello_World_2.elf 打包生成Hello_World_2.bin。

⑨ Hello_World_1.bin刷写至QPSI FLASH的0地址。

⑨ Hello_World_2.bin刷写至QPSI FLASH的0x40000地址。

4.实验现象

Xilinx First Stage Boot Loader
Release 2016.4  Jan 20 2020-13:45:46
Devcfg driver initialized
Silicon Version 3.1
Boot mode is QSPI
Single Flash Information
FlashID=0x1 0x2 0x19
SPANSION 256M Bits
QSPI is in single flash connection
QSPI Init Done
Flash Base Address: 0xFC000000
Reboot status register: 0x60680000
Multiboot Register: 0x0000C008
Image Start Address: 0x00040000
Partition Header Offset:0x00040C80
Partition Count: 2
Partition Number: 1
Header Dump
Image Word Len: 0x00002002
Data Word Len: 0x00002002
Partition Word Len:0x00002002
Load Addr: 0x00100000
Exec Addr: 0x00100000
Partition Start: 0x000065D0
Partition Attr: 0x00000010
Partition Checksum Offset: 0x00000000
Section Count: 0x00000001
Checksum: 0xFFDF37C8
Application
Handoff Address: 0x00100000
In FsblHookBeforeHandoff function
SUCCESSFUL_HANDOFF
FSBL Status = 0x1
my Hello World from Image 2 at address 0x0004_0000
my Hello World from Image 2 at address 0x0004_0000

5.对实验现象的分析

FSBL_1失败,Multiboot Regsiter(只有低13位)逐渐增加到8,代表8*0x8000=0x40000。之后会记录下这个值。FSBL_2运行成功,启动Hello_World_2.elf应用程序。

6.实验二

在Hello_World_1程序中主动修改multiboot寄存器的值,再触发软件复位,使其主动跳转到指定的地址Hello_World_2处。

在Hello_World_2程序中主动修改multiboot寄存器的值,再触发软件复位,使其主动跳转到指定的地址Hello_World_1处。

如此,循环跳转。

在实验一的基础上修改Hello_World_1.elf的代码如下:

#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xil_io.h"
#include "sleep.h"

#define PSS_RST_CTRL_REG 0xF8000200 //PSS_RST_CTRL寄存器,绝对地址,
#define SLCR_UNLOCK_ADDR 0xF8000008 //SLCR_UNLOCK寄存器,绝对地址,
#define UNLOCK_KEY 0xDF0D //使能码
#define PSS_RST_MASK 0x01 //复位码

void PsSoftwareReset(void)
{
	Xil_Out32(SLCR_UNLOCK_ADDR, UNLOCK_KEY); //写使能
	Xil_Out32(PSS_RST_CTRL_REG, PSS_RST_MASK); //复位
}

#define XDCFG_MULTIBOOT_ADDR_OFFSET_REG 0xF800702C //MULTIBOOT寄存器,绝对地址,
#define XDCFG_UNLOCK_OFFSET_ADDR 0xF8007034 //XDCFG_UNLOCK_寄存器,绝对地址,
#define UNLOCK_XDCFG_KEY 0x757BDF0D //使能码

#define APP1_LOCATION 0x00 //Hello_World_1位置
#define APP2_LOCATION 0x08 //Hello_World_2位置 以32KB为单位,8*0x8000=0x400000


void ModifyMultiBoot(void)
{
	Xil_Out32(XDCFG_UNLOCK_OFFSET_ADDR , UNLOCK_XDCFG_KEY ); //写使能
	Xil_Out32(XDCFG_MULTIBOOT_ADDR_OFFSET_REG , APP2_LOCATION ); //更改MULTIBOOT
}

int main()
{
	init_platform();
	print("Hello World\r\n");
	sleep(5);
	ModifyMultiBoot();
	PsSoftwareReset();
	cleanup_platform();
	return 0;
}

修改Hello_World_2.elf的代码如下:

#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xil_io.h"
#include "sleep.h"

#define PSS_RST_CTRL_REG 0xF8000200 //PSS_RST_CTRL寄存器,绝对地址,
#define SLCR_UNLOCK_ADDR 0xF8000008 //SLCR_UNLOCK寄存器,绝对地址,
#define UNLOCK_KEY 0xDF0D //使能码
#define PSS_RST_MASK 0x01 //复位码

void PsSoftwareReset(void)
{
	Xil_Out32(SLCR_UNLOCK_ADDR, UNLOCK_KEY); //写使能
	Xil_Out32(PSS_RST_CTRL_REG, PSS_RST_MASK); //复位
}

#define XDCFG_MULTIBOOT_ADDR_OFFSET_REG 0xF800702C //MULTIBOOT寄存器,绝对地址,
#define XDCFG_UNLOCK_OFFSET_ADDR 0xF8007034 //XDCFG_UNLOCK_寄存器,绝对地址,
#define UNLOCK_XDCFG_KEY 0x757BDF0D //使能码

#define APP1_LOCATION 0x00 //Hello_World_1位置
#define APP2_LOCATION 0x08 //Hello_World_2位置 以32KB为单位,8*0x8000=0x400000


void ModifyMultiBoot(void)
{
	Xil_Out32(XDCFG_UNLOCK_OFFSET_ADDR , UNLOCK_XDCFG_KEY ); //写使能
	Xil_Out32(XDCFG_MULTIBOOT_ADDR_OFFSET_REG , APP1_LOCATION ); //更改MULTIBOOT
}

int main()
{
	init_platform();
	print("Hello World\r\n");
	sleep(5);
	ModifyMultiBoot();
	PsSoftwareReset();
	cleanup_platform();
	return 0;
}

实现了APP1和APP2之间循环跳转。

7. 实验三

在app 的fsbl 中image_mover.c中:

/*******************************************************************************/
/* 自己添加的函数 */
/*******************************************************************************/

#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xil_io.h"
#include "sleep.h"

#define PSS_RST_CTRL_REG 0xF8000200 //PSS_RST_CTRL寄存器,绝对地址,
#define SLCR_UNLOCK_ADDR 0xF8000008 //SLCR_UNLOCK寄存器,绝对地址,
#define UNLOCK_KEY 0xDF0D //使能码
#define PSS_RST_MASK 0x01 //复位码

void PsSoftwareReset(void)
{
	Xil_Out32(SLCR_UNLOCK_ADDR, UNLOCK_KEY); //写使能
	Xil_Out32(PSS_RST_CTRL_REG, PSS_RST_MASK); //复位
}

#define XDCFG_MULTIBOOT_ADDR_OFFSET_REG 0xF800702C //MULTIBOOT寄存器,绝对地址,
#define XDCFG_UNLOCK_OFFSET_ADDR 0xF8007034 //XDCFG_UNLOCK_寄存器,绝对地址,
#define UNLOCK_XDCFG_KEY 0x757BDF0D //使能码




void ModifyMultiBoot(void)
{
	Xil_Out32(XDCFG_UNLOCK_OFFSET_ADDR , UNLOCK_XDCFG_KEY ); //写使能
	Xil_Out32(XDCFG_MULTIBOOT_ADDR_OFFSET_REG , 0x0 ); //更改MULTIBOOT
}

/*******************************************************************************/

大概276行:

	/*
	 * Get partitions header information
	 */
	Status = GetPartitionHeaderInfo(ImageStartAddress);
	if (Status != XST_SUCCESS) {
		fsbl_printf(DEBUG_GENERAL, "Partition Header Load Failed\r\n");
		OutputStatus(GET_HEADER_INFO_FAIL);

		/* 自己添加的函数,如果加载失败,则重置MultiBoot寄存器,并软件复位,跳到IAP中 */
		ModifyMultiBoot();
		PsSoftwareReset();		
		
		FsblFallback();
	}
  • 29
    点赞
  • 203
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ta o

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值