在FPGA上搭建Cortex-m3软核

在FPGA上搭建Cortex-m3软核

前言

​ 说是在fpga上搭建,其实还是比较偷懒了,在Vivado上进行搭建,比较方便。先来讲讲Cortex-m3这个东西,玩过单片机的人应该都用过Stm32f103c8t6这块板子,里面的核心架构就是Cortex-m3,c8t6这个器件是基于m3内核组成一块芯片。由于自己需要做一个加密解密的soc,所以需要先搭建一个m3的软核,后续在软核基础上把做好的模块挂到AXI总线上。花了一天做这个,今天就顺带着博客写了,就当作笔记了。

Cortex-m3 Design_Star计划

​ 其实多亏了Risc-V的兴起,ARM公司在前几年把m3和m0的内核通过Design_Star的活动给开源了,开发者只需要在ARM网站上注册就可以下载源码或者是IP核来直接调用,目前来看比较完善的有Xilinx和Gowin这两家体验挺好。手头没有高云的器件,只有一块4k(但是带了硬核),所以就拿手头的zynq来做这次项目。

在FPGA上搭建Cortex-m3软核_第1张图片

前期准备

硬件资源

​ 1、你需要一块Xilinx的板子,lut容量大概10k左右应该就差不多。

​ 2、jlink调试器

软件资源

​ 1、Cortex-m3的ip核

​ 2、Keil的cortex-m3的bsp

Cortex-m3软核搭建

1、创立工程文件夹

​ 为了我们方便开发,我们先建立一个名为“Cortex-m3_7010"的文件夹,文件夹下方有下图这些文件夹
在FPGA上搭建Cortex-m3软核_第2张图片

​ 其中”cm3_core“中存储的是我们下载得到的资源包中的”Arm_ipi_repository“这个文件夹。

2、建立Vivado工程

​ 本篇博客面向的是有FPGA开发经验的同学,怎么建立Vivado工程就不具体讲了,建立完工程后在Tools-Settings中找到ip相关的设置栏

在FPGA上搭建Cortex-m3软核_第3张图片

​ 在”Repository“中添加Cortex-m3的ip核的路径。

3、在Block Design中搭建Cortex-m3

​ 相信用过Vivado的同学们应该都知道Xilinx的Block Design的功能十分高效。使用方法建议百度。

​ 创建Block Design后,我们添加Cortex-m3的IP核进我们的画布中。

在FPGA上搭建Cortex-m3软核_第4张图片

​ 添加IP核处搜索Arm即可出现两个IP核,第一个就是我们想要的m3的IP核,第二个则是DAP的调试的IP核,我们使用Jlink进行调试,所以我们只需要将第一个IP核添加进来即可。

4、Cortex-m3 IP核

​ 我们双击m3的IP核就可以对其进行配置。

在FPGA上搭建Cortex-m3软核_第5张图片

​ 第一栏里的中断的数量是不需要我们去设置了,对应的IRQ的接口会根据你接入的位宽自动展开。其他的按照默认即可。

在FPGA上搭建Cortex-m3软核_第6张图片

​ 然后来调整Debug部分的设置。我使用的Jlink进行调试,同时也不需要Trace功能,所以选择”no trace“,并且将JTAG的那个勾选取消。

​ 接下来设置ITCM和DTCM的大小

在FPGA上搭建Cortex-m3软核_第7张图片

​ 上图中Initialize的勾选取消,这个功能是将ITCM/DTCM按设置进行初始化,我们不需要,取消勾选。DTCM同ITCM设置相同

​ 按照上方设置即可完成。选择OK即可。

5、时钟网络构建

​ Cortex-m3基本上最高就是跑到50M的频率,所以我们先确定时钟频率就是50M。通过”Clk_Wizard“(时钟生成向导“)这个IP核,生成对应的时钟频率,并且激活LOCKED端口即可。

在FPGA上搭建Cortex-m3软核_第8张图片

​ 输出的Clk_out1就是我们需要的时钟,将内核的时钟连到这里就行,同时我们后续外设的时钟也是使用这个。

6、复位信号网络搭建

​ 复位是很重要的一环,如果复位部分没做好的话软核很可能会跑不通。笔者到现在还是有时候会因为复位网络导致系统出错误。但是在Vivado里,有一个很好用的IP核可以帮助我们解决困难。(属实被Vivado宠坏了

在FPGA上搭建Cortex-m3软核_第9张图片

​ 就是这个,PS端复位信号的生成IP核,真挺好用的。配置的话按照默认的即可。将时钟信号接入对应的Sync_clk。外部复位信号源接入到”ext_reset_in"中。时钟的locked信号接入dcm_locked中。输出端口:

在FPGA上搭建Cortex-m3软核_第10张图片

​ “mb_reset"是输出的复位,我们将这个作为arm的ip核的系统复位信号以及debug的系统复位信号。不过需要注意的是,他这里是高电平有效的信号,我们需要生成not门来之后再接入到arm ip核中去。

​ ”Interconnect_restn"用来当作总线的复位源,”periphera“用来当作外设的复位源。这样基本的复位信号网络就搭建好了。

7、AXI总线

​ Vivado给了一个叫“AXI Interconnection"的ip核,通过这个ip核,我们可以将我们想要的总线与外设搭建起来。我们这次先将GPIO与Uart挂上AXI总线,设置好相关参数,将时钟和复位信号连接起来。

在FPGA上搭建Cortex-m3软核_第11张图片

​ 如上图,连线都是比较基本的。

8、SWD调试接口

​ 我们这次使用的是Jlink的SWD模式,在Cortex-m3上相关的接口是:

SWTCLK、SWDI/TMS、SWDO、SWDOEN这几个引脚。其中SWTCLK是调试器给的外部时钟,直接引出引脚即可,SWDI与SWDO是输入输出,但是我们在调试器上属于是双向IO,因此我们需要例化IOBUF的原语来实现双向IO的功能。

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2022/04/16 21:28:24
// Design Name: 
// Module Name: swdiobuf
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module swdiobuf(
    input swd_o,
    output swd_i,
    input swd_oe,
    inout swd_io
    );
    IOBUF swd_iobuf_inst1
    (
        .O(swd_i),
        .I(swd_o),
        .IO(swd_io),
        .T(~swd_oe)    //
        );
        
endmodule

​ 然后把这个rtl导入到Block Design中按找接口进行连线即可。

9、Cortex-m3相关接口配置

​ 有两个引脚NMI、CFGITCM需要我们手动配置一下,这两个引脚的作用可以去查看说明文档(记得是4-128页)。配置的方法可以通过常量IP核来实现。

在FPGA上搭建Cortex-m3软核_第12张图片
在FPGA上搭建Cortex-m3软核_第13张图片
在FPGA上搭建Cortex-m3软核_第14张图片

​ 上图是常量IP设置的信息。

10、地址分配

在FPGA上搭建Cortex-m3软核_第15张图片

​ 我们需要为外设进行分配存储空间。DTCM和ITCM不需要我们手动配置。右键Auto set即可。

11、创建引用文件、导出IP核

​ 这一步用过的Vivado的应该都会。就不多讲了。

12、设置引脚、综合实现

​ 设置引脚需要注意一点,SWDCLK这个引脚需要设置为FPGA上的时钟引脚,否则综合的时候会报错,显示该引脚输入的时钟无法作为时钟源来使用。(具体的报错信息忘记了)排除了以上问题之后综合实现翻译成bit流文件,通过JTAG或者其他方式下载到FPGA的板子上即可。

Keil端软件程序编写

1、Keil设置

​ Keil软件配置需要设置BSP的支持包,具体的可以去资源网站下载,安装完即可。然后需要根据我们搭建M3的软核来设置内存大小和频率。

在FPGA上搭建Cortex-m3软核_第16张图片
在FPGA上搭建Cortex-m3软核_第17张图片

​ 按上图选中信号以及配置ram地址即可。

2、Jlink配置

​ 插入Jlink连接到板子上如果出现了相关的型号,就可以说明FPGA软核搭建成功,如果有错误的话从头看看布线是否有错误。

在FPGA上搭建Cortex-m3软核_第18张图片

3、典中典之点灯

​ 每一个EE工程师的起始之路,就是点灯。今天我们在搭建好的Cortex-m3软核上通过挂载到AXI总线上的GPIO进行点灯操作。

​ 先利用官方给的DS_CM3.h的库来做一个定时器。

	SysTick_Config(SystemCoreClock/1000);

​ 这个函数可以配置一个滴答计时器,然后设置句柄来生成一个计数器。

volatile uint32_t SystemTicks =0;
void SysTick_Handler(void)
{
	SystemTicks++;
}

void Delay(uint32_t ms)
{
	uint32_t this_time=SystemTicks;
	while((SystemTicks-this_time) < ms);
}

​ 生成了这个计时器之后,就可以来点灯了。查看Vivado的内存地址分配可以看到GPIO的地址是 0x40000000;查看GPIO的库可以知道地址的一些分配之后就可以进行点灯了。

#define LED_BASEADDR 0x40000000
#define LED_DATA		 0x0000
int main()
{
	SysTick_Config(SystemCoreClock/1000);
	while(1)
	{
		*(uint32_t *)(LED_BASEADDR+LED_DATA)=0x01;
		Delay(1000); 
		*(uint32_t *)(LED_BASEADDR+LED_DATA)=0x02;
		Delay(1000 ); 
	}
}

​ 编译通过即可。

4、Jlink flash下载设置

在FPGA上搭建Cortex-m3软核_第19张图片

​ 正常来讲,这里是没有适配的,我们需要自己写一个下载的方法(需要手动改成ohchip下载,要用flash下载的话需要在搭建软核的时候重新设置code_ram);

​ 找到Arm下的Flash的文件夹。如下图:

在FPGA上搭建Cortex-m3软核_第20张图片

​ 途中的template文件夹是预留给我们用来进行自定义下载方法的模板,我们复制一份之后重命名为“DTCM_onchip"后打开工程文件进行修改。

​ 如下图修改:

在FPGA上搭建Cortex-m3软核_第21张图片
在FPGA上搭建Cortex-m3软核_第22张图片

​ 保存编译后回到Jlink的Flash页面把我们做好的添加进来,然后就可以下载了。

现象

如下图:

在FPGA上搭建Cortex-m3软核_第23张图片

如有错误欢迎指出

在FPGA上搭建Cortex-m3软核_第24张图片

你可能感兴趣的:(fpga,fpga开发,经验分享,嵌入式硬件)