本文为《ARMCortex-M0全可编程SoC原理及实现面向处理器、协议、外设、编程和操作系统》一书的大体复现,由于版权问题,本文不附加该书资源,请自行搜索
其余相关资料:链接:https://pan.baidu.com/s/1eXJGQtEgLWh8gfwml0Rt8A
提取码:0nx9
在Vivado中新建工程,选择FPGA型号为xc7a75tffg484-1,一直点下一步即可
在主界面,点击左上方加号,添加源文件,在完成后添加要引入的20MHz时钟(以下内容转载自《ARMCortex-M0全可编程SoC原理及实现面向处理器、协议、外设、编程和操作系统》)
上述过程可能因为Vivado版本问题略有不同,但基本能够重复,故不赘述
完成后源文件管理如下
由于是完成后进行的文章撰写,一些内容与原书有差异,包括:原书中错误之处进行修改,为适应任务要求在UART相关模块中对连线进行了修改、原书中循序渐进的添加子模块的过程被跳过(建议有余力的朋友还是遵照原书一步一步搭建)
模块功能请自行翻看原书进行较好的理解,或对照代码注释进行理解,细讲内容过多,还请谅解
keil的具体下载配置方法这里给出原书的示例
这里我提供一下我的安装包,仅供参考
实验一中汇编文件忘保存了,被实验二文件覆盖了,这里仅从实验二开始展示汇编代码,实验仿真周期较长,有时需要适当测试时调节时钟周期,类似测试模式的思路,来快速确定结果正误,同时避免浪费资源
可以看到,当reset信号被触发后(即reset信号出现下降沿,中断响应跳转至reset_handler子模块,DCD为arm处理器汇编语言中模块跳转指令),在子模块中,在0x51000000处存入0x1A2B3C4D(此处地址选择0x51000000是根据书中相应的寄存器位置确定的,相关说明请看原书)
以下为仿真波形,an为位选择,如00000001,00000010,000001000等等,seg为此时对应的数码管输入
以下为输出译码
always @(*)
case (code) //a-b-c-d-e-f-g
4'b0000 : seg=7'b0000001; //0
4'b0001 : seg=7'b1001111; //1
4'b0010 : seg=7'b0010010; //2
4'b0011 : seg=7'b0000110; //3
4'b0100 : seg=7'b1001100; //4
4'b0101 : seg=7'b0100100; //5
4'b0110 : seg=7'b0100000; //6
4'b0111 : seg=7'b0001111; //7
4'b1000 : seg=7'b0000000; //8
4'b1001 : seg=7'b0000100; //9
4'b1010 : seg=7'b0001000; //A
4'b1011 : seg=7'b1100000; //B
4'b1100 : seg=7'b0110001; //C
4'b1101 : seg=7'b1000010; //D
4'b1110 : seg=7'b0110000; //E
4'b1111 : seg=7'b0111000; //F
default : seg=7'b1111111; //no display
endcase
翻看手册,查看需要设置的寄存器
根据实验要求,设置control:01(clk16)1(周期模式)1(使能)=0x07;设置load寄存器初值为(32’d5000):0x00001388。设计汇编代码main.s如文件夹中所示
关键代码如下:
Reset_Handler PROC
GLOBAL Reset_Handler
ENTRY
LDR R1, =0xE000E100 ;Interrupt Set Enable Register
LDR R0, =0x00000002
STR R0, [R1]
LDR R1, =0x50000000 ; Reset LED
LDR R0, =0x00000000
;MOVS R0,#0
;MOVS R0,#1
STR R0,[R1]
;Configure the timer
LDR R1, =0x52000000 ;timer load value register
;LDR R0, =0x0007FFFF ;=50,000,000 (system tick frequency)//0x02faf080
LDR R0, =0x00001388 ;=50,000,000 (system tick frequency)//0x02faf080
STR R0, [R1]
LDR R1, =0x52000008 ;timer control register
;MOVS R0, #0x03 ;prescaler=1, enable timer, reload mode
MOVS R0, #0x07 ;prescaler=1, enable timer, reload mode///changed
STR R0, [R1]
TIMER_Handler PROC
PUSH {R0,R1,LR}
;LDR R1, =0x5200000c ;clear timer
; MOVS R0, #0x01
;STR R0, [R1]
LDR R0, =0x50000000
LDR R1, =0x01
STR R1,[R0]
;ADDS R1,R1,#2 ; add 2
;STR R1,[R0] ; send to led
LDR R0, =0x0002FFFF
DCD LOOP
LDR R0, =0x50000000
LDR R1, =0x0
STR R1,[R0]
POP {R0,R1,PC}
ENDP
LOOP PROC
SUBS R0,R0,#1
BNE LOOP
ENDP
LOOP模块负责使LED持续发光一段时间,在初始化设定定时器加载值,周期模式后,可实现重复计时
主体部分包括在中断发生后添加了一个LOOP循环使LED0持续若干个周期发光。具体波形如下:
若干周期循环一次
LED0持续发光若干周期
定时功能
可以看到,实验三很好的完成了
为实现题目所要求的发送,串行传输、接收数据。此处将原代码进行如下修改,在UART模块中将数据的发送端与接收端直接相连(失去了原本的意义,此处仅为展示数据传输过程),将此串行传输线命名为RxTx。实现UART模块内部的数据传输。
关键汇编代码如下:
Reset_Handler PROC
GLOBAL Reset_Handler
ENTRY
LDR R1, =0x53000000
LDR R0, =0x01
STR R0, [R1]
LDR R1, =0x53000000
LDR R0, =0x02
STR R0, [R1]
LDR R1, =0x53000000
LDR R0, =0x04
STR R0, [R1]
LDR R1, =0x53000000
LDR R0, =0x08
STR R0, [R1]
LDR R1, =0x53000000
LDR R0, =0x10
STR R0, [R1]
LDR R1, =0x53000000
LDR R0, =0x20
STR R0, [R1]
LDR R1, =0x53000000
LDR R0, =0x40
STR R0, [R1]
LDR R1, =0x53000000
LDR R0, =0x80
STR R0, [R1]
可以看到,波形符合,实验成功
在vivado中运行布局布线(Implementation),查看运行结果如下
资源占用情况如图所示