Development Environment.
Program : Quartus Prime 18.1 Lite Edition, Eclipse Mars.2 Release(4.5.2)
Tool : Modelsim 10.5b Starter Edition
FPGA : Cyclone V
Hardware Devices : De1-SoC Board.
Language : Verilog2001
Objective.
Design GPIO corresponding to commercial IP and generate interrupt signals.
Why?
GPIO는 General Purpose Input/Output의 약어로 마이크로 프로세서와 외부 디바이스 간의 통신을 위해 사용된다. 특정 목적을 위해 설계된 것이 아닌 사용자가 직접 입출력에 대한 신호를 임의로 지정하여 동작을 제어할 수 있도록 해준다. 입력으로 사용되는 경우는 외부 인터럽트를 처리할 수 있도록 하는 것이 일반적이다. Interrupt 동작을 포함한 GPIO를 설계하고 De1-SoC Board로 검증하여 GPIO와 Interrupt에 대한 이해를 넓히고자 한다.
Design Steps.
1. Block Diagram.
2. Verilog code with Avalon interface.
3. Modelsim Simulation.
4. verification with De1-SoC Board.
1. Block Diagram.
GPIO 내부의 data_in, interruptmask, edgecapture와 같은 레지스터들은 IP나 모듈에서 특정한 기능들을 수행하도록 설계되었다. PIO Regsiter Map을 참고하여 각 레지스터의 오프셋 및 기능을 확인할 수 있다.
2. Verilog Code with Avalon Interface.
`define AVALON_DBUS_SIZE 32
`define AVALON_ABUS_SIZE 2
`define INPUT_DBUS_SIZE 1
module custom_gpio_in (
input clk ,
input reset_n ,
input [`AVALON_ABUS_SIZE-1:0] address ,
input write_n ,
input [`AVALON_DBUS_SIZE-1:0] writedata ,
input [ `INPUT_DBUS_SIZE-1:0] in_port ,
output irq ,
output [`AVALON_DBUS_SIZE-1:0] readdata
);
reg [ `INPUT_DBUS_SIZE-1:0] data_in;
reg [ `INPUT_DBUS_SIZE-1:0] edge_cap;
reg [ `INPUT_DBUS_SIZE-1:0] int_mask;
reg [ `INPUT_DBUS_SIZE-1:0] data_in_dly0;
reg [ `INPUT_DBUS_SIZE-1:0] data_in_dly1;
wire [ `INPUT_DBUS_SIZE-1:0] read_out;
assign read_out = (address == 2) ? int_mask :
(address == 3) ? edge_cap :
data_in;
reg [`AVALON_DBUS_SIZE-1:0] r_readdata;
always@(posedge clk, negedge reset_n) begin
if(!reset_n)
data_in <= 0;
else
data_in <= in_port;
end
wire int_mask_str = ((address == 2) && !write_n);
always@(posedge clk, negedge reset_n) begin
if(!reset_n)
int_mask <= 0;
else if(int_mask_str)
int_mask <= writedata;
end
wire edge_det = ~data_in_dly1 & data_in_dly0;
always@(posedge clk, negedge reset_n) begin
if(!reset_n) begin
data_in_dly0 <= 0;
data_in_dly1 <= 0;
end else begin
data_in_dly0 <= in_port;
data_in_dly1 <= data_in_dly0;
end
end
wire edge_cap_str = ((address == 3) && !write_n);
always@(posedge clk, negedge reset_n) begin
if(!reset_n)
edge_cap <= 0;
else if(edge_cap_str)
edge_cap <= 0;
else if(edge_det)
edge_cap <= 1'b1;
end
always@(posedge clk, negedge reset_n) begin
if(!reset_n)
r_readdata <= 0;
else
r_readdata <= {`AVALON_DBUS_SIZE{1'b0}} | read_out;
end
assign readdata = r_readdata;
assign irq = |(int_mask & edge_cap);
endmodule
`timescale 1 ns / 1 ns
module Avalon_Model (
input clk ,
input reset ,
output reg [31:0] address ,
output reg [ 3:0] byteenable ,
output reg read ,
output reg write ,
input waitrequest ,
input [31:0] readdata ,
output reg [31:0] writedata
);
initial begin
address = 32'hx;
byteenable = 4'hx;
read = 1'b0;
write = 1'b0;
writedata = 32'hx;
repeat(3) @(posedge clk);
Avalon_Write(32'h0002, 32'h1);
Avalon_Write(32'h0003, 32'h1);
Avalon_Read(32'h0000);
Avalon_Read(32'h0002);
Avalon_Read(32'h0003);
end
task Avalon_Write;
input [31:0] w_address;
input [31:0] w_writedata;
begin
@(posedge clk);
#(FF);
address = w_address;
byteenable = 4'b0001;
write = 1'b1;
writedata = w_writedata;
@(posedge clk);
while(waitrequest)begin
@(posedge clk);
end
#(FF);
address = 32'hx;
byteenable = 4'bx;
write = 1'b0;
writedata = 32'hx;
end
endtask
task Avalon_Read;
input [31:0] r_address;
begin
@(posedge clk);
#(FF);
address = r_address;
byteenable = 4'b0001;
read = 1'b1;
@(posedge clk);
while(waitrequest)begin
@(posedge clk);
end
#(FF);
$display("addr = 0x%x, rdata = 0x%x \n", address, readdata);
address = 32'hx;
byteenable = 4'bx;
read = 1'b0;
end
endtask
endmodule
3. Modelsim Simulation.
`timescale 1 ns / 1 ns
module tb_Avalon_Model_gpio();
reg clk;
reg reset;
wire [31:0] address;
wire [ 3:0] byteenable;
wire read;
wire write;
wire [31:0] readdata;
wire waitrequest;
wire [31:0] writedata;
reg in_port;
wire irq;
Avalon_Model Avalon_Model_u0 (
.clk (clk ),
.reset (reset ),
.address (address ),
.byteenable (byteenable ),
.read (read ),
.write (write ),
.waitrequest(waitrequest),
.readdata (readdata ),
.writedata (writedata )
);
custom_gpio_in custom_gpio_in_u0 (
.clk (clk ),
.reset_n (!reset ),
.address (address[1:0] ),
.write_n (!write ),
.writedata(writedata ),
.in_port (in_port ),
.irq (irq ),
.readdata (readdata )
);
initial fork
clk_gen();
reset_gen();
data_gen();
join
task clk_gen;
begin
clk = 1'b0;
forever #10 clk = ~clk;
end
endtask
task reset_gen;
begin
reset = 1'b0;
repeat(2) @(posedge clk);
reset = 1'b1;
repeat(2) @(posedge clk);
reset = 1'b0;
end
endtask
task data_gen;
begin
#70;
in_port = 1'b0;
#220;
in_port = 1'b1;
end
endtask
endmodule
vlib work
vlog custom_gpio_in.v tb_Avalon_Model_gpio.v Avalon_Model.v
vsim work.tb_Avalon_Model_gpio
view wave
add wave -radix unsigned /clk
add wave -radix unsigned /reset
add wave -radix unsigned /address
add wave -radix unsigned /byteenable
add wave -radix unsigned /read
add wave -radix unsigned /write
add wave -radix unsigned /readdata
add wave -radix unsigned /writedata
add wave -radix unsigned /custom_gpio_in_u0/address
add wave -radix unsigned /custom_gpio_in_u0/write_n
add wave -radix unsigned /custom_gpio_in_u0/r_readdata
add wave -radix unsigned /custom_gpio_in_u0/in_port
add wave -radix unsigned /custom_gpio_in_u0/data_in
add wave -radix unsigned /custom_gpio_in_u0/data_in_dly0
add wave -radix unsigned /custom_gpio_in_u0/data_in_dly1
add wave -radix unsigned /custom_gpio_in_u0/edge_det
add wave -radix unsigned /custom_gpio_in_u0/int_mask
add wave -radix unsigned /custom_gpio_in_u0/int_mask_str
add wave -radix unsigned /custom_gpio_in_u0/edge_cap
add wave -radix unsigned /custom_gpio_in_u0/edge_cap_str
add wave -radix unsigned /custom_gpio_in_u0/irq
add wave -radix unsigned /custom_gpio_in_u0/int_mask
add wave -radix unsigned /custom_gpio_in_u0/edge_cap
add wave -radix unsigned /custom_gpio_in_u0/irq
run 600ns
4. Verification with De1-SoC Board & Eclipse.
1. Add Custom Component.
Top-level Module, Signal Type, Interface 설정에 주의
2. System Configuration.
Clk, CPU(Nios II Processor), Memory, JTAG(Debugging), My_gpio_0(Custom Component, GPIO)
Generate HDL > create sopcinfo, qip File.
3. Compilation.
1) 프로젝트에 qip File 추가하고 Platform Designer의 Instantation Template Copy 후 Analysis & Synthesis.
module custom_gpio (
input clk,
input reset_n,
input sw
);
niosII_system uNiosII_system_0 (
.clk_clk (clk ),
.custom_gpio_0_conduit_end_export (sw ),
.reset_reset_n (reset_n)
);
endmodule
2) Pin Planner Setting
3) Full Compilation.
4. Verification With Eclipse.
#include "sys/alt_stdio.h"
#include "altera_avalon_pio_regs.h" // copy
#include "unistd.h"
#include "system.h"
#include "sys/alt_irq.h"
#include "priv/alt_iic_isr_register.h"
void key_isr (void)
{
unsigned int k;
k = IORD_ALTERA_AVALON_PIO_EDGE_CAP(CUSTOM_GPIO_0_BASE); // input sw value
alt_printf("key_isr [0x%x] \n",k);
IOWR_ALTERA_AVALON_PIO_EDGE_CAP(CUSTOM_GPIO_0_BASE, 0x1); // clear
}
int main()
{
unsigned int switch_v;
alt_putstr("Hello from Nios II!\n");
*(volatile unsigned int *)0x9000 = 0xff;
IOWR_ALTERA_AVALON_PIO_EDGE_CAP(CUSTOM_GPIO_0_BASE, 0x1); // clear
alt_iic_isr_register(
CUSTOM_GPIO_0_IRQ_INTERRUPT_CONTROLLER_ID,
CUSTOM_GPIO_0_IRQ,
key_isr,
NULL,
NULL);
IOWR_ALTERA_AVALON_PIO_IRQ_MASK(CUSTOM_GPIO_0_BASE, 0x1); // masking
while (1){
switch_v = *(volatile unsigned int *)0x0;
printf("switch values = 0x%x \n", switch_v);
usleep(1*500*1000);
}
while(1);
return 0;
}
'Verilog Projects' 카테고리의 다른 글
Morse Code Generator. (0) | 2023.12.17 |
---|---|
Avalon Bus : PWM (0) | 2023.11.12 |
Avalon Bus Modeling. (1) | 2023.11.12 |
UART. (0) | 2023.11.08 |
8-Bit Multiplier. (0) | 2023.10.28 |