PIO(Parallel Input/Output)是SOPCBuilder里面一个最常用的IP之一,而且相对简单,容易上手使用。个人感觉PIO可类比于单片机的GPIO管 脚,用于用户自己定义的外设操作。一般来说,我们在SOPC系统中用PIO主要是因为方便,因为FPGA的管脚越来越多,内部逻辑资源越来越多,所以设计 时几乎不用担心管脚的数目或者逻辑资源是否不够;相比之下单片机的GPIO可能会让用户感到数目不够,有时不够方便。所以在SOPC系统我们可以同时用很 多使用PIO接口的设备。大体来说,这些设备主要分输入和输出两类:
输入类:按钮,自定义键盘等
输出类:LED,LCD定义接口连线等
标准件:如pwm步进电机等1ZA8v"a"L9X_$^
[attach]42[/attach](gw2O-C#f8R
如上图所示,在Nios/NiosII系统中,PIO接口IP可用于输入、输出、以及双向口三种类型。另外,SOPCBuilder中的PIO还支持中断 检测。不过中断检测及处理只在其作为输入设备时可用。如果是用PIO连接一个输出设备(例如LED),则系统自动禁止中断。L]C!L;F fTp8^3PNV
K@?J8q
这里只举一个button_pio(4位)作为输入接口的例子,如下图:
可以看到,作为输入接口时,另外两个标签项也可选,先看看第二个标签项(作输出接口时另外两个标签选项是自动禁止的):
]5zhw uDS%lZiQ
Edge Capture Register下面的三个选项是指捕获输入动作时是检测哪一种,用户可以选择只检测上升沿(Rising Edge),这样PIO内部的Edge Capture Register只在有上升沿动作时接收数据。同样道理,另外的两个选项一看便知。对于Button,我们一般倾向于选双向沿均可监测到数据变化。
下面的Interrupt选项是指用户选择以什么方式作为中断的输入,一种是电平变化产生中断,一种是沿的变化产生中断。第一种方式只有在输入由低电平变 化为高电平时才有效(不过用户可以根据需要,在做好的Nios模块外面的相应管脚上加上非门,使之由高电平变电平时生效);第二种方式只有当Edge Capture Register位是1(高电平)时才有用。d-T(XYxh
再来看一看第三个标签下面的东东: S9z}@p$L ~ZZ _'[4[
/]S3QRm&} C
这个标签下面的东西是用于仿真的。例如如果我们在测试输入设备时想给他一个激励,这里我用的是0x0001。什么意思呢?即表示最低位的button位为 高电平1。如果我用的激励数据是0x0003,这又是什么意思呢?聪明的你一定会发现这表示激励使低两位的button位为1,呵呵。9\+w(pu9F.G0Q
下面我们来分析一个SOPCBuilder生成的HDL文件: yv,eW1K;[ p3p
module led_pio (
//inputs:
address,i2dh'X {!{Z5I%?"sI
chipselect,+C,d9B2Y,r)YY
clk,mT?+B{
reset_n,!U*O:u%@v i"^
write_n,r GS'M?:s
writedata,
//outputs:
out_port
);
output [ 3: 0] out_port;
wire clk_en;
reg [ 3: 0] data_out;
wire [ 3: 0] out_port; EO,_%EOh]4K
assign clk_en = 1;
//s1, which is an e_avalon_slave
always @(posedge clk or negedge reset_n)begin N&vVFi$q(S |
if (reset_n == 0)
data_out <= 0;
else if (chipselect && ~write_n && (address = = 0))
data_out <= writedata[3 : 0];
end
assign out_port = data_out;
endmodule
你一定立刻注意到这段描述的输入端口怎么有点似曾相识?没错,avalon总线的要求就是这样!回忆一下在SOPCBuilder下加入用户自定义逻辑的 要求是不是必须得有这几个端口?呵呵。上面的代码并不难看懂,大家可以看到led_pio是如何被avalon总线驱动的。
关于PIO的软件编程,NiosII的IDE的样板工程里有很多程序可以参考,这里我就不赘述了,只是还想捎带介绍一下altera_avalon_pio_regs.h和另外一个细节。 V5n%_W!jM3g
这个头文件比较奇怪,它和其它设备的驱动文件独立开来,专门控制PIO设备。所以一定要记住在你对PIO外设进行编程时一定要包含这个头文件,否则会出错。 S"MG(r]ol{]5V
include
#define IOADDR_ALTERA_AVALON_PIO_DATA(base) __IO_CALC_ADDRESS_NATIVE(base, 0)
#define IORD_ALTERA_AVALON_PIO_DATA(base) IORD(base, 0) v3E#JA^al
#define IOWR_ALTERA_AVALON_PIO_DATA(base, data) IOWR(base, 0, data)
FQ(QHFC$}:c$P@
#define IOADDR_ALTERA_AVALON_PIO_DIRECTION(base) __IO_CALC_ADDRESS_NATIVE(base, 1)
#define IORD_ALTERA_AVALON_PIO_DIRECTION(base) IORD(base, 1)
#define IOWR_ALTERA_AVALON_PIO_DIRECTION(base, data) IOWR(base, 1, data)
#define IOADDR_ALTERA_AVALON_PIO_IRQ_MASK(base) __IO_CALC_ADDRESS_NATIVE(base, 2)
#define IORD_ALTERA_AVALON_PIO_IRQ_MASK(base) IORD(base, 2) 8f9oD)l1u9SB
#define IOWR_ALTERA_AVALON_PIO_IRQ_MASK(base, data) IOWR(base, 2, data)
#define IOADDR_ALTERA_AVALON_PIO_EDGE_CAP(base) __IO_CALC_ADDRESS_NATIVE(base, 3)
#define IORD_ALTERA_AVALON_PIO_EDGE_CAP(base) IORD(base, 3) WOtU5s|
#define IOWR_ALTERA_AVALON_PIO_EDGE_CAP(base, data) IOWR(base, 3, data)
可以看出,这里主要有DATA、DIRECTION、IRQ_MASK、EDGE_CAP几个寄存器或位的宏定义,而你可以从SOPCBuilder生成 的文件中找到相对应的硬件定义。这也说明了PIO实际上主要是由以上几个寄存器控制工作。因此,软件中只要对相应的寄存器针对基地址进行操作写入数据就可 以了。 $|"p
再来看看另一个值得注意的细节。我们可以从样板工程里发现类似于这样的语句:D
volatile int edge_capture_button;!m'Fd|x9?&f+p
#ifdef BUTTON_PIO_BASE_(}i*}?0o5Qh4oF
void handle_button_interrupts(void* context, alt_u32 id)
{(Nsj2~X D
volatile int* edge_capture_ptr = (volatile int*) context;?,@PrK(?Z
*edge_capture_ptr = IORD_ALTERA_AVALON_PIO_EDGE_CAP(BUTTON_PIO_BASE);
IOWR_ALTERA_AVALON_PIO_EDGE_CAP(BUTTON_PIO_BASE, 0);ia.~7OtD:nv S;i,f
}
void init_button_pio() P(h A(E'n o9]S
{{!DU7dEu
void* edge_capture_ptr = (void*) &edge_capture_button;ZQg NIV
IOWR_ALTERA_AVALON_PIO_IRQ_MASK(BUTTON_PIO_BASE, 0xf);
IOWR_ALTERA_AVALON_PIO_EDGE_CAP(BUTTON_PIO_BASE, 0x0);/m-v%M1rA;T^~!w{
alt_irq_register( BUTTON_PIO_IRQ, edge_capture_ptr, handle_button_interrupts ); 5BCv%?5t%IA
}
#endif
第一个函数是中断处理,这里暂不介绍。第二个函数是button的初始化函数。我们可以看到主要是三个步骤:将IRQ_MASK置为1(因为这个寄存器位 在相应的硬件文件里要取and操作),EDGE_CAP则置为0,因为此时并没有输入设备的沿状态发生变化,因此表示按钮尚未按下;第三步则是中断注册, 只要按照软件开发手册上说的去做就好了,不用在乎细节也是可以的,只要注册完毕,你的PIO外设就可以接收外部的输入啦,然后Nios会自动跳到相应的处 理程序。
2008年4月13日 星期日
NiosII PIO interrupt (轉貼)
標籤:
技術文章/NIOS2
訂閱:
張貼留言 (Atom)
沒有留言:
張貼留言