0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

用FPGA搭建一个STM32内核?

硬件攻城狮 来源:硬件攻城狮 2023-03-20 10:11 次阅读

1.必要的基础知识

为了更快的完成在FPGA上实现ARM Cortex-M3软核,一些必要的基础知识还是要有的!

FPGA开发基础知识,如FPGA开发流程,设计、综合、布局、布线、约束、下载

Xilinx Vivado开发环境使用基础,如BlockDesign设计方式,管脚分配,Bit流文件生成与下载

ARM Cortex-M3内核的使用基础,如STM32MM32GD32、CH32等微控制器的开发。

Keil-MDK开发环境的使用基础,基本的工程建立、编译、下载流程。

如果以上知识都具备,那么,恭喜你!可以在2小时内完成ARM Cortex-M3软核在FPGA上的实现。

2.Cortex-M3 FPGA IP核下载

首先,我们需要从ARM官网上获取ARM Cortex-M3 FPGA软核IP包

下载地址如下:

https://silver.arm.com/browse/AT426

文件名称:Cortex-M3 DesignStart FPGA-Xilinx edition(r0p1-00rel0)

文件大小:7.52MB

MD5SUM:cd67536c29023429cde47130d51b6f49

官网下载需要先注册账号,如果下载速度很慢,可以在公众号后台回复:220318,获取下载链接,复制到浏览器下载。

f585d4ee-c4b7-11ed-bfe3-dac502259ad0.jpgARM官网

压缩包解压之后,共有4个文件夹:

f5b91c3c-c4b7-11ed-bfe3-dac502259ad0.jpg压缩包内容

各个文件夹存放的内容:

docs

存放ARM Cortex-M3处理器参考手册、DesignStart FPGA版本使用说明、基于Arty-A7开发板的顶层BlockDesign框图等文件。

hardware

存放基于Digilent Arty-A7开发板的Vivado工程,顶层BlockDesign文件,管脚约束文件,Testbench文件等。

software

存放Keil-MDK工程,SPI Flash的编程算法文件等。

vivado

包括DesignStart Cortex-M3 Xilinx FPGA版本的IP核文件,其中Arm_ipi_repository文件夹就是内核源文件了,IP文件内容已经加密,没有可读性。

f5d72768-c4b7-11ed-bfe3-dac502259ad0.jpgIP核源码

3.硬件准备

为了完成DS CM3在FPGA上的搭建,我们至少需要以下硬件:

一块Artix-7开发板,用于构建Cortex-M3软核SoC,我使用的是正点原子达芬奇Pro开发板,FPGA型号为XC7A100T

Xilinx FPGA下载器,用于下载软核Bit流到FPGA,如Platform Usb Cable,JTAG-HS2/HS3等。

ARM Cortex-M‍3调试器,用于调试ARM核程序下载和调试,如JlinkV9,Jlink-OB等。

官方的DS CM3 IP核是基于Digilent的Arty-A7开发板,FPGA型号为XC7A35T/100T,Vivado版本为v2019.1,如果你手头正好有这块开发板,那么可以直接使用官方提供的示例工程。

arty-a7开发板

正点原子达芬奇Pro开发板

4.软件准备

Xilinx Vivado开发环境,官方建议版本为2018.2以上,我使用的是2018.3版本

Keil MDK开发环境,如5.33版本

DS_CM3的Keil器件包

从Keil官网上下载DesignStart Cortex-M3所专用的器件支持包,下载链接如下:

https://keilpack.azureedge.net/pack/Keil.V2M-MPS2_DSx_BSP.1.1.0.pack

5.Cortex-M3软核搭建

准备好以上软硬件,就可以开始Cortex-M3软核的搭建了。

首先,新建一个文件夹,命名为cortex_m3_on_xc7a100t,用于存放本次示例所有的工程文件,并新建以下几个文件夹:

f6c391f2-c4b7-11ed-bfe3-dac502259ad0.jpg目录结构

每个文件夹的功能:

bd文件夹

用来存放BlockDesign设计

cm3_core文件夹

用来存放的是ARM Cortex-M3内核IP核文件,

doc文件夹

用来存放设计文档

flash文件夹

用来存放生成的bit和mcs文件

rtl文件夹

用来存放用户设计的verilog源文件

xdc文件夹

用来存放管脚、时序约束文件

其中cm3_core文件夹,需要将官方压缩文件文件中的Arm_ipi_repository文件夹复制过来,路径为AT426-BU-98000-r0p1-00rel0vivadoArm_ipi_repository

以上文件夹准备好之后,就可以开始新建工程了。

5.1 新建Vivado工程

打开Vivado 2018.3,打开工程创建向导,输入工程名称,工程的存放路径为之前我们新建的文件夹。

f7017760-c4b7-11ed-bfe3-dac502259ad0.jpg新建工程

选择FPGA芯片的完整型号:XC7A100TFGG484

f71d5bd8-c4b7-11ed-bfe3-dac502259ad0.jpg选择芯片型号

最终创建完成之后的工程目录

f743a1da-c4b7-11ed-bfe3-dac502259ad0.jpgVivado工程目录

5.2 添加IP核搜索路径

为了能在BlockDesign中搜索到ARM Cortex-M3处理器IP核,我们需要把ARM 软核IP所在的路径添加到搜索路径。

f766901e-c4b7-11ed-bfe3-dac502259ad0.jpg添加到搜索路径

5.3 创建BlockDesign设计

为了方便后续使用图形化的方式连接各IP核,我们采用BlockDesign图形化的设计方式,这样可以快速的搭建出一颗定制化的软核处理器。

新建BlockDesign,命名为cm3_core,保存到最初创建的bd文件夹中。

在画布中添加Cortex-M3处理器核:

f7a8277c-c4b7-11ed-bfe3-dac502259ad0.jpg添加ARM核

双击Cortex-M3 IP核进行一些基本配置,我们不需要Trace功能,选择No Trace,使用SWD接口调试,禁用JTAG端口

f7cc7a1e-c4b7-11ed-bfe3-dac502259ad0.jpg配置ARM核

指令空间和数据空间大小,这里设置成64KB,都不进行初始化。

f808b02e-c4b7-11ed-bfe3-dac502259ad0.jpgITCM核DTCM配置

5.4 添加一些必要的IP核

时钟PLL

用于提供给内核、总线、外设时钟,这里我们配置成50MHz单端输入,PLL输出配置成50MHz,如果时钟频率设置更高,综合后会提示WNS,TNS时序不满足,可能会影响系统的正常运行。

处理器复位IP

用于提供内核、外设、互联组件所需要的复位信号,不需要进行定制,保持默认设置。

总线互联IP

Cortex-M3内核为AHB总线,而且内部已经转换成了AXI3总线,而Xilinx官方提供的GPIO/UART等外设IP核是AXI4-Lite总线,所以需要添加一个总线互联矩阵,用于将不同协议进行转换,从机数量配置为1,主机数量配置为2,连接到处理器的SYS总线。

基本逻辑门IP

Cortex-M3内核需要低电平复位,而复位IP输出为高电平复位,需要在中间插入一个非门来进行转换。

常量IP

本次软核搭建不涉及中断部分,所以IRQ和NMI都给定常量0即可,如果需要将中断接入处理器,可以通过Concat核将多个中断源合并成一个连接到IRQ。

将以上IP添加到BlockDesign画布中,并按照下图进行连接:

f82df668-c4b7-11ed-bfe3-dac502259ad0.jpg原理图连接

从官方手册中可以知道,ARM提供的软核IP中已经包括了ITCM和DTCM存储器,所以我们无需添加外部的BRAM来作为程序和数据的存储区。

f8674404-c4b7-11ed-bfe3-dac502259ad0.jpgCortex-M3内核结构

内核中提供ITCM和DTCM都是基于RAM实现,这也就意味着后续我们使用Keil下载程序只是下载到RAM中,掉电数据会丢失。

至此,ARM Cortex-M3处理器内核就搭建完成了,下面来添加GPIO和UART外设。

5.5 添加GPIO和UART外设

一些常用的单片机,如STM32,芯片内部的TIM、UART、SPI、CAN等外设一般是固定数量的,而我们使用FPGA来搭建ARM软核SoC就比较灵活了,如果你不需要SPI,那就不用添加SPI外设,需要10个UART就添加10个UART,外设配置比较灵活,当然这些外设都是基于FPGA逻辑资源实现的,实际添加的数量会受限于FPGA芯片的逻辑资源大小。

下面以添加一组AXI GPIO和一组AXI UART为例,介绍如何使用ARM软核来控制这两个外设。

Xilinx官方提供的AXI GPIO外设具有以下特性:

内部有两个通道,通道1和通道2,每个通道最多支持32个管脚

每个管脚可以配置成输入或输出模式

每个管脚可以设置复位初值

支持中断输出

提供的AXI UART外设有以下特性:

全双工

支持5-8位数据位

支持奇偶校验

可配置波特率110-230400

这里我们将GPIO配置成双通道,通道1为输出模式,低4位用于连接LED通道2为输入模式,低4位用于连接按键。

f896cb70-c4b7-11ed-bfe3-dac502259ad0.jpgGPIO配置

UART配置成115200波特率,8位数据位,无奇偶校验。

f8af466e-c4b7-11ed-bfe3-dac502259ad0.jpgUART配置

配置完成之后,将它们连接的到互联IP的主机接口上:

f8d3d60a-c4b7-11ed-bfe3-dac502259ad0.jpg原理图连接

这两组IP的时钟可以和处理器使用同样的时钟,复位可以使用复位IP输出的外设复位信号。

关于AXI GPIO和AXI UART的详细使用,可以查看官方文档:

pg144-axi-gpio.pdf

https://www.xilinx.com/support/documentation/ip_documentation/axi_gpio/v2_0/pg144-axi-gpio.pdf

pg142-axi-uartlite.pdf

https://www.xilinx.com/support/documentation/ip_documentation/axi_uartlite/v2_0/pg142-axi-uartlite.pdf

5.6 SWD接口的引出

官方的DesignStart IP核资料中,除了Cortex-M3处理器,还有一个DAP-Link调试核,如果使用DAP-Link调试器需要添加这个IP核。

f8f4845e-c4b7-11ed-bfe3-dac502259ad0.jpgDAP-Link

这里我们不使用DAP-Link调试器,而是使用Jlink SWD模式。SWD模式一共需要两根线,一个是SWCLK时钟信号,一个是SWDIO双向数据信号,处理器提供了3个管脚:SWDI,SWDO和SWDOEN,我们还需要实现一个双向端口模块。

基于IOBUF原语实现的双向端口模块,内容如下:

moduleswdio_tri_buffer(
//Inputs
inputswd_o,
inputswd_oe,

//Outputs
outputswd_i,

//Inouts
inoutswd_io
);

IOBUFswd_iobuf_inst(
.O(swd_i),
.I(swd_o),
.IO(swd_io),

.T(!swd_oe)
);

endmodule

将它添加到我们的设计中。

f923c822-c4b7-11ed-bfe3-dac502259ad0.jpgSWD接口连接

最终的BlockDesign设计如下图所示:

f934723a-c4b7-11ed-bfe3-dac502259ad0.jpg原理图连接

5.7 分配外设基地址

添加完外设IP之后,我们还需要对外设进行基地址和空间分配,在地址编辑框,右键选择自动分配。

f996e384-c4b7-11ed-bfe3-dac502259ad0.jpg基地址分配

分配完成之后,使用设计验证(Validate Design)功能,可以检查当前BlockDesign设计连接的合法性。

f9cf2834-c4b7-11ed-bfe3-dac502259ad0.jpg验证设计

5.8 生成Wrapper并例化到顶层

为了方便后续添加自定义的FPGA逻辑模块,我们将Cortex-M3软核处理器作为一个处理器例化到顶层设计中。

在BlockDesign源文件上右键,先选择Generate Output Products,耐心等待生成完成之后,选择Create HDL Wrapper。

f9ef3e6c-c4b7-11ed-bfe3-dac502259ad0.jpg生成Wrapper

之后就会生成一个_wrapper的verilog文件。

新建顶层文件top_hdl.v并保存到rtl文件夹,将_wrapper例化到顶层。

moduletop_hdl(
//Inputs
inputclk,
inputrst_n,
inputswclk,
inputuart_rxd,
input[3:0]sw,

//Outputs
output[3:0]led,
outputuart_txd,

//Inouts
inoutswdio
);

cm3_core_wrappercm3_core_wrapper_ut0(
//Inputs
.cm3_clk(clk),
.cm3_resetn(rst_n),
.cm3_gpio_in_tri_i(sw[3:0]),
.cm3_swclk(swclk),
.cm3_uart_rxd(uart_rxd),

//Outputs
.cm3_gpio_out_tri_o(led[3:0]),
.cm3_uart_txd(uart_txd),

//Inouts
.cm3_swdio(swdio)
);

endmodule//top_hdlend

5.9 管脚分配

综合(Synthesis)完成之后,使用Vivado的图形化工具进行管脚分配,尤其注意要将SWDIO和SWDCLK引出到排针管脚上,方便后续使用外接的Jlink调试器进行ARM程序下载。

fa159620-c4b7-11ed-bfe3-dac502259ad0.jpg分配管脚

或者直接新建XDC文件,使用约束语句进行管脚分配。

部分约束语句:

set_propertyPACKAGE_PINR4[get_portsclk]
set_propertyPACKAGE_PINV13[get_portsswclk]
set_propertyPACKAGE_PINV14[get_portsswdio]
set_propertyPACKAGE_PINE14[get_portsuart_rxd]
set_propertyPACKAGE_PIND17[get_portsuart_txd]
set_propertyPACKAGE_PINU7[get_portsrst_n]
set_propertyPACKAGE_PINV9[get_ports{led[3]}]
set_propertyPACKAGE_PINY8[get_ports{led[2]}]
set_propertyPACKAGE_PINY7[get_ports{led[1]}]
set_propertyPACKAGE_PINW7[get_ports{led[0]}]
set_propertyPACKAGE_PINT4[get_ports{key[3]}]
set_propertyPACKAGE_PINT3[get_ports{key[2]}]
set_propertyPACKAGE_PINR6[get_ports{key[1]}]
set_propertyPACKAGE_PINT6[get_ports{key[0]}]

如果你的板子和我的(正点原子达芬奇Pro)一样,那么可以直接使用以上管脚约束。

如果你分配的时钟管脚不是FPGA的全局时钟管脚,需要添加BUFG原语进行缓冲。

5.10 Bit流文件生成和下载

我的板子使用的是QSPI Flash,为了提高下载和启动速度,在生成Bit流时,配置生成选项:数据压缩、50M读取速度,4位数据线

fb0a1af6-c4b7-11ed-bfe3-dac502259ad0.jpg生成Bit流配置

或者直接使用XDC语句进行约束:

set_propertyBITSTREAM.GENERAL.COMPRESSTRUE[current_design]
set_propertyBITSTREAM.CONFIG.CONFIGRATE50[current_design]
set_propertyCONFIG_VOLTAGE3.3[current_design]
set_propertyCFGBVSVCCO[current_design]
set_propertyBITSTREAM.CONFIG.SPI_BUSWIDTH4[current_design]

以上约束不是必须的,只是为了提高下载和配置速度。

耐心等待工程综合完成,生成Bit流文件,综合的速度和处理器主频、核心数有关。

和常规的FPGA下载方式一样,将生成的软核Bit文件通过Xilinx下载器下载到FPGA内部,先不要固化到外部SPI Flash 。

手头没有Xilinx下载器的,可以参考之前的文章,自己做一个JTAG-HS2下载器

开源、低成本的Xilinx FPGA下载器

5.11 Jlink连接测试

下载完成之后,现在FPGA内部运行的就是一颗基于ARM Cortex-M3的软核处理器了,使用Jlink等调试工具可以连接到芯片。

将Jlink调试器的SWCLK和SWDIO连接到我们分配的管脚V13和V14上。

手头没有Jlink的,也可以参考之前的文章,自己做一个Jlink-OB

手把手教你制作Jlink-OB调试器

使用Keil开发DesignStart Cortex-M3软核的程序,需要先安装一个DesignStart专用的器件包。

打开一个STM32 Keil工程,器件修改为刚刚安装的ARM DS_CM3,在Option->Debug-Setting界面中选择SWD方式,第一次连接会提示需要选择一个器件,这里选择Cortex-M3:

fb58cce6-c4b7-11ed-bfe3-dac502259ad0.jpg选择器件型号

如果以上配置均正确,就能看到已经连接到的ARM Cortex-M3核心。如果没有,说明FPGA工程配置有错误,需要确认是否和以上配置流程一致。

fb7e002e-c4b7-11ed-bfe3-dac502259ad0.jpg连接到ARM核心

至此,ARM Cortex-M3软核基本搭建完成,接下来我们使用Keil来编写ARM核的程序,实现GPIO和UART的控制。

6.Cortex-M3软核程序设计

和常规的ARM Cortex-M3内核单片机开发流程类似,使用Keil新建工程,源文件,根据外设使用手册,读写指定的寄存器实现GPIO的控制,UART数据写入,编译下载,调试。

在之前创建的cortex_m3_on_xc7a100t文件夹下,新建mdk_prj文件夹,用于保存Keil-MDK的工程,并新建以下3个文件夹:

application//用户源文件
object//编译生成的文件
project//Keil的工程文件

6.1 新建Keil工程

打开Keil-MDK,选择Project->New Project,新建一个工程,命名为ds_cm3_prj,保存到project目录下。

fbb793e8-c4b7-11ed-bfe3-dac502259ad0.jpgKeil工程目录

器件型号选择我们新安装的ARM Cortex-M3 DS_CM3内核。

fbe97d68-c4b7-11ed-bfe3-dac502259ad0.jpg选择器件型号

组件管理界面中,添加CMSIS内核文件和Startup启动文件:

fc113f06-c4b7-11ed-bfe3-dac502259ad0.jpg添加内核文件

并按照如下结构组织文件:

fc4e076a-c4b7-11ed-bfe3-dac502259ad0.jpg文件结构

6.2 设置RAM和ROM地址

在工程选项中设置片上ITCM的起始地址0x0、大小64K,片上DTCM起始地址0x20000000、大小64K:

fc7bb200-c4b7-11ed-bfe3-dac502259ad0.jpgRAM地址配置

起始地址来源于使用手册中图4-1系统内存地址映射,可以看到其中ITCM和DTCM的起始地址:

fc8f8e92-c4b7-11ed-bfe3-dac502259ad0.jpgITCM和DTCM起始地址

大小是我们在Cortex-M3内核配置中设置的大小:

fcbd22ee-c4b7-11ed-bfe3-dac502259ad0.jpgITCM和DTCM大小

设置完成之后,新建main.c文件,输入以下内容,编译工程,应该无错误输出。

#include"DS_CM3.h"
#include"system_DS_CM3.h"

intmain(void)
{
while(1)
{

}
}

6.3 GPIO输入输出控制

通过查看AXI GPIO的使用手册,通道1的数据寄存器偏移地址为0,通道2的数据寄存器偏移地址为0x08,根据Vivado中的连接,LED连接到通道1,按键连接到通道2上,所以只需要对这两个寄存器地址进行读写,就可以实现LED的控制和拨码开关状态的读取。

fcdd689c-c4b7-11ed-bfe3-dac502259ad0.jpgAXI GPIO寄存器定义

在Vivado地址分配界面,可以看到GPIO和UART的基地址分别为:0x4000_0000和0x4060_0000。

fd180f88-c4b7-11ed-bfe3-dac502259ad0.jpg外设基地址

LEL控制和拨码开关读取:

*(volatileuint32_t*)(0x40000000+0x0)=0x0f;//GPIO通道1低4位写1
*(volatileuint32_t*)(0x40000000+0x0)=0x00;//GPIO通道1低4位写0

uint32_tsw=0;
sw=*(uint32_t*)(0x40000000+0x08);//获取GPIO通道2的32位输入状态

6.4 串口数据发送和接收

向串口发送FIFO写入一字节数据:

while((*(volatileuint32_t*)(0x40600000+0x08))&0x08!=0x08);//等待发送FIFO不满
*(volatileuint32_t*)(0x40600000+0x04)=0x41;//向串口发送FIFO写入字符'A'=0x41

从串口接收一字节数据:

uint8_tdat=0;
if((*(volatileuint32_t*)(0x40600000+0x08))&0x01==1)//串口接收FIFO中有数据
dat=(*(volatileuint32_t*)(0x40600000+0x00));//从接收FIFO中读取1字节数据。

关于AXI GPIO和AXI UART寄存器的详细说明,可以查看官方文档:

pg144-axi-gpio.pdf

https://www.xilinx.com/support/documentation/ip_documentation/axi_gpio/v2_0/pg144-axi-gpio.pdf

pg142-axi-uartlite.pdf

https://www.xilinx.com/support/documentation/ip_documentation/axi_uartlite/v2_0/pg142-axi-uartlite.pdf

6.5 延时函数实现

为了让LED的变化,可以被人眼所看到,需要使用延时函数对亮灭进行延时。

使用系统滴答定时器实现一个延时函数:

volatileuint32_tcnt=0;//volatile类型

voidSysTick_Handler(void)
{
cnt++;
}

voiddelay_ms(uint32_tt)
{
cnt=0;
while(cnt-t>0);
}

为了让延时函数准确延时,我们还需要更改工程中的系统时钟频率,和FPGA中配置的内核时钟保持一致。

fd4f0060-c4b7-11ed-bfe3-dac502259ad0.jpg

系统时钟

完成的main.c文件内容:

#include"DS_CM3.h"
#include"system_DS_CM3.h"
//C库
#include
#include
#include

#defineBASEADDR_LED0x40000000
#defineBASEADDR_UART0x40600000
#defineCHANNEL_LED1
#defineCHANNEL_SW2

#defineXGPIO_CHAN_OFFSET8
#defineXGpio_WriteReg(BaseAddress,RegOffset,Data)Xil_Out32((BaseAddress)+(RegOffset),(uint32_t)(Data))
#defineXGpio_ReadReg(BaseAddress,RegOffset)XGpio_In32((BaseAddress)+(RegOffset))

#defineXUL_TX_FIFO_OFFSET4/*transmitFIFO,writeonly*/
#defineXUL_STATUS_REG_OFFSET8/*statusregister,readonly*/
#defineXUL_SR_TX_FIFO_FULL0x08/*transmitFIFOfull*/

#defineXUartLite_GetStatusReg(BaseAddress)XUartLite_ReadReg((BaseAddress),XUL_STATUS_REG_OFFSET)
#defineXUartLite_ReadReg(BaseAddress,RegOffset)XGpio_In32((BaseAddress)+(RegOffset))

#defineXUartLite_IsTransmitFull(BaseAddress)
((XUartLite_GetStatusReg((BaseAddress))&XUL_SR_TX_FIFO_FULL)==
XUL_SR_TX_FIFO_FULL)

#defineXUartLite_WriteReg(BaseAddress,RegOffset,Data)Xil_Out32((BaseAddress)+(RegOffset),(uint32_t)(Data))

volatileuint32_tcnt=0;

voidSysTick_Handler(void)
{
cnt++;
}

voiddelay_ms(uint32_tt)
{
cnt=0;
while(cnt-t>0);
}

uint32_tXGpio_In32(uint32_tAddr)
{
return*(volatileuint32_t*)Addr;
}

voidXil_Out32(uint32_tAddr,uint32_tValue)
{
volatileuint32_t*LocalAddr=(volatileuint32_t*)Addr;
*LocalAddr=Value;
}

uint32_tXGpio_DiscreteRead(uint32_tAddr,uint8_tChannel)
{
returnXGpio_ReadReg(Addr,(Channel-1)*XGPIO_CHAN_OFFSET);
}

voidXGpio_DiscreteWrite(uint32_tAddr,uint8_tChannel,uint32_tData)
{
XGpio_WriteReg(Addr,(Channel-1)*XGPIO_CHAN_OFFSET,Data);
}

voidXUartLite_SendByte(uint32_tBaseAddress,uint8_tData)
{
while(XUartLite_IsTransmitFull(BaseAddress));
XUartLite_WriteReg(BaseAddress,XUL_TX_FIFO_OFFSET,Data);
}

voidcm3_print(constchar*ptr)
{
while(*ptr!=(char)0){
XUartLite_SendByte(BASEADDR_UART,*ptr);
ptr++;
}
}

voidMyUartPrintf(char*fmt,...)
{
unsignedcharUsartPrintfBuf[296];
va_listap;
unsignedchar*pStr=UsartPrintfBuf;

va_start(ap,fmt);
vsnprintf((char*)UsartPrintfBuf,sizeof(UsartPrintfBuf),(constchar*)fmt,ap);
va_end(ap);

while(*pStr!=0)
{
XUartLite_SendByte(BASEADDR_UART,*pStr);
pStr++;
}
}

voidled_blink(void)
{
XGpio_DiscreteWrite(BASEADDR_LED,CHANNEL_LED,0);
delay_ms(500);
XGpio_DiscreteWrite(BASEADDR_LED,CHANNEL_LED,0xf);
delay_ms(500);
}

intmain(void)
{
uint32_tsw=0;

SystemCoreClockUpdate();
SysTick_Config(SystemCoreClock/1000);

cm3_print("HelloDesignStartARMCortex-M3onFPGAXilnxArtix-7XC7A100T
");
MyUartPrintf("SystemCoreClock=%ld
",SystemCoreClock);

while(1)
{
led_blink();
sw=XGpio_DiscreteRead(BASEADDR_LED,CHANNEL_SW);
MyUartPrintf("keystate=%d-%d-%d-%d
",sw>>3,sw>>2&1,sw>>1&1,sw&1);
}
}

实现的功能是,4颗LED每100ms闪烁一次,同时串口输出此时拨码开关的实时状态。

编译无误后,就可以进行程序下载了。

6.6 Flash编程算法生成

使用Jlink下载程序需要指定Flash编程算法,但是Keil自带的算法中并没有我们所需要的:

fdb87374-c4b7-11ed-bfe3-dac502259ad0.jpg下载算法

所以我们需要定制一份Flash编程算法,打开Keil安装目录下的ARMFlash文件夹,将_Template文件夹复制出一份,并命名为DS_CM3,

fdeeba2e-c4b7-11ed-bfe3-dac502259ad0.jpg复制模板

打开其中的Keil工程:

fe4b0a54-c4b7-11ed-bfe3-dac502259ad0.jpg下载算法

这个工程可以自己设置要编程的Flash起始地址、大小,擦除大小等。

FlashDev.c文件填入以下内容,和我们之前ITCM的配置保持一致,起始地址0x0,大小64K:

#include"..FlashOS.H"//FlashOSStructures

structFlashDeviceconstFlashDevice={
FLASH_DRV_VERS,//DriverVersion,donotmodify!
"MyCM3onFPGA",//DeviceName
ONCHIP,//DeviceType
0x00000000,//DeviceStartAddress
0x00010000,//修改为64KB
1024,//ProgrammingPageSize
0,//Reserved,mustbe0
0xFF,//InitialContentofErasedMemory
100,//ProgramPageTimeout100mSec
3000,//EraseSectorTimeout3000mSec

//SpecifySizeandAddressofSectors
0x010000,0x000000,//只有一个扇区,起始地址为0
SECTOR_END
};

FlashPrg.c文件,实现一些存储区擦除的函数:


#include"..FlashOS.H"//FlashOSStructures
#include"string.h"

intInit(unsignedlongadr,unsignedlongclk,unsignedlongfnc){
return(0);//FinishedwithoutErrors
}

intUnInit(unsignedlongfnc){
return(0);//FinishedwithoutErrors
}

intEraseChip(void){
memset((unsignedchar*)0,0,0x10000);
return(0);//FinishedwithoutErrors
}

intEraseSector(unsignedlongadr){
memset((unsignedchar*)adr,0,1024);
return(0);//FinishedwithoutErrors
}

intProgramPage(unsignedlongadr,unsignedlongsz,unsignedchar*buf){
memcpy((unsignedchar*)adr,buf,sz);
return(0);//FinishedwithoutErrors
}

编译无误后,会在工程目录下生成一个FLM文件。
fe812792-c4b7-11ed-bfe3-dac502259ad0.jpg新生成的下载算法

将它复制到上一级目录:

fe971dfe-c4b7-11ed-bfe3-dac502259ad0.jpg新生成的下载算法

6.7 编译下载运行

再打开我们的ARM核Keil工程,添加DS_CM3 Flash编程算法:

fece7074-c4b7-11ed-bfe3-dac502259ad0.jpg添加Flash编程算法

点击下载按钮,把ARM程序下载到ARM核:

fee74bc6-c4b7-11ed-bfe3-dac502259ad0.jpg

可以看到LED每500ms闪烁一次,串口数据每1s输出一次,同时按下按键,串口输出按键的状态。

ff1b0eb6-c4b7-11ed-bfe3-dac502259ad0.jpg

和其他ARM内核芯片一样,也是支持在线调试的:

ff3a661c-c4b7-11ed-bfe3-dac502259ad0.jpg43

由于ARM程序是下载到Cortex-M3软核内的RAM存储区,所以掉电后程序会丢失。如何将程序下载到片外的SPI Flash中,我还没有成功实现。

审核编辑:汤梓红

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 微控制器
    +关注

    关注

    48

    文章

    6809

    浏览量

    147637
  • FPGA
    +关注

    关注

    1602

    文章

    21320

    浏览量

    593199
  • ARM
    ARM
    +关注

    关注

    134

    文章

    8651

    浏览量

    361815
  • 内核
    +关注

    关注

    3

    文章

    1309

    浏览量

    39846
  • STM32
    +关注

    关注

    2239

    文章

    10671

    浏览量

    348755

原文标题:用FPGA搭建一个STM32内核?

文章出处:【微信号:mcu168,微信公众号:硬件攻城狮】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    基于STM32U5 的 STM32CubeMX环境搭建

    基于STM32U5 的 STM32CubeMX环境搭建
    的头像 发表于 09-21 17:35 902次阅读
    基于<b class='flag-5'>STM32</b>U5 的 <b class='flag-5'>STM32</b>CubeMX环境<b class='flag-5'>搭建</b>

    Xilinx FPGA 搭建8051核

    网上能找到的资料都是altera的FPGA做的,有人用过xilinx FPGA搭建8051核吗?请与我联系
    发表于 06-03 14:59

    请问FPGAstm32串口通信位数比较大的数据如何用串口去传输

    就是在之前stm32作串口的时候直没有仔细去思考串口通信的过程,直到自己fpga试着去搭建
    发表于 05-10 02:40

    FPGA做的MCU内核的汇编指令集完全解析

    FPGA做的MCU内核的汇编指令集完全解析,FPGA使用VHDL编写MCU内核,使用PHP编写汇编器,使用vc studio编写FLASH
    发表于 03-04 18:53

    无法看到FPGA的spi内核

    嗨,我们在我们的项目中使用Artix7100t FPGA,我必须在这个FPGA中使用spi核心。在xilinx 14.7 coregen中,我无法看到该
    发表于 04-13 09:58

    在Altera系列fpga搭建cortex m3内核,添加摄像头外设的问题

    描述:在块Altera cyclone iv系列的fpga芯片上(友晶的DE2-115开发板),搭建cortex-M3软核,并把ov7
    发表于 04-19 23:17

    FPGA中有两XAUI内核可以互相连接吗?

    SFP,连接到Kintex-7评估板的HPC端口。现在基于上面的图像你可以指导我,我可以有下面的图像吗?这意味着我可以在FPGA中生成两XAUI和MAC
    发表于 07-22 14:00

    寻求FPGAstm32高速通讯的方案。

    寻求FPGAstm32高速通讯的方案。速度要求达到USB2.0速度。48m原设计通过。stm32+u***达到48m可是
    发表于 11-03 21:05

    如何自己搭建STM32编程IDE?

    编译器组成与编译流程是怎样的?如何自己搭建STM32编程IDE?
    发表于 11-29 06:20

    STM32(CM3内核) 内存映射简介

    这里写目录标题STM32(CM3内核) 内存映射.CM3内核简介二.CM3内核地址映射三.搭建
    发表于 02-11 07:48

    关于STM32F0讲座:内核

    STM32F0产品技术讲座:第一节 内核
    的头像 发表于 07-05 00:15 3705次阅读

    STM32 软件开发环境搭建

    STM32 软件开发环境搭建
    发表于 11-13 16:51 24次下载
    <b class='flag-5'>STM32</b> 软件开发环境<b class='flag-5'>搭建</b>

    使用 rust 开发 stm32:开发环境搭建

    使用 rust 开发 stm32:开发环境搭建
    发表于 11-18 19:36 51次下载
    使用 rust 开发 <b class='flag-5'>stm32</b>:开发环境<b class='flag-5'>搭建</b>

    STM32(CM3内核) 内存映射

    这里写目录标题STM32(CM3内核) 内存映射一.CM3内核简介二.CM3内核地址映射三.搭建代码,实现映射
    发表于 12-07 19:21 9次下载
    <b class='flag-5'>STM32</b>(CM3<b class='flag-5'>内核</b>) 内存映射

    STM32 搭建开发环境

    STM32 搭建开发环境
    发表于 12-08 14:36 19次下载
    <b class='flag-5'>STM32</b> <b class='flag-5'>搭建</b>开发环境