基于Zynq7000平台VxWorks6.9开发应用——FPGA动态加载篇

2023-05-16

 

 

前言 

本篇文章主要讲解在Xilinx ZedBoard上通过VxWorks6.9动态加载FPGA bit/bin文件,从而实现软件定义功能目的。本文力求讲述清楚PS动态加载PL的原理和实现方法,并配套完整的演示软件和相关代码进行验证。下面将从以下几个方面进行讲解。

  1. Zynq7000 PL加载原理设计
  2. VxWorks6.9动态加载FPGA

开发使用工具说明:

  1. WorkBench3.3

 

1、Zynq7000 PL加载原理设计

图1 非安全启动流程框图

如图1所示,非安全启动流程中PS通过芯片的固件程序从存储设备中读取引导软件fsbl到芯片RAM运行从而完成PS的整个启动流程。PL加载的通道则从PS通过AXI总线到达设备配置模块,然后通过PCAP进行加载。

除了JTAG加载PL之外,PL可以使用PCAP进行配置。用户可以在任何时候配置PL,无论是在PS使用FSBL启动后,还是在操作系统启动之后加载PL的镜像。本节介绍配置PL的要求。PL加载前必须先上电,才能进行配置。重复加载需要复位清除PL的配置SRAM单元。

表1 设备配置寄存器表

本文主要讲解PCAP配置PL的流程,其主要是通过配置表1的寄存器进行操作。

(1) PCAP配置PL

发送配置位流,PL必须完成内部清除工作。其状态由DevC的status寄存器中的[PCFG_INIT]位指示。内部环回功能也必须禁用,并且[PCAP_MODE]位必须设置。位流被传输到PL使用DevC DMA。PCFG_DONE标志表示PL配置成功。具体配置流程为:

1.  等待PL([0xF8007014]STATUS-bit[4])将PCFG_INIT设置为高;

2. 设置内部环回为0 ([0xF8007080]MCTRL-bit[4]),关闭内部环回;

3. 设置PCAP_PR和PCAP_MODE为1 ([0xF8007000]CTRL-bit[27:26]),选择并使能PCAP接口进行配置;

4. 启动一个DevC DMA传输;

a)源地址:PL位流的位置

b)目的地址:0xFFFFFFFF

c)源长度:PL位流中32位字的总数

d)目的长度:PL位流中32位字的总数

5. 等待PL ([0xF800700C]INT_STS-bit[2])将PCFG_DONE设置为高。

 

(2) PL重复配置

        PL配置完成后,使用PCAP重新配置PL,必须在Control中将PCAP_MODE和PCAP_PR位设置为1。内部环回功能也必须禁用。发送重配置位流到使用DevC DMA的PL,源和目标与初始配置相同。PL重复配置流程如下:

  1. 设置PCAP_MODE和PCAP_PR为1, ([0xF8007000]CTRL-bit[27:26]),选择并使能PCAP接口进行配置;

2. 从PL中清除之前的配置;

a)设置PCFG_PROG_B([0xF8007000]CTRL-bit[30])高。

b)设置“PCFG_PROG_B ([0xF8007000]CTRL-bit[30])为低”。

c)检查PCFG_INIT = 0 ([0xF8007014]STATUS-bit[4])。

d)向INT_STS[2]写入1,清除PCFG_DONE_INT。

3.检查PCFG_INIT = 1 (STATUS-bit[4]);

4. 设置INT_PCAP_LPBK为0(MCTRL-bit[4]);

5. 通过向INT_STS[12]写入1来清除D_P_DONE_INT;

6. 启动一个DevC DMA传输;

a)源地址:新PL位流的位置。

b)目的地址:0xFFFF_FFFF。

c)Source Length:新的PL位流中32位字的总数。

d) Destination Length:新PL位流中32位字的总数。

7. 轮询或等待devcfg。INT_STS[D_P_DONE_INT]触发中断;

8. (可选)如果清除了之前的配置,请检查INT_STS上的PCFG_DONE_INT。

如果之前的PL配置没有被使用清除,那么PCFG_DONE标志将不会被设置PCFG_PROG_B。在这种情况下,应该使用D_P_DONE_INT来指示新的位流,需要注意的是,PCAP和ICAP接口是相互排斥的。一次只有一个接口可以与PL配置控制器通信,使用哪个接口是由DevC的控制寄存器中的PCAP_PR位控制的。

 

2、VxWorks6.9动态加载FPGA

本文主要目的是为了讲解VxWorks6.9系统下动态加载FPGA位流文件。对外提供一个VxWorks系统加载FPGA位流文件的接口函数。在BSP包里面实现fpga_load_driver.c、fpga_load_driver.h文件,如下图所示。

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

文件名称: fpga_load_driver.h

文件标识: 定义头文件

内容摘要: ZYNQ7000平台FPGA软件加载驱动.

其它说明: PS->PL加载,涉及PCAP接口.支持bitbin格式自适应加载.

*

当前版本: V1.00.00

    者: root

完成日期: 02/19/2020

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

#ifndef __FPGA_LOAD_H__

#define __FPGA_LOAD_H__

 

//#define  FPGA_LOAD_DEBUG                 1

 

/* fpga load return value definitions */

#define FPGA_SUCCESS                    0

#define FPGA_FAIL                       -1

 

int zynq_load_fs(char *pFilePath);

 

#endif /* __FPGA_LOAD_H__ */

 

1、定义操作寄存器接口

#define ZYNQ_SYS_CTRL_BASEADDR          0xF8000000

#define ZYNQ_DEV_CFG_APB_BASEADDR       0xF8007000

 

/* Reflect slcr offsets */

struct slcr_regs {

    UINT32 scl; /* 0x0 */

    UINT32 slcr_lock; /* 0x4 */

    UINT32 slcr_unlock; /* 0x8 */

    UINT32 reserved0_1[61];

    UINT32 arm_pll_ctrl; /* 0x100 */

    UINT32 ddr_pll_ctrl; /* 0x104 */

    UINT32 io_pll_ctrl/* 0x108 */

    UINT32 reserved0_2[5];

    UINT32 arm_clk_ctrl; /* 0x120 */

    UINT32 ddr_clk_ctrl; /* 0x124 */

    UINT32 dci_clk_ctrl; /* 0x128 */

    UINT32 aper_clk_ctrl; /* 0x12c */

    UINT32 reserved0_3[2];

    UINT32 gem0_rclk_ctrl; /* 0x138 */

    UINT32 gem1_rclk_ctrl; /* 0x13c */

    UINT32 gem0_clk_ctrl; /* 0x140 */

    UINT32 gem1_clk_ctrl; /* 0x144 */

    UINT32 smc_clk_ctrl/* 0x148 */

    UINT32 lqspi_clk_ctrl; /* 0x14c */

    UINT32 sdio_clk_ctrl; /* 0x150 */

    UINT32 uart_clk_ctrl; /* 0x154 */

    UINT32 spi_clk_ctrl; /* 0x158 */

    UINT32 can_clk_ctrl; /* 0x15c */

    UINT32 can_mioclk_ctrl; /* 0x160 */

    UINT32 dbg_clk_ctrl; /* 0x164 */

    UINT32 pcap_clk_ctrl; /* 0x168 */

    UINT32 reserved0_4[1];

    UINT32 fpga0_clk_ctrl; /* 0x170 */

    UINT32 reserved0_5[3];

    UINT32 fpga1_clk_ctrl; /* 0x180 */

    UINT32 reserved0_6[3];

    UINT32 fpga2_clk_ctrl; /* 0x190 */

    UINT32 reserved0_7[3];

    UINT32 fpga3_clk_ctrl; /* 0x1a0 */

    UINT32 reserved0_8[8];

    UINT32 clk_621_true; /* 0x1c4 */

    UINT32 reserved1[14];

    UINT32 pss_rst_ctrl; /* 0x200 */

    UINT32 reserved2[15];

    UINT32 fpga_rst_ctrl; /* 0x240 */

    UINT32 reserved3[5];

    UINT32 reboot_status; /* 0x258 */

    UINT32 boot_mode; /* 0x25c */

    UINT32 reserved4[116];

    UINT32 trust_zone; /* 0x430 */ /* FIXME */

    UINT32 reserved5_1[63];

    UINT32 pss_idcode; /* 0x530 */

    UINT32 reserved5_2[51];

    UINT32 ddr_urgent; /* 0x600 */

    UINT32 reserved6[6];

    UINT32 ddr_urgent_sel; /* 0x61c */

    UINT32 reserved7[56];

    UINT32 mio_pin[54]; /* 0x700 - 0x7D4 */

    UINT32 reserved8[74];

    UINT32 lvl_shftr_en; /* 0x900 */

    UINT32 reserved9[3];

    UINT32 ocm_cfg; /* 0x910 */

};

 

struct devcfg_regs {

    UINT32 ctrl; /* 0x0 */

    UINT32 lock; /* 0x4 */

    UINT32 cfg; /* 0x8 */

    UINT32 int_sts; /* 0xc */

    UINT32 int_mask; /* 0x10 */

    UINT32 status; /* 0x14 */

    UINT32 dma_src_addr; /* 0x18 */

    UINT32 dma_dst_addr; /* 0x1c */

    UINT32 dma_src_len; /* 0x20 */

    UINT32 dma_dst_len; /* 0x24 */

    UINT32 rom_shadow; /* 0x28 */

    UINT32 reserved1[2];

    UINT32 unlock; /* 0x34 */

    UINT32 reserved2[18];

    UINT32 mctrl; /* 0x80 */

    UINT32 reserved3;

    UINT32 write_count; /* 0x88 */

    UINT32 read_count; /* 0x8c */

};

 

#define devcfg_base ((struct devcfg_regs *)ZYNQ_DEV_CFG_APB_BASEADDR)

#define slcr_base   ((struct slcr_regs *)ZYNQ_SYS_CTRL_BASEADDR)

 

#define vxReadl(addr)        *(volatile UINT32 *)(addr)

#define vxWritel(data, addr)    *(volatile UINT32 *)(addr) = (data)

 

2、配置DMA传输初始化

static int zynq_dma_transfer(UINT32 srcbuf, UINT32 srclen, UINT32 dstbuf, UINT32 dstlen)

{

    UINT32 isr_status;

    struct timeval start_time, now;

 

    /* Set up the transfer */

    vxWritel((UINT32)srcbuf, &devcfg_base->dma_src_addr);

    vxWritel(dstbuf, &devcfg_base->dma_dst_addr);

    vxWritel(srclen, &devcfg_base->dma_src_len);

    vxWritel(dstlen, &devcfg_base->dma_dst_len);

 

    isr_status = vxReadl(&devcfg_base->int_sts);

 

    /* Polling the PCAP_INIT status for Set */

    gettimeofday(&start_time, NULL);

    while (!(isr_status & DEVCFG_ISR_DMA_DONE))

    {

        if (isr_status & DEVCFG_ISR_ERROR_FLAGS_MASK) {

            printf("%s: Error: isr = 0x%08X\n", __func__,

                  isr_status);

            printf("%s: Write count = 0x%08X\n", __func__,

                  vxReadl(&devcfg_base->write_count));

            printf("%s: Read count = 0x%08X\n", __func__,

                  vxReadl(&devcfg_base->read_count));

 

            return FPGA_FAIL;

        }

 

        gettimeofday(&now, NULL);

        if (now.tv_sec - start_time.tv_sec > CONFIG_SYS_FPGA_PROG_TIME) {

            printf("%s: Timeout wait for DMA to complete\n",

                   __func__);

            return FPGA_FAIL;

        }

        isr_status = vxReadl(&devcfg_base->int_sts);

    }

 

    debug("%s: DMA transfer is done\n", __func__);

 

    /* Clear out the DMA status */

    vxWritel(DEVCFG_ISR_DMA_DONE, &devcfg_base->int_sts);

 

    return FPGA_SUCCESS;

}

 

3、 实现FPGA文件动态加载接口

int zynq_load_fs(char *pFilePath)

{

    int fd;

    int ret;

    UINT32 swap, diff;

    int filehead, fileend, filelen;

    UINT32 *buf_start = NULL;

 

    fd = open(pFilePath, O_RDONLY, 0777);

 

    if (fd < 0)

    {

        printf("no %s such file\n", pFilePath);

        return FPGA_FAIL;

    }

 

    filehead = lseek(fd, 0, SEEK_SET);

    fileend = lseek(fd, 0, SEEK_END);

    lseek(fd, 0, SEEK_SET);

    filelen = fileend - filehead;

 

    //dcache_disable();

    char *buf = (char *)malloc(filelen);

    if(NULL == buf)

    {

        printf("not enough mem!\n");

        return FPGA_FAIL;

    }

 

    read(fd, (char *)buf, filelen);

 

    buf_start = check_data((UINT8 *)buf, filelen, &swap);

    diff = (UINT32)buf_start - (UINT32)buf;

    /* fpga bit file */

    if (diff != 0)

    {

        ret = zynq_load(buf+diff, filelen-diff, BIT_FULL);

    }

    else  /* fpga bin file */

    {

        ret = zynq_load(buf, filelen, BIT_FULL);

    }

 

    //dcache_enable();

    if (ret != FPGA_SUCCESS)

    {

        printf("fpga load fail!\n");

        free(buf);

        close(fd);

        return FPGA_FAIL;

    }

 

    printf("fpga load success!\n");

    free(buf);

    close(fd);

 

    return FPGA_SUCCESS;

}

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

基于Zynq7000平台VxWorks6.9开发应用——FPGA动态加载篇 的相关文章

随机推荐