工程目标
基于TLFM20S-EVM开发板,搭建PS和PL联合开发的基础功能,使用PS侧的CPU通过EMIO控制PL侧的LED灯闪烁,同时程序运行在DDR中。
开发环境
- PL开发工具:VIVADO 2018.3,主要用于PL侧逻辑开发和使用XILINX丰富的IP资源(若无需复杂的IP资源,则可以单独使用PROCISE)。
- PS开发工具:IAR 8.11.2.13606,用于编写PS侧的C语言
- 转换工具:PROCISE 2025.1.1,用于转换VIVADO工程,生成相应的BSP供后续PS开发。
- 开发板:TLFM20S-EVM,核心芯片为复旦微的FMQL20S400M,对标XILINX的XC7Z020CLG400-2。
- 下载器:XILINX的JTAG下载器、JLINK仿真器。
工程搭建步骤
- 按照《TLFM20S-EVM开发板PS和PL联合开发工程搭建》完成工程搭建,并下载程序进入调试模式。
-
调试模式中,暂停程序运行,打开View -> Disassembly。

可以查看目前程序运行在0xE1FE_xxxx地址,属于AHB_SRAM范围(0xE1FE_0000 ~ 0xE1FF_FFFF)。说明程序运行在AHB_SRAM中。

-
退出调试模式,关闭IAR。打开VIVADO,先打开Block Design。

-
双击ZYNQ核进行配置。Page Navigator选择DDR Configuration,首先勾选Enable DDR,然后打开DDR Controller Configuration,Memory Type选择DDR3(Low Voltage),Memory Part选择MT41K128M16 JT-125。然后单击OK。

回到Block界面,选择DDR引脚,右击Make External,将DDR引脚引出。

最终完成的Block如下图。

-
然后编译Block,最后生成wrapper HDL。修改top.v文件如下。
`timescale 1ns / 1ps ////////////////////////////////////////////////////////////////////////////////// // Company: // Engineer: // // Create Date: 2026/02/28 22:44:57 // Design Name: // Module Name: top // Project Name: // Target Devices: // Tool Versions: // Description: // // Dependencies: // // Revision: // Revision 0.01 - File Created // Additional Comments: // ////////////////////////////////////////////////////////////////////////////////// module top( DDR_0_addr , DDR_0_ba , DDR_0_cas_n , DDR_0_ck_n , DDR_0_ck_p , DDR_0_cke , DDR_0_cs_n , DDR_0_dm , DDR_0_dq , DDR_0_dqs_n , DDR_0_dqs_p , DDR_0_odt , DDR_0_ras_n , DDR_0_reset_n , DDR_0_we_n , FIXED_IO_ddr_vrn , FIXED_IO_ddr_vrp , FIXED_IO_mio , FIXED_IO_ps_clk , FIXED_IO_ps_porb , FIXED_IO_ps_srstb , PJTAG_0_tck , PJTAG_0_tdi , PJTAG_0_tdo , PJTAG_0_tms , PIN_PL_LED_OUT ); inout [14:0] DDR_0_addr; inout [2:0] DDR_0_ba; inout DDR_0_cas_n; inout DDR_0_ck_n; inout DDR_0_ck_p; inout DDR_0_cke; inout DDR_0_cs_n; inout [3:0] DDR_0_dm; inout [31:0] DDR_0_dq; inout [3:0] DDR_0_dqs_n; inout [3:0] DDR_0_dqs_p; inout DDR_0_odt; inout DDR_0_ras_n; inout DDR_0_reset_n; inout DDR_0_we_n; inout FIXED_IO_ddr_vrn; inout FIXED_IO_ddr_vrp; inout [53:0] FIXED_IO_mio; inout FIXED_IO_ps_clk; inout FIXED_IO_ps_porb; inout FIXED_IO_ps_srstb; input PJTAG_0_tck; input PJTAG_0_tdi; output PJTAG_0_tdo; input PJTAG_0_tms; output [0:0] PIN_PL_LED_OUT; system_wrapper system( .DDR_0_addr (DDR_0_addr ), .DDR_0_ba (DDR_0_ba ), .DDR_0_cas_n (DDR_0_cas_n ), .DDR_0_ck_n (DDR_0_ck_n ), .DDR_0_ck_p (DDR_0_ck_p ), .DDR_0_cke (DDR_0_cke ), .DDR_0_cs_n (DDR_0_cs_n ), .DDR_0_dm (DDR_0_dm ), .DDR_0_dq (DDR_0_dq ), .DDR_0_dqs_n (DDR_0_dqs_n ), .DDR_0_dqs_p (DDR_0_dqs_p ), .DDR_0_odt (DDR_0_odt ), .DDR_0_ras_n (DDR_0_ras_n ), .DDR_0_reset_n (DDR_0_reset_n ), .DDR_0_we_n (DDR_0_we_n ), .FIXED_IO_ddr_vrn (FIXED_IO_ddr_vrn ), .FIXED_IO_ddr_vrp (FIXED_IO_ddr_vrp ), .FIXED_IO_mio (FIXED_IO_mio ), .FIXED_IO_ps_clk (FIXED_IO_ps_clk ), .FIXED_IO_ps_porb (FIXED_IO_ps_porb ), .FIXED_IO_ps_srstb (FIXED_IO_ps_srstb), .GPIO_O_0 (PIN_PL_LED_OUT ), .PJTAG_0_tck (PJTAG_0_tck ), .PJTAG_0_tdi (PJTAG_0_tdi ), .PJTAG_0_tdo (PJTAG_0_tdo ), .PJTAG_0_tms (PJTAG_0_tms ) ); endmodule - VIVADO中重新编译工程,生成bit。
-
打开原Procise工程,PSOC -> From Vivado,按之前从VIVADO工程中导入的步骤完成Load Block Design配置。

导入过程中提示Overwrite Operation,选择Yes即可。

然后提示Make Interface External,选择OK即可。

-
弹出Export Hardware对话框,勾选Empty和FSBL,然后单击OK即可。稍等片刻,会自动打开IAR工程。

-
首先修改ICF文件,打开工程文件夹,procise -> SDK -> system_platform -> Empty,将a7_ahbsram.icf复制一份,并改名为a7_ddr_me.icf。然后使用文本编辑器打开,做如下修改。
修改ICFEDIT_PS_DDR_end地址为0x20100000。(因为开发板配置的DDR为512MB;若配置了1GB,则无需修改)
修改ICFEDIT_region_RAM_start和ICFEDIT_region_RAM_end的地址为ICFEDIT_PS_DDR_start和ICFEDIT_PS_DDR_end。(将RAM映射地址由AHB_SRAM改为PS DDR)

其余无需修改,保存即可。
-
回到IAR,workspace区域选择下方的Empty(即将Empty工程设为active)。然后单击Empty-Debug,右击选择Option。

-
Options for node "Empty"对话框中,Category中选择Linker,右侧选择Config,Linker Configuration file中选择...,找到前文修改的a7_ddr_me.icf文件。

-
然后Category中选择J-Link/J-Trace,右侧选择Setup,Reset中选择Software。(因为调试时,先使用IAR加载FSBL文件,完成DDR初始化;然后再下载开发的APP文件。若下载的APP文件选择硬件复位,则会清除DDR的初始化状态,导致程序加载错误,故改为软件复位)

-
单击OK关闭Options对话框。打开empty.c文件,注释init_platform()调用,新增icache_enable()调用。如下:
#include "platform.h" #include "fmsh_gpio_public.h" #include "fmsh_ps_parameters.h" void main() { //init_platform(); icache_enable(); //Enable USER_LEVEL_SHIFTER REG FMSH_WriteReg(FPS_SLCR_BASEADDR, 0x008, 0xDF0D767BU); //unlock SLCR FMSH_WriteReg(FPS_SLCR_BASEADDR, 0x838, 0xF); //enablue usr_lvl_shifter FMSH_WriteReg(FPS_SLCR_BASEADDR, 0x004, 0xDF0D767BU); //lock SLCR FGpioPs_Config* gpio_cfgPpr; gpio_cfgPpr = FGpioPs_LookupConfig(FPAR_GPIOPS_2_DEVICE_ID); FGpioPs_T gpios; FGpioPs_init(&gpios, gpio_cfgPpr); FGpioPs_setDirection(&gpios, 0xf); while(1) { FGpioPs_writeData(&gpios, FMSH_BIT0); delay_ms(500); FGpioPs_writeData(&gpios, 0x0); delay_ms(500); } //example_test(Device_ID); } -
单击Empty-Debug,右击,选择Rebuild All。编译完成即可。

-
workspace区域选择下方的FSBL(即将FSBL工程设为active)。单击FSBL-Deubg,右击选择Rebuild All。编译完成即可。

- 给开发板接上xilinx下载器和JLINK仿真器,配置的拨码开关选择JTAG独立模式([3:0] = 1000),然后开发板加电。
- 回到VIVADO,烧写bit。
- 回到IAR,workspace下方选择FSBL,单击Download and Debug,下载FSBL程序并进入调试模式。单击Go,运行3-5秒钟即可退出调试模式。(此时已完成DDR的初始化)
- workspace下方选择Empty,单击Download and Debug,下载Empty程序并进入调试模式。单击Go,可以看到开发板上EMIO控制的LED灯在闪烁。
- 单击Break,中断程序运行。View -> Core,打开Cores窗口,可以看到PC寄存器的地址范围在0x0010_0000 ~ 0x3FFF_FFFF之间,该区域为DDR3的地址范围,说明程序运行在DDR中。(注,因开发板DDR实际大小为512MB,故PC寄存器的地址范围应在0x0010_0000 ~ 0x2010_0000之间)。
总结:
- ICF文件要修改正确。
- APP工程的复位要改为软件复位,否则会重置DDR的状态,没法进行程序调试。
- 软件烧写先后顺序:bit -> FSBL -> APP。
- 开发板配置要正确,否则FSBL烧写完成后,会自动按配置进行加载,如SPI模式,则会读取SPI内的程序,导致后续APP烧写无法连接JLINK等问题。
- APP的初始代码要屏蔽ps_init()调用(通过注释main中的init_platform()),防止重复初始化DDR。
- 仅使能icache,不要使能dcache(dcache的使能方式还未摸索出来,使能会导致程序进入异常中断)。
如果这篇文章对您有帮助,欢迎打赏支持。
若需要工程原文件,请打赏5元后发送索取邮件到crazychip999@qq.com,记得附上打赏截图。