前面的实验内容主要介绍了如何设置EMIO,并驱动LED和获取开关变量。本文的实验主要进行EMIO扩展,并驱动6个数码管的显示,数码管的位选排列D1-6,是从又往左排列的。
(1)数码管的内容可以是数字钟或自拟内容
(2)数码管的硬件连接如下图所示:
数码管的硬件介绍与FPGA管脚的对应关系:
(1)数码管的型号:LG3361BH;
(2)为共阳极数码管
(3)为了降低共阳端FPGA的电流,采用NDS336P MOS管进行驱动;由于MOS管是P沟道,因此FPGA管脚为低电平是导通,FPGA及软件编程时应注意。
(4)数码管的8段与FPGA之间经行1.5V到3.3V的电平转换,具体细节请参照FII-PE7030的原理图
数码管8段 与FPGA管脚的映射表
数码管(段) | a | b | c | d | e | f | g | p |
网络名称 | SEG_PA | SEG_PB | SEG_PC | SEG_PD | SEG_PE | SEG_PF | SEG_PG | SEG_DP |
FPGA -PIN | J10 | J9 | A7 | B7 | A8 | A9 | A10 | B10 |
数码管位选与FPGA管脚的映射表
数码管(位) | 1 | 2 | 3 | 4 | 5 | 6 |
网络名称 | SEG_D1 | SEG_D2 | SEG_D3 | SEG_D4 | SEG_D5 | SEG_D6 |
FPGA PIN | C1 | E3 | F7 | D6 | H11 | J11 |
数码管XDC的设置
(1)数码管段的XDC部分
#EGPIO_INOUT[8-15] used as segments selection
set_property PACKAGE_PIN J10 [get_ports EGPIO_INOUT[8]]
set_property IOSTANDARD LVCMOS15 [get_ports EGPIO_INOUT[8]]
set_property PACKAGE_PIN J9 [get_ports EGPIO_INOUT[9]]
set_property IOSTANDARD LVCMOS15 [get_ports EGPIO_INOUT[9]]
set_property PACKAGE_PIN A7 [get_ports EGPIO_INOUT[10]]
set_property IOSTANDARD LVCMOS15 [get_ports EGPIO_INOUT[10]]
set_property PACKAGE_PIN B7 [get_ports EGPIO_INOUT[11]]
set_property IOSTANDARD LVCMOS15 [get_ports EGPIO_INOUT[11]]
set_property PACKAGE_PIN A8 [get_ports EGPIO_INOUT[12]]
set_property IOSTANDARD LVCMOS15 [get_ports EGPIO_INOUT[12]]
set_property PACKAGE_PIN A9 [get_ports EGPIO_INOUT[13]]
set_property IOSTANDARD LVCMOS15 [get_ports EGPIO_INOUT[13]]
set_property PACKAGE_PIN A10 [get_ports EGPIO_INOUT[14]]
set_property IOSTANDARD LVCMOS15 [get_ports EGPIO_INOUT[14]]
set_property PACKAGE_PIN B10 [get_ports EGPIO_INOUT[15]]
set_property IOSTANDARD LVCMOS15 [get_ports EGPIO_INOUT[15]]
数码管位选XDC部分:
注意:位选的前两位在Bank33, 该Bank的IO电平为1.8V, 因此在XDC文件中IOSTANDARD 应设为LVCMOS18
这里仅列出新增部分
#1
set_property PACKAGE_PIN C1 [get_ports EGPIO_INOUT[16]]
set_property IOSTANDARD LVCMOS18 [get_ports EGPIO_INOUT[16]]
#2
set_property PACKAGE_PIN E3 [get_ports EGPIO_INOUT[17]]
set_property IOSTANDARD LVCMOS18 [get_ports EGPIO_INOUT[17]]
#3
set_property PACKAGE_PIN F7 [get_ports EGPIO_INOUT[18]]
set_property IOSTANDARD LVCMOS15 [get_ports EGPIO_INOUT[18]]
#4
set_property PACKAGE_PIN D6 [get_ports EGPIO_INOUT[19]]
set_property IOSTANDARD LVCMOS15 [get_ports EGPIO_INOUT[19]]
#5
set_property PACKAGE_PIN H11 [get_ports EGPIO_INOUT[20]]
set_property IOSTANDARD LVCMOS15 [get_ports EGPIO_INOUT[20]]
#6
set_property PACKAGE_PIN J11 [get_ports EGPIO_INOUT[21]]
set_property IOSTANDARD LVCMOS15 [get_ports EGPIO_INOUT[21]]
FPGA 程序更改:
顶层文件修改:
inout DDR_we_n,
// user added
inout [21:0]EGPIO_INOUT,
// user added
inout FIXED_IO_ddr_vrn,
顶层文件:
// user added
(*mark_debug=”true”*)wire [31:0] EGPIO_tri_o;
(*mark_debug=”true”*)wire [31:0] EGPIO_tri_i;
(*mark_debug=”true”*)wire [31:0] EGPIO_tri_t; //GPIO wire connection
-
- //扩展到22 EGPIO, 0-7 仍然用于LED
- //8-15 用作数码管显示
- //16-21 用于第几个数码管选择
genvar i;
generate
for (i=0;i<32;i=i+1) begin
assign EGPIO_INOUT=EGPIO_tri_t?1’bZ:EGPIO_tri_o; //GPIO as output wire connection
assign EGPIO_tri_i= EGPIO_INOUT; //GPIO as input wire connection
end
endgenerate
软件设计:
(1)设计任务:
将开关的输入以16进制的形式显示在数码管上:
1)读取开关量
2)7段数码管(7 segment digital tube) ,译码设计
3)位扫描
//8段共阳数码管译码程序(其中段8为小数点P):
int seven_seg(unsigned char x)
{int seg=0;
switch (x&0x0f) {
case 0: seg =0xc0; break; //1100,0000,0为亮,1为熄灭,0需要亮6个灯
case 1: seg=0xcf; break; //1100,1111,0为亮,1为熄灭,1需要亮2个灯
case 2: seg=0xa4; break; //解释同上
case 3: seg=0xb0; break;
case 4: seg=0x99; break;
case 5: seg=0x92; break;
case 6: seg =0x82; break;
case 7: seg =0xf8; break;
case 8: seg=0x80; break;
case 9: seg=0x90; break;
case 0x0a: seg=0x88; break;
case 0x0b: seg=0x83; break;
case 0x0c: seg=0xc6; break;
case 0x0d: seg=0xa1; break;
case 0x0e: seg=0x86; break;
case 0x0f: seg=0x8e; break;}
return seg;}
//GPIO 的组合,k 是传进来的开关量,//bit_sel是位选,高电平有效,led是和开
//关共享FPGA管脚的8个指示灯
void dis( unsigned char bit_sel,unsigned char k ,unsigned char led,XGpioPs *x)
{ unsigned int emio_out=0;
unsigned int tmp=0;
unsigned char tmp_k=0;
unsigned char seg=0;
seg=seven_seg(tmp_k); //显示数码管,0为亮,1为熄灭
tmp=~(bit_sel<<16); //bit_sel选择数码管,01表示数码管1,10表示数码管2,100表示数码管3,1000表示数码管4,10000表示数码管5,100000表示数码管6
tmp=0xff0000&tmp; //tmp表示数码管选择的地址,一次选择一个,从000001到100000
emio_out=(tmp)|(seg<<8)|(led); //led最右边8位,表示LED,seg<<8,表示数码管的显示数值,tmp
XGpioPs_Write(x, 2, emio_out); // bank 2的数值写入,低位8位为led,中间8位为seg数值,高6位为数码管选择
delay(2);
}
主程序流程:
0.设置数码管子程序
1.初始化GPIO口程序
2.初始化变量3
3.显示数码管,显示开关量(由7循环过来)
4.交叉显示奇偶数位LED
5.GPIO设为输入
6.读取开关的值
7.串口打印开关的值
8.循环到第3步
while(1)
{ unsigned int tmp_k=0;
XGpioPs_SetDirection(&psGpioInstancePtr,2, 0x3fffff); //GPIO设为输出 dis(0x01,k,led,&psGpioInstancePtr); //低四位开关量显示在第一个数码管
tmp_k=k>>4;
dis(0x02,tmp_k,led,&psGpioInstancePtr); //高四位开关量显示在第二个数码管
dis(0x04,0,led,&psGpioInstancePtr); //第三个数码管显示0
dis(0x8,0,led,&psGpioInstancePtr); //第四个数码管显示0
dis(0x10,0,led,&psGpioInstancePtr); //第五个数码管显示0
dis(0x20,0,led,&psGpioInstancePtr); //第六个数码管显示0
if(count>100){
count=0;
led=~led; //取反,奇数偶数led互换
XGpioPs_SetDirection(&psGpioInstancePtr,2, 0x3fff00); // GPIO设为输入
delay(1);
k=XGpioPs_Read(&psGpioInstancePtr, 2); //读取拨码开关的值
xil_printf(“switch value,k= %x\n\r”,k); //打印拨码开关的值
}
else
count++; }
总结:本实验介绍了EMIO的基本映射,FPGA接口设计,XDC的管脚约束,软件的驱动以及应用程序的设计等,这里只起到抛砖引玉的作用,只介绍基本的映射方法,用户也可以将MIO中的一部分映射到EMIO,如可以把网络的MAC接口映射到PL端与PL的千兆PHY相连,这里不再累述。