并行IO接口设计
1 实验目的
-
掌握GPIO IP核的工作原理和使用方法; -
掌握中断控制方式的IO接口设计原理; -
掌握中断程序设计方法; -
掌握IO接口程序控制方法。
2 实验任务与要求
- 并行IO要求:所有实验任务要求分别采用程序控制方式、普通中断方式、快速中断方式实现,中断方式时,GPIO输入、延时都采用中断实现。每位同学仅完成其中的一个任务,且需完成的实验任务编号与学号后三位模3的取值一致。
3 实验环境
- Vivado 2019.1
- Nexys4 DDR? FPGA Board
- Xilinx SDK
4 实验内容与步骤
4.1 设计思路
4.1.1 实现逻辑
? GPIO_2做中断源的中断服务程序读取SW15~0和button,根据button的状态选择输出模式,设置相应的段码,输出SW15~0的状态到七段数码管上,而七段数码管连续输出的基础就是TIMER作中断源的输出程序。
4.1.2 中断源
? 本次实验的中断源为GPIO_2和TIMER;
4.1.3 中断方式设计
? 采用按键中断和定时器中断,即中断源为所搭建硬件平台的GPIO_2和TIMER,在采用快速中断时,相比普通中断,要填中断向量寄存表,以及要设置MER寄存器的状态,但在中断服务程序中无需编写程序来清除INTC的中断请求,返回的ack信号为01时会将它清除,只须清除中断源GPIO_2的中断。
4.1.4 中断服务程序设计
- 对于中断源为GPIO_2的中断服务程序,主要功能为在通道一输出位码和在通道二输出此刻i所对应的段码,并且将位码右移一位,i加一,实现在人眼分辨不出来的极短时间内输出所有的数字到七段数码管上,每当i为8时,重置位码和i,并且在结束时清除TIMER的中断状态。即写中断状态寄存器;
- 对于中断源为TIMER的中断服务程序,主要功能为循环扫描,使显示器顺序点亮,显示相应的数字,并且由于选择速度很快,肉眼无法分辨,就认为时同时点亮了所有的数码管。
4.2 硬件电路
4.2.1 Nexys4 DDR开发板的外设
4.2.2 GPIO与外设的连接
- 本实验使用到了GPIO_0的SW7~0和LED7~0、GPIO_1的最右边一位数码管、GPIO_2的BTND、U、L、R、C。
4.2.3 并行IO中断系统
4.3 硬件平台
- 根据左东红老师的学习通视频,基于Vivado2019.1版本搭建了并行的IO中断系统。
4.4 软件流程图
4.5 设计源代码及注释
#include "xil_io.h"
#include "stdio.h"
#include "xgpio_l.h"
#include "xintc_l.h"
#include "xtmrctr_l.h"
#include "xio.h"
#include "xil_exception.h"
#define RESET_VALUE 100000
void Seg_TimerCounterHandler()__attribute__ ((fast_interrupt));
void BTN_sw_seg()__attribute__ ((fast_interrupt));
short segcode[8]={0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
char segtable[16]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};
short pos=0xff7f;
int i=0;
int main()
{
Xil_Out16(XPAR_AXI_GPIO_0_BASEADDR+XGPIO_TRI_OFFSET,0xffff);
Xil_Out8(XPAR_AXI_GPIO_1_BASEADDR+XGPIO_TRI_OFFSET,0x0);
Xil_Out8(XPAR_AXI_GPIO_1_BASEADDR+XGPIO_TRI2_OFFSET,0x0);
Xil_Out8(XPAR_AXI_GPIO_2_BASEADDR+XGPIO_TRI_OFFSET,0x1f);
Xil_Out32(XPAR_AXI_GPIO_2_BASEADDR+XGPIO_IER_OFFSET,XGPIO_IR_CH1_MASK);
Xil_Out32(XPAR_AXI_GPIO_2_BASEADDR+XGPIO_GIE_OFFSET,XGPIO_GIE_GINTR_ENABLE_MASK);
Xil_Out32(XPAR_AXI_TIMER_0_BASEADDR+XTC_TCSR_OFFSET,
Xil_In32(XPAR_AXI_TIMER_0_BASEADDR+XTC_TCSR_OFFSET)&~XTC_CSR_ENABLE_TMR_MASK);
Xil_Out32(XPAR_AXI_TIMER_0_BASEADDR+XTC_TLR_OFFSET,RESET_VALUE);
Xil_Out32(XPAR_AXI_TIMER_0_BASEADDR+XTC_TCSR_OFFSET,
Xil_In32(XPAR_AXI_TIMER_0_BASEADDR+XTC_TCSR_OFFSET)|XTC_CSR_LOAD_MASK);
Xil_Out32(XPAR_AXI_TIMER_0_BASEADDR+XTC_TCSR_OFFSET,(Xil_In32(XPAR_AXI_TIMER_0_BASEADDR+XTC_TCSR_OFFSET)&~XTC_CSR_LOAD_MASK)\
|XTC_CSR_ENABLE_TMR_MASK|XTC_CSR_AUTO_RELOAD_MASK|XTC_CSR_ENABLE_INT_MASK|XTC_CSR_DOWN_COUNT_MASK);
Xil_Out32(XPAR_AXI_INTC_0_BASEADDR+XIN_IAR_OFFSET,0x6);
Xil_Out32(XPAR_AXI_INTC_0_BASEADDR+XIN_IMR_OFFSET,0x6);
Xil_Out32(XPAR_AXI_INTC_0_BASEADDR+XIN_IER_OFFSET,XPAR_AXI_GPIO_2_IP2INTC_IRPT_MASK|XPAR_AXI_TIMER_0_INTERRUPT_MASK);
Xil_Out32(XPAR_AXI_INTC_0_BASEADDR+XIN_MER_OFFSET,XIN_INT_MASTER_ENABLE_MASK|XIN_INT_HARDWARE_ENABLE_MASK);
Xil_Out32(XPAR_AXI_INTC_0_BASEADDR+XIN_IVAR_OFFSET+0x4,(int)BTN_sw_seg);
Xil_Out32(XPAR_AXI_INTC_0_BASEADDR+XIN_IVAR_OFFSET+0x8,(int)Seg_TimerCounterHandler);
microblaze_enable_interrupts();
return 0;
}
void Seg_TimerCounterHandler()
{
Xil_Out8(XPAR_AXI_GPIO_1_BASEADDR+XGPIO_DATA_OFFSET,pos);
Xil_Out8(XPAR_AXI_GPIO_1_BASEADDR+XGPIO_DATA2_OFFSET,segcode[i]);
pos=pos>>1;
i++;
if(i==8)
{
i=0;
pos=0xff7f;
}
Xil_Out32(XPAR_AXI_TIMER_0_BASEADDR+XTC_TCSR_OFFSET,Xil_In32(XPAR_AXI_TIMER_0_BASEADDR+XTC_TCSR_OFFSET));
}
void BTN_sw_seg()
{
char button=Xil_In8(XPAR_AXI_GPIO_2_BASEADDR+XGPIO_DATA_OFFSET);
short cur_sw=Xil_In16(XPAR_AXI_GPIO_0_BASEADDR+XGPIO_DATA_OFFSET);
if(button==0x10)
{
for(int i=0;i<8;i++){
for(int n=0;n<8;n++){
segcode[7-n]=segtable[(cur_sw>>n)&0x1];
}
}
}
else if(button==0x02)
{
for(int i=0;i<4;i++){
for(int n=0;n<4;n++){
segcode[7-n]=segtable[(cur_sw>>(4*n))&0xf];
}
for(int n=4;n<8;n++){
segcode[7-n]=0xff;
}
}
}
else if((button==0x01))
{
int k=cur_sw;
for(int j=0;j<5;j++){
switch(k%10)
{
case(0):segcode[7-j]=segtable[0];break;
case(1):segcode[7-j]=segtable[1];break;
case(2):segcode[7-j]=segtable[2];break;
case(3):segcode[7-j]=segtable[3];break;
case(4):segcode[7-j]=segtable[4];break;
case(5):segcode[7-j]=segtable[5];break;
case(6):segcode[7-j]=segtable[6];break;
case(7):segcode[7-j]=segtable[7];break;
case(8):segcode[7-j]=segtable[8];break;
case(9):segcode[7-j]=segtable[9];break;
}
k/=10;
}
for(int n=5;n<8;n++){
segcode[7-n]=0xff;
}
}
Xil_Out32(XPAR_AXI_GPIO_2_BASEADDR+XGPIO_ISR_OFFSET,Xil_In32(XPAR_AXI_GPIO_2_BASEADDR+XGPIO_ISR_OFFSET));
}
#include "xil_io.h"
#include "stdio.h"
#include "xgpio_l.h"
#include "xintc_l.h"
#include "xtmrctr_l.h"
#define RESET_VALUE 100000
void Seg_TimerCounterHandler();
void BTN_sw_seg();
void My_ISR() __attribute__ ((interrupt_handler));
short segcode[8]={0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
char segtable[16]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};
short pos=0xff7f;
int i=0;
int main()
{
Xil_Out16(XPAR_AXI_GPIO_0_BASEADDR+XGPIO_TRI_OFFSET,0xffff);
Xil_Out8(XPAR_AXI_GPIO_1_BASEADDR+XGPIO_TRI_OFFSET,0x0);
Xil_Out8(XPAR_AXI_GPIO_1_BASEADDR+XGPIO_TRI2_OFFSET,0x0);
Xil_Out8(XPAR_AXI_GPIO_2_BASEADDR+XGPIO_TRI_OFFSET,0x1f);
Xil_Out32(XPAR_AXI_GPIO_2_BASEADDR+XGPIO_IER_OFFSET,XGPIO_IR_CH1_MASK);
Xil_Out32(XPAR_AXI_GPIO_2_BASEADDR+XGPIO_GIE_OFFSET,XGPIO_GIE_GINTR_ENABLE_MASK);
Xil_Out32(XPAR_AXI_TIMER_0_BASEADDR+XTC_TCSR_OFFSET,
Xil_In32(XPAR_AXI_TIMER_0_BASEADDR+XTC_TCSR_OFFSET)&~XTC_CSR_ENABLE_TMR_MASK);
Xil_Out32(XPAR_AXI_TIMER_0_BASEADDR+XTC_TLR_OFFSET,RESET_VALUE);
Xil_Out32(XPAR_AXI_TIMER_0_BASEADDR+XTC_TCSR_OFFSET,
Xil_In32(XPAR_AXI_TIMER_0_BASEADDR+XTC_TCSR_OFFSET)|XTC_CSR_LOAD_MASK);
Xil_Out32(XPAR_AXI_TIMER_0_BASEADDR+XTC_TCSR_OFFSET,(Xil_In32(XPAR_AXI_TIMER_0_BASEADDR+XTC_TCSR_OFFSET)&~XTC_CSR_LOAD_MASK)\
|XTC_CSR_ENABLE_TMR_MASK|XTC_CSR_AUTO_RELOAD_MASK|XTC_CSR_ENABLE_INT_MASK|XTC_CSR_DOWN_COUNT_MASK);
Xil_Out32(XPAR_AXI_INTC_0_BASEADDR+XIN_IAR_OFFSET,0x6);
Xil_Out32(XPAR_AXI_INTC_0_BASEADDR+XIN_IER_OFFSET,XPAR_AXI_GPIO_2_IP2INTC_IRPT_MASK|XPAR_AXI_TIMER_0_INTERRUPT_MASK);
Xil_Out32(XPAR_AXI_INTC_0_BASEADDR+XIN_MER_OFFSET,XIN_INT_MASTER_ENABLE_MASK|XIN_INT_HARDWARE_ENABLE_MASK);
microblaze_enable_interrupts();
return 0;
}
void My_ISR()
{
int status;
status=Xil_In32(XPAR_AXI_INTC_0_BASEADDR+XIN_ISR_OFFSET);
if((status&XPAR_AXI_TIMER_0_INTERRUPT_MASK)==XPAR_AXI_TIMER_0_INTERRUPT_MASK)
{
Seg_TimerCounterHandler();
}
else if((status&XPAR_AXI_GPIO_2_IP2INTC_IRPT_MASK)==XPAR_AXI_GPIO_2_IP2INTC_IRPT_MASK)
{
BTN_sw_seg();
}
Xil_Out32(XPAR_AXI_INTC_0_BASEADDR+XIN_IAR_OFFSET,status);
}
void Seg_TimerCounterHandler()
{
Xil_Out8(XPAR_AXI_GPIO_1_BASEADDR+XGPIO_DATA_OFFSET,pos);
Xil_Out8(XPAR_AXI_GPIO_1_BASEADDR+XGPIO_DATA2_OFFSET,segcode[i]);
pos=pos>>1;
i++;
if(i==8)
{
i=0;
pos=0xff7f;
}
Xil_Out32(XPAR_AXI_TIMER_0_BASEADDR+XTC_TCSR_OFFSET,Xil_In32(XPAR_AXI_TIMER_0_BASEADDR+XTC_TCSR_OFFSET));
}
void BTN_sw_seg()
{
char button=Xil_In8(XPAR_AXI_GPIO_2_BASEADDR+XGPIO_DATA_OFFSET);
short cur_sw=Xil_In16(XPAR_AXI_GPIO_0_BASEADDR+XGPIO_DATA_OFFSET);
if(button==0x10)
{
for(int i=0;i<8;i++)
{
for(int n=0;n<8;n++){
segcode[7-n]=segtable[(cur_sw>>n)&0x1];
}
}
}
else if(button==0x02)
{
for(int i=0;i<4;i++){
for(int n=0;n<4;n++){
segcode[7-n]=segtable[(cur_sw>>(4*n))&0xf];
}
for(int n=4;n<8;n++){
segcode[7-n]=0xff;
}
}
}
else if((button==0x01))
{
int k=cur_sw;
for(int j=0;j<5;j++){
switch(k%10)
{
case(0):segcode[7-j]=segtable[0];break;
case(1):segcode[7-j]=segtable[1];break;
case(2):segcode[7-j]=segtable[2];break;
case(3):segcode[7-j]=segtable[3];break;
case(4):segcode[7-j]=segtable[4];break;
case(5):segcode[7-j]=segtable[5];break;
case(6):segcode[7-j]=segtable[6];break;
case(7):segcode[7-j]=segtable[7];break;
case(8):segcode[7-j]=segtable[8];break;
case(9):segcode[7-j]=segtable[9];break;
}
k/=10;
}
for(int n=5;n<8;n++){
segcode[7-n]=0xff;
}
}
Xil_Out32(XPAR_AXI_GPIO_2_BASEADDR+XGPIO_ISR_OFFSET,Xil_In32(XPAR_AXI_GPIO_2_BASEADDR+XGPIO_ISR_OFFSET));
}
4.5 下载及功能验证
? 在经过调试和修改代码后,下载到实验FPGA上,能够实现要求的功能,验收,功能验证图片如下:
5 实验心得、体会
? 深入学习了硬件平台的搭建,中断的原理,在SDK上以c语言实现各种中断的功能以及GPIO,TIMER等的具体功能。
|