Kraklog
GPIO , UART 본문
licenese가 없기 때문에 economy를 골라준다.
on chip memory를 올려주고 총 memory size를 바꿔준다.
배치 후 연결을 해준다.
연결을 해준 후인데 아직 에러가 4개가 남았다.
그 중 한가지는 adress가 겹쳐서 생기는 문제이다.
address를 재할당해주면 해결된다.
이 에러는 on chip memory가 연결되지 않아서 생기는 문제이다.
cpu의 reset vector와 exception vector를 on chip memory와 연결해준다.
slave는 data master에 연결해준다.
LED 등 입출력을 위해서는 pio가 필요하다.
8bit led를 출력하기 위해서 크기는 8로 설정해주었다.
led를 바꾸고 clock과 reset, s1을 연결해준다. 반드시 conduit을 설정해줘야 출력을 볼 수 있다.
이 때 에러가 발생할 수 있는데, 보통 address 에러이다. 재할당해준다.
led의 핀이 할당된것을 알 수 있다.
4bit 키 입력을 위해 pio를 할당해준다.
edge capture는 동작 특성상 falling edge에서, 인터럽트를 보기 위해서 설정해준다.
컴파일 완료 후
핀 플래너를 통해 핀을 설정해준다.
아니면 다른 방법으로 qsf 파일을 편집하는 방식이 있다.
개인적으론 qsf를 편집하는게 더 편한듯
선택해주어 사용하지 않는 led 불이 아예 들어오지 않게 설정해주었다.
설정 후 컴파일
sof 파일을 올려준다.
Nios II에 새로운 프로젝트로 my_gpio를 만들어준다.
실행해주면 console 창에 "Hello from Nios II!"가 출력되어진다.
led의 address가 0x9000 임을 확인하고
led 출력을 위한 코드를 작성해준다.
다시 run을 해주면 console 창에 Hello from Nios와 함께 LED가 출력된다.
Hello from Nios 대신에 다른 문구 등을 넣어서 기기의 문제가 없음을 출력해주면 일반적인 테스트 모듈로 생각해도 된다.
polling 방식으로 key 버튼 읽기
key의 address 는 0x0000
#include "sys/alt_stdio.h"
#include "unistd.h"
int main()
{
alt_putstr("Hello from Nios II!\n");
*(volatile unsigned int *) 0x9000 = 0xff;
unsigned int key_v;
/* Event loop never exits. */
while (1){
key_v = * (volatile unsigned int *) 0x000;
printf("key value = 0x%x\n",key_v);
usleep (80*10000);
}
return 0;
}
`timescale 1ns / 1ns
//`define APWM
`define gpio
module avalon_module (
input clk ,
input rst ,
input mp_waitR , //Avalon bus
input [31:0] mp_rData ,
output reg [31:0] mp_addr ,
output reg [ 3:0] mp_bEn ,
output reg mp_rD ,
output reg mp_wR ,
output reg [31:0] mp_wData
);
parameter FF = 1;
initial begin
mp_addr =32'hx; //unknown value
mp_bEn =4'bx;
mp_rD =1'b0;
mp_wR =1'b0;
//mp_waitR =;
//mp_rData =;
mp_wData =32'hx;
#200;
`ifdef APWM
avalon_write(32'd0,32'd10); //set period
avalon_write(32'd1,32'd7); //set duty
avalon_read(32'h0000);
avalon_read(32'h0001);
`elsif gpio
avalon_write(32'h2, 32'd1);
avalon_write(32'h3, 32'd1);
avalon_read(32'h0);
avalon_read(32'h2);
avalon_read(32'h3);
#400
avalon_read(32'h0);
`else
avalon_write(32'h1000,32'hAABBCCDD);
avalon_write(32'h1000,32'hDEADBEEF);
avalon_read(32'h1000);
avalon_read(32'h2000);
`endif
end
//avalon write (bus modeling)
task avalon_write;
input [31:0] wAddr;
input [31:0] wData;
begin
@(posedge clk);
#(FF); //step 1 delay
mp_addr = wAddr;
mp_bEn = 4'b1;
mp_wR = 1'b1 ;
mp_wData = wData ;
@(posedge clk);
while (mp_waitR) begin //mp_waitR == 0
@(posedge clk);
end
#(FF);
//initial value
mp_addr = 32'hx ;
mp_bEn = 4'bx ;
mp_wR = 1'b0 ;
mp_wData = 32'hx ;
end
endtask
task avalon_read;
input [31:0] rAddr;
begin
@(posedge clk);
#(FF); //step 1 delay
mp_addr = rAddr;
mp_bEn = 4'b1;
mp_rD = 1'b1 ;
@(posedge clk);
while (mp_waitR) begin //mp_waitR == 0
@(posedge clk);
end
#(FF);
$display("AV rAddr 0x%x, rData 0x%x", mp_addr, mp_rData);
//initial value
mp_addr = 32'hx ;
mp_bEn = 4'bx ;
mp_rD = 1'b0 ;
@(posedge clk);
end
endtask
endmodule
`define clk_50MHz 20
//`define regs
//`define pwms
`define gpio
module tb_avalon_module;
reg clk ;
reg rst ;
//Avalon bus
`ifdef regs
wire mp_waitR ;
wire [31:0] mp_rData ;
`elsif pwms
wire mp_waitR ;
wire [31:0] mp_rData ;
wire [07:0] pwm_out ;
`elsif gpio
wire mp_waitR ;
wire [31:0] mp_rData ;
reg in_port ;
wire irq ;
`else
reg mp_waitR ;
reg [31:0] mp_rData ;
`endif
wire [31:0] mp_wData ;
wire [31:0] mp_addr ;
wire [ 3:0] mp_bEn ;
wire mp_rD ;
wire mp_wR ;
avalon_module uAvalon_module (
.clk (clk ),
.rst (rst ),
.mp_waitR (mp_waitR),
.mp_rData (mp_rData),
.mp_addr (mp_addr ),
.mp_bEn (mp_bEn ),
.mp_rD (mp_rD ),
.mp_wR (mp_wR ),
.mp_wData (mp_wData)
);
`ifdef regs
my_reg uMy_reg (
.clk(clk) ,
.rst(rst) ,
//Avalon Bus
.addr (mp_addr ),
.bEn (mp_bEn ),
.rD (mp_rD ),
.wR (mp_wR ),
.waitR(mp_waitR),
.rData(mp_rData),
.wData(mp_wData)
);
`elsif pwms
avalon_pwm uAvalon_pwm_0 (
.clk (clk ),
.wr_data(mp_wData),
.wr_n (~mp_wR),
.addr (mp_addr[0]),
.clr_n (~rst),
.rd_data(mp_rData),
.pwm_out(pwm_out)
);
`elsif gpio
avalon_gpio uAvalon_gpio (
.clk (clk ),
.reset_n (~rst ),
.address (mp_addr[1:0] ),
.write_n (~mp_wR ),
.writedata (mp_wData ),
.readdata (mp_rData ),
.in_port (in_port ),
.irq (irq )
);
`else
`endif
initial fork
clk_gen;
rst_gen;
`ifdef regs
`elsif pwms
`elsif gpio
data_gen;
`else
data_gen;
`endif
join
task clk_gen;
begin
clk = 1'b0;
forever #(`clk_50MHz/2) clk = ~clk;
end
endtask
task rst_gen;
begin
rst =1'b0;
repeat(2) @(posedge clk);
rst =1'b1;
repeat(2) @(posedge clk);
rst =1'b0;
end
endtask
`ifdef regs
`elsif pwms
`elsif gpio
task data_gen;
begin
#75;
in_port = 1'h0;
#500;
in_port = 1'h1;
end
endtask
`else
task data_gen;
begin
#75;
mp_rData = 32'h11223344;
end
endtask
`endif
endmodule
edge capture , interrupt
- edge detcion을 하기 위해 F/F 2개 사용. (가장 효율적이다.)
interrupt에서 reduction operator를 사용해야하는데 비트가 길어진 경우 비트 중 하나라도 1이 있으면 interrupt를 발생시켜야 하기 때문이다.
edge_captire & int_mask가 1일때 irq가 발생하게 된다.
`define AVALON_ABUS_SIZE 2
`define AVALON_DBUS_SIZE 32
`define INPUT_BUS_SIZE 1
module my_avalon_gpio (
input clk ,
input reset_n ,
input [`AVALON_ABUS_SIZE-1:0] address ,
input write_n ,
input [`AVALON_DBUS_SIZE-1:0] writedata,
output [`AVALON_DBUS_SIZE-1:0] readdata ,
input [` INPUT_BUS_SIZE -1:0] in_port ,
output irq
);
//ADDR 0 : data in/out
//ADDR 1 : direction -> No
//ADDR 2 : interrupt mask
//ADDR 3 : edgecapture
//register => sequencial
reg [` INPUT_BUS_SIZE-1:0] data_in ;
reg [` INPUT_BUS_SIZE-1:0] int_mask ;
reg [` INPUT_BUS_SIZE-1:0] edge_cap ;
//2 Flip Flop
reg [` INPUT_BUS_SIZE-1:0] data_in_dly0;
reg [` INPUT_BUS_SIZE-1:0] data_in_dly1;
wire [` INPUT_BUS_SIZE-1:0] read_out ;
assign read_out = (address == 2) ? int_mask :
(address == 3) ? edge_cap :
data_in;
//data read
reg [`AVALON_DBUS_SIZE-1:0] reg_readdata;
always @(posedge clk, negedge reset_n) begin
if (!reset_n)
reg_readdata <= 0;
else
reg_readdata <= {`AVALON_DBUS_SIZE{1'b0}} | read_out;
end
assign readdata = reg_readdata;
//data write -> Use 3 register
//data_in
always @(posedge clk, negedge reset_n) begin
if (!reset_n)
data_in <= 0;
else
data_in <= in_port;
end
//interrupt mask -> CPU
wire int_mask_str = (!write_n && (address == 2));
always @(posedge clk, negedge reset_n) begin
if (!reset_n)
int_mask <= 0;
//else if (!write_n && (address == 2))
else if (int_mask_str)
int_mask <= writedata;
end
//data_in delay - Flip Flop
wire [` INPUT_BUS_SIZE-1:0] edge_det = data_in_dly0 & ~data_in_dly1;
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
//edgecapture
wire edge_cap_str = (!write_n && (address == 3));
always @(posedge clk, negedge reset_n) begin
if (!reset_n)
edge_cap <= 0;
else if (edge_cap_str)
edge_cap <= 0; //clear
else if (edge_det[0])
edge_cap[0] <= 1'b1; //On
end
//interrupt
assign irq = |(int_mask & edge_cap);
assign readdata = reg_readdata;
endmodule
UART
#include "sys/alt_stdio.h"
#include "unistd.h" //usleep을 사용하기 위함
#include "system.h"
#include "altera_avalon_uart_regs.h"
int main()
{
unsigned int state;
alt_putstr("Hello from Nios II!\n");
/* Event loop never exits. */
while (1) {
state = IORD_ALTERA_AVALON_UART_STATUS(UART_0_BASE);
while (!(state & 0x40)) { //0x40 = 6th bit
state = IORD_ALTERA_AVALON_UART_STATUS(UART_0_BASE);
}
IOWR_ALTERA_AVALON_UART_TXDATA(UART_0_BASE, 'A'); //write out data
usleep(1*1000*1000);
}
return 0;
}
A출력
#include "sys/alt_stdio.h"
#include "unistd.h"
#include "system.h"
#include "altera_avalon_uart_regs.h"
int main()
{
unsigned int state;
unsigned char c;
alt_putstr("Hello from Nios II!\n");
/* Event loop never exits. */
while (1) {
state = IORD_ALTERA_AVALON_UART_STATUS(UART_0_BASE);
while (!(state & 0x40)) { //0x40 = 6th bit
state = IORD_ALTERA_AVALON_UART_STATUS(UART_0_BASE);
}
IOWR_ALTERA_AVALON_UART_TXDATA(UART_0_BASE, 'A'); //write out data
usleep(1*400*1000);
if (state & 0x80) {
c = IORD_ALTERA_AVALON_UART_RXDATA(UART_0_BASE); //rrdy : 데이터를 읽을 준비가 되어있음.
alt_printf("RCV data = [%c 0x%x] \n" , c, c);
}
}
return 0;
}
Interrupt 를 통해 txdata 전송을 확인.
0x80은 7bit register를 가리키므로 7 register는 read data이고, 0x80엔는 데이터가 들어와있게 된ㄴ다.
따라서 ready에 있는 값을 인터럽트를 통해 출려 시킬 수 있다.
'[Harman] 하만 반도체 설계 > NiosII' 카테고리의 다른 글
IIC - bit bang (0) | 2024.01.03 |
---|---|
Avalon PWM, PWM Interrupt (0) | 2023.09.08 |
Avalon BUS + reg 설계 (0) | 2023.08.28 |
PWM / CRC (0) | 2023.08.28 |
Nios Processor (0) | 2023.07.28 |