10月6日更新,添加含有串口工程,串口调试有问题的可以参照文章最后的补充内容和工程对照参考。
工程路径:链接:https://pan.baidu.com/s/16LTiR0PZQ721LPCrrQw6kw 提取码:xbgm
SF1开发环境搭建
一、SF1芯片介绍
SF1 系列器件集成了 RISCV MCU, 为用户产品开发和快速应用提供一种集 FPGA、 MCU 功能于一体的高性能、 低功耗的解决方案。
SF1 系列 RISC-V MCU 模块有以下特性:
1) 支持 RV32IMCA 指令集;
2) 三级流水设计, 主频最大 160MHz;
3) 支持机器模式和用户模式, 支持 PMP(Physical Memory Protection);
4) 快速的中断响应;
5) 拥有 8KB Icache, 8KB Dcache 和 8KB 的 DLM ( Data Local Memory) ;
6) 包含通用外设 QSPI,I2C,UART,GPIO;
7) 通过 AHB 总线访问 FPGA 逻辑;
8) 支持功能丰富的软件开发调试环境;
SF1 是集成了三级流水线的 RISC-V MCU 内核以及包含有 5824 LUTs 的 FPGA。 RISC-V MCU 的 APB与 DSC, DSI 等硬核模块通过硬线直连, 用户可以通过 MCU 其进行初始化配置。 RISC-V MCU 预留 AHB端口, 可通过 AHB 总线访问 FPGA 用户逻辑, 也可访问 PSRAM 等存储单元。 此外, 在 SF1 RISC-V MCU所有 IO 都与 FPGA 相连, 因此, MCU 系统时钟、 中断、 调试等接口, 需通过用户配置 FPGA 来实现。 当MCU 处于 Bypass Mode 时(关闭 MCU Enable), DSC/DSI 的模块也可以通过用户逻辑的 APB master 来配置, 此时 MCU 不能工作。架构框图如下:
开发板如图:
接下来我们通过设计流水灯样例来说明整个工程设计的流程。
二、构建SOC
安装工具包中的TD软件,版本号5.6.1_59063。打开TD工具。
1)、创建工程
点击Project——>New Project.
填写工程名称、存放路径、选择芯片为SF1;SF1S60CG121I。
2)、创建MCU IP
点击Tools->IP Generator。选择Create an IP Core。
填写IP的名称,选择Device 为 SF1;SF1S60CG121I。
选择Micro-Controller——>SF1 RISCV。
打开MCU的IP配置界面。按图中配置MCU。详细配置说明在下面使用时再介绍。
点击OK,完成MCU的配置工作。
3)、设计GPIO接口电路
在创建MCU IP的时候可以选中GPIO Enable来使能GPIO,在使能后会发现MCU的端口会多出三个GPIO相关端口。
该端口与FPGA的物理端口连接需要一个控制电路,通过gpio0_dir来控制物理端口和gpio0_in还是gpio0_out相连接。需要设计电路步骤如下。
选择Compile Order标签栏添加源码,在空白处鼠标右击,选择New Source。编写Verilog代码。
填写文件名,勾选添加到工程。文件类型根据自己的需求选择,这里选择的是Verilog。
填写代码如下:
module gpio_controler (
output wire O_gpio_in,
input wire I_gpio_dir, ///1'b0: input , 1'b1: output
input wire I_gpio_out,
inout wire IO_gpio
);
assign IO_gpio = I_gpio_dir ? I_gpio_out : 1'bz;
assign O_gpio_in = IO_gpio;
endmodule
这段代码是控制MCU的GPIO口与FPGA的端口连接。其中IO_gpio就是FPGA的物理端口。O_gpio_in、I_gpio_dir、I_gpio_out是MCU的gpio的相关端口,分别是输入,方向控制和输出口。生成的电路如下图。当dir为1时,端口输出gpio_out的值:
当dir为0时,gpio为输入,端口输入到gpio_in中,而原来的out路径为高阻状态,不会输入到out中。
其实不难发现当gpio作为输出时,我们也可以通过in通路读会gpio的输出值。
4)、构建SOC
接下来使用生成的MCU和gpio_controler构建SOC,选择Compile Order标签栏添加源码,在空白处鼠标右击,选择New Source。编写Verilog代码。填写文件名为SF1_SOC。
代码如下:
module SF1_SOC(
input wire I_clk,
input wire I_rst,
input wire I_timer_clk,
input wire I_jtag_tck,
output wire O_jtag_tdo,
input wire I_jtag_tms,
input wire I_jtag_tdi,
input wire I_uart_rx,
output wire O_uart_tx,
inout wire IO_gpio_0,
inout wire IO_gpio_1,
inout wire IO_gpio_2
);
wire S_gpio0_out;
wire S_gpio0_dir;
wire S_gpio0_in ;
wire S_gpio1_out;
wire S_gpio1_dir;
wire S_gpio1_in ;
wire S_gpio2_out;
wire S_gpio2_dir;
wire S_gpio2_in ;
gpio_controler u0_gpio_controler(
.O_gpio_in ( S_gpio0_in ),
.I_gpio_dir ( S_gpio0_dir ),
.I_gpio_out ( S_gpio0_out ),
.IO_gpio ( IO_gpio_0 )
);
gpio_controler u1_gpio_controler(
.O_gpio_in ( S_gpio1_in ),
.I_gpio_dir ( S_gpio1_dir ),
.I_gpio_out ( S_gpio1_out ),
.IO_gpio ( IO_gpio_1 )
);
gpio_controler u2_gpio_controler(
.O_gpio_in ( S_gpio2_in ),
.I_gpio_dir ( S_gpio2_dir ),
.I_gpio_out ( S_gpio2_out ),
.IO_gpio ( IO_gpio_2 )
);
SF1_MCU u_SF1_MCU(
.core_clk ( I_clk ),
.timer_clk ( I_timer_clk ),
.core_reset ( I_rst ),
.jtag_tck ( I_jtag_tck ),
.jtag_tdo ( O_jtag_tdo ),
.jtag_tms ( I_jtag_tms ),
.jtag_tdi ( I_jtag_tdi ),
.soft_ip_apbm_en ( 1'b0 ),
.qspi0cfg1_mode ( 1'b1 ),
.qspi0cfg2_mode ( 1'b1 ),
.uart_tx ( I_uart_tx ),
.uart_rx ( O_uart_rx ),
.gpio0_out ( S_gpio0_out ),
.gpio0_dir ( S_gpio0_dir ),
.gpio0_in ( S_gpio0_in ),
.gpio1_out ( S_gpio1_out ),
.gpio1_dir ( S_gpio1_dir ),
.gpio1_in ( S_gpio1_in ),
.gpio2_out ( S_gpio2_out ),
.gpio2_dir ( S_gpio2_dir ),
.gpio2_in ( S_gpio2_in ),
.htrans ( ),
.hwrite ( ),
.haddr ( ),
.hsize ( ),
.hburst ( ),
.hprot ( ),
.hmastlock ( ),
.hwdata ( ),
.hclk ( ),
.hrdata ( ),
.hresp ( ),
.hready ( ),
.i2c_sda_out ( ),
.i2c_sda_sel ( ),
.i2c_scl_out ( ),
.i2c_scl_sel ( ),
.i2c_sda_in ( ),
.i2c_scl_in ( ),
.nmi ( ),
.clic_irq ( ),
.sysrstreq ( ),
.apb_clk_down ( ),
.apb_paddr_down ( ),
.apb_penable_down ( ),
.apb_pprot_down ( ),
.apb_prdata_down ( ),
.apb_pready_down ( ),
.apb_pslverr_down ( ),
.apb_pstrobe_down ( ),
.apb_pwdata_down ( ),
.apb_pwrite_down ( ),
.apb_psel0_down ( ),
.apb_psel1_down ( ),
.apb_psel2_down ( )
);
endmodule
三、创建顶层设计
1)、添加时钟
SF1内置的RISC-V可以工作在最高160MHz,开发板上板载的时钟是25MHz,那么需要PLL的IP获得比25MHz更高的频率提供给RISC-V这个MCU工作,本次例程设计提供100MHz给RISC-V内核。与创建MCU IP类似,点击Tools->IP Generator。选择Create an IP Core。填写IP的名称为PLL。选择PLL IP,如下图
2)、构建顶层设计
选择Compile Order标签栏添加源码,在空白处鼠标右击,选择New Source。编写Verilog代码。填写文件名为TOP,编写代码如下。
代码如下:
module TOP(
input wire I_clk_25m,
input wire I_rst_n,
input wire I_jtag_tck,
output wire O_jtag_tdo,
input wire I_jtag_tms,
input wire I_jtag_tdi,
input wire I_uart_rx,
output wire O_uart_tx,
output wire O_led0,
output wire O_led1,
output wire O_led2
);
wire S_sys_clk_100m;
wire S_rst;
assign S_rst = ~I_rst_n; //开发板按键按下为低电平
pll u_pll(
.refclk ( I_clk_25m ),
.reset ( S_rst ),
.clk0_out ( S_sys_clk_100m )
);
SF1_SOC u_SF1_SOC(
.I_clk ( S_sys_clk_100m ),
.I_timer_clk ( I_clk_25m ),
.I_rst ( S_rst ),
.I_jtag_tck ( I_jtag_tck ),
.O_jtag_tdo ( O_jtag_tdo ),
.I_jtag_tms ( I_jtag_tms ),
.I_jtag_tdi ( I_jtag_tdi ),
.I_uart_rx ( I_uart_rx ),
.O_uart_tx ( O_uart_tx ),
.IO_gpio_0 ( O_led0 ),
.IO_gpio_1 ( O_led1 ),
.IO_gpio_2 ( O_led2 )
);
endmodule
设置TOP为顶层文件,方法如下
双击Read Design查看设计是否有语法等错误问题。
完成后图上的问好变为一个勾。
点击Optimize Gate 完成综合构建门电路。
四、配置管脚
顶层设计完成后需要将响应的管脚进行约束,即配置管脚。配置管脚有两种方式,一个是图形化配置,一个是直接编写管脚约束文件。下面以图形化配置方法来演示。在开始之前需要确认是否正确设置了顶层文件,是否综合完成了Gate电路。完成后选择Tools——>IO Constraint。
对应开发板的原理图将相应的管脚号填写好。
点击保存,文件名这里命名为pin.adc。打开文件里面就是管脚约束文件的格式。
五、生成bit文件
如果按步骤双击响应的综合。最后生成bit
在工程目录下phy_1中有生成的bit文件
生成的bit文件就是我们搭建好的SOC,接下来需要使用C语言对内核的RISC-V进行编程去实现流水灯的控制。
六、搭建RISC-V编程环境
将提供的开发环境FutureDynasty.7z文件解压缩到一个非中文目录下。<font color=#FF0000 >非中文目录!非中文目录!非中文目录!</font>重要的事情说三遍。双击FutureDynasty.exe可以打开软件。打开后首先设置工作空间目录,同样需要非中文路径。
1)、创建工程
选择File——>New——>Project...
选择C Project。点击Next。
2)、设置工程
1、配置编译工具链。第一次使用该工具时需要配置编译工具链。工具链在FutureDynasty目录下\toolchain\sf1\gcc\bin里面。将该路径进行配置。选择Project——>Properties。如图
2、配置调试器路径。在同一配置界面下,选择OpenOCD Path。该工具在FutureDynasty目录下\toolchain\sf1\openocd\bin,如下图
3、编译工程。点击编译,工程编译结束后在工程目录下Debug目录下生成HEX文件即为RISC-V执行程序。
七、下载代码
1)、连接开发板到PC
在套件里有两个下载器,其中一个在表面有AL-Link-mini字样的是FPGA下载器。
导线的一头有突出部分,朝向正面。。
另一端连接到开发板,在开发板的FGPA JTAG端口。
。
连接开发板的Type-C口连接线给开发板供电。
2)、下载代码
回到TD工具,选择下载工具。
添加下载文件。点击ADD,文件分别为TD工程生成的SOC的bit文件,RISC-V的运行程序HEX文件。
点击RUN等待一段时间就可以下载完成了。观察开发板现象我们会发现只有两个灯进行闪烁。那是因为代码需要修改。
如果修改代码重新生成HEX,再进行下载。由于下载需要一定时间,这样开发效率很低,在SOC创建完成后,调试RISC-V程序需要使用调试器在线调试代码,这样效率最高,调试结束后再进行下载,建议使用这样的调试方式。
八、调试RISC-V代码
1)、连接调试器
RISC-V的调试器在其正面有RV-Linke-AL标识,和FPGA 下载器类似,连接调试器突出部分朝向正面,另一端连接开发板的MCU JTAG。将RISC-V连接到PC机上后。在设备管理器里面多出两个设备。
接下来需要更新驱动,打开FutureDynasty目录下toolchain\softcore\openocd\drivers\UsbDriverTool里面的UsbDriverTool.exe,打开后,按图修改。
修改之后多了设备,如果表示驱动安装成功。
2)、设置调试参数
回到软件FutureDynasty,选择工程,鼠标右击,选择Debug As——>Debug Configurations
除此之外查看openopcd的路径和gdb的路径是否为FutureDynasty软件目录下。
点击Debug,进入调试界面。
观察代码我们发现源码只配置了两个LED,所以第三个led不会点亮,修改代码重新调试。在右上角选择如图回到代码编辑界面。
修改代码如下:
重新编译调试。观察开发板led流水灯现象。确认无误后就可以进行下载工作了,参看七、下载代码。
补充内容
1、主频设置
参照上面的设计设置MCU的主频为100MHz,那么在FutureDynasty工具新建的工程模板中需要修改工程中对于主频的定义项,打开新建的工程,在system_nuclei.c文件中修改SYSTEM_CLOCK的值为1000000000.
这样保证软件开发的主频设置和硬件设计的主频一致。
2、串口波特率设置
文中设计时没有添加串口,如果需要添加串口非常简单,只需要在创建MCU时勾选串口即可,在SOC和顶层将串口管脚引出即可,串口的对应管脚RX—>E4;TX—>A4;
为了串口能够正常工作在进行软件开发时首先要保证主频设置正确,因为主频SYSTEM_CLOCK的值决定了串口波特率的设置。此外需要修改工程SDK中的一个bug,打开文件nuclei_uart.c,如图。修改第16行代码如图显示,重新编译代码即可。
其中的misc_get_clock_divide()函数是获得当前内核主频的分频系数。