CortexM3系列2:基于ZYNQ7020实现CortexM3
介绍
使用ARM 的Design Start计划,FPGA版本的M3核,在FPGA开发板上面进行例化,搭建soc。
这里使用的FPGA板卡是ZYNQ7020,有官方板卡可以直接跑官方ARM的例程,但是没有的话,也可以进行移植,本文使用的是ZYNQ7020。
实现的功能就是在PL端例化CortexM3核,同时加入GPIO 的ip来点亮LED灯。
参考了两位博主的文章和视频,感谢。
下面我们正式开始
Block Design设计
准备CortexM3核
从ARM 官网下载资料 AT326,需要注册ARM账号
下载好之后解压,注意 vivado\Arm_ipi_repository这个目录,后面在vivado中要作为ip repository添加进来
新建工程
在D盘目录下,新建Y文件夹,这里是为了避免路径过长
然后新建hardware文件夹,如下图所示
打开vivado(版本为2019.01),创建vivado工程,选择芯片型号(这里是xc7z020clg400-2)
新建工程名称为 : zynq_m3,工程路径为: D:/Y/hardware/zynq_m3
把上面的vivado\Arm_ipi_repository复制到 D:/Y/
将ip添加到vivado工程中
打开 IP Catalog,发现M3的ip核已经添加进来
Block Design设计
新建block design,添加Cortex M3 ip。有关Block Design的使用可以参考这篇博文
下面进行相关ip的配置和连接,本文只列出需要修改的部分,没有提及的部分,全部保持默认配置即可。
对Cortex M3 ip进行配置
- 不用Trace功能和JTAG
- Instruction Memory 和 Data Memory都设置为64KB,不用初始化。(这里ARM官方的教程是需要初始化ITCM的,但是我在移植到zynq的时候一直没有弄好,后面采用了通过STLINK烧录的方式写入ITCM,参考了参考1,参考2,参考3)
完成对Coretex M3的配置,下面进行其他部分的配置和连接
添加Clock和Reset模块
添加clock和reset模块
添加 clocking wizard模块,配置如下,输出50M时钟
把输入时钟调整为50MHz
添加Processor System Reset模块,保持默认配置即可
添加完ip情况如下图所示
添加SWD模块
添加 swdio_tri_buffer.v文件
内容如下
`timescale 1ns / 1ps
module swdio_tri_buffer(
input swd_o,
output swd_i,
input swd_oe,
inout swd_io
);
IOBUF swd_iobuf_inst(
.O(swd_i),
.I(swd_o),
.IO(swd_io),
.T(~swd_oe)//T: 1 : offchip -> onchip; 0: onchip->offchip
);
endmodule
在block design中,右键空白处,选择 Add Module,选择加入刚才的swdio_tri_buffer.v文件
加入后 block design如下
添加GPIO模块
添加 AXI GPIO模块
添加后模块如下
添加其他模块并连线
右键clocking wizard模块的clk_in,选择Make External,将信号改名为m3clock,设置为50MHz
同理,将clocking wizard模块的resetn,通过Make External引出,改名为reset_n
添加utility vector logic模块,配置为1bit,or功能
添加两个constant模块
一个配置为1bit 的0,命名为constant_0。一个配置为2bit的1,命名为constant_1。
除了GPIO没有连接,其他连接关系如下。
然后点击 Run Connection Automation
点击OK 后,自动连接GPIO,并添加了AXI Interconnect模块
确保时钟线连接情况,都是clk_out1出来
复位线情况
修改gpio引出的引脚名称为led_0
最终连接情况如下
进行地址分配,根据Cortex M3手册发现外设地址空间为0x4000_000到0x4013_FFFF。所以给GPIO分配0x4000_000到0x4000_FFFF
然后点击Validate验证
至此硬件配置完成,添加约束文件,生成比特流即可。可以参考本文的约束文件,根据自己的开发板修改
create_clock -period 20.000 -name m3clock -waveform {0.000 10.000} [get_nets m3clock]
set_property PACKAGE_PIN U18 [get_ports m3clock]
set_property IOSTANDARD LVCMOS18 [get_ports m3clock]
set_property PACKAGE_PIN D19 [get_ports reset_n]
set_property IOSTANDARD LVCMOS33 [get_ports reset_n]
set_property PACKAGE_PIN B20 [get_ports led_0_tri_o]
set_property IOSTANDARD LVCMOS33 [get_ports led_0_tri_o]
set_property PACKAGE_PIN E17 [get_ports swdio]
set_property IOSTANDARD LVCMOS33 [get_ports swdio]
set_property PACKAGE_PIN E18 [get_ports swclk]
set_property IOSTANDARD LVCMOS33 [get_ports swclk]
set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets swclk_IBUF]
软件设计
Keil环境配置
需要准备
一个ST-Link下载器,相关连接和调试方法参考这篇文章
一个DesignStart专用的器件包,可以在Keil的pack installer里面选择DS_CM3安装
Keil新建工程
在D:/Y/新建software/m3_for_zynq,新建Keil工程。选择DS_CM3 package,选择CMSIS CORE和Startup
调整C/C++配置,修改warning等级
配置地址空间,ITCM对应IROM1,起始地址为0x0,大小为64K,跟硬件对应。DTCM对应IRAM1,起始地址为0x20000000,大小为64K
通过ST-LINK连接板子对应的SWD引脚后,先烧录bit流。然后如果此时能检测到,说明Cortex-M3核的SWD正常工作。(如果检测不到SWD,则下载bit流后,手动对CortexM3的reset_n引脚进行复位,注意不是对板子进行复位,而是对CortexM3进行复位。)
Flash文件制作
通过SWD本来是要烧录到Flash里面的,但是我们是想烧录到ITCM里面。对于keil而言没有ITCM的Flash模型,所以我们可以自己制作一个。
参考2
参考3
找到Keil的安装目录,然后进入C:\keil\ARM\flash文件夹(根据自己安装keil的路径),将_Template文件夹复制一份,命名为ITCMOnChip,然后打开 ITCMOnChip里面的keil工程
首先打开 FlashDev.c文件在这里插入图片描述,修改名称,起始地址和大小(这个和ITCM保持一致就行,起始地址是0x00000000,大小是64KB),然后修改sector,只保留一个sector就行(设置sector的时候注意,前面是size后面是地址)
配置好后保存FlashDev.c文件,打开FlashPrg.c文件
首先在顶部添加对string.h的include
#include <string.h>
然后编辑擦除函数,就是擦除内容所有内容
然后是擦除一个sector
最后是编辑写入数据的函数
点击编译,然后会在工程文件同路径下生成一个NewDevice.FLM文件
我们把这个FLM文件改名为ITCMOnChip.FLM,然后把它复制到上一级目录(我这里是C:\keil\ARM\flash)
至此Flash文件制作完成
烧录工程
回到新建的M3软件工程中,添加如下main.c文件
编译成功后
点开Debug配置窗口,配置ST-Link和Flash(注意此时的硬件开发板需要上电,同时烧录好上面生成的bit流)
都配置好后,点击ok
然后点击烧录
如果出现无法烧录的情况,尝试将CortexM3的复位引脚接地,然后重新下载bit流,然后断开复位引脚重新烧录或者烧录完后断开复位引脚,烧录成功后等待一会,led灯开始闪烁。
完成配置。
总结
本篇文章讲解了如何在ZYNQ上面实现CortexM3的集成,并且点亮了LED,实现了闪烁的效果。至于其他的外设比如UART,SPI甚至自己写的加速器ip,都可以在block design中通过总线连接的方式连接到CortexM3核,类似PS-PL的教程。该系列完成,在此对本文参考的资料作者表示感谢。