유저 인터페이스로 12분할 엔코더와 스위치를 달아놨는데 함 써먹어 봐야겠어.
엔코더는 A, B signal 외에 스위치 시그널도 있다. 푸쉬타입을 샀거등...
그 외 버튼이 두개가 있고 이걸 interface_Logic에 연결해서 입력신호 필터링을 한 후
인터럽트 신호와 무슨 신호인지 알려주는 데이터 신호가 출력된다.
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
entity Interface_Logic_v001 is
port
(
clk_in : in std_logic;
EN0_S : in std_logic;
EN0_A, EN0_B : in std_logic;
Key_01, Key_02 : in std_logic;
data : out std_logic_vector(2 downto 0);
intr : out std_logic
);
end entity;
architecture rtl of Interface_Logic_v001 is
signal data_signal : std_logic_vector(2 downto 0);
signal ff_EN0_A, ff_EN0_S, ff_Key_01, ff_Key_02 : std_logic_vector(1 downto 0);
signal rotary_in : std_logic_vector(1 downto 0);
signal rotary_q1, rotary_q2 : std_logic;
begin
process(clk_in)
variable clk_cnt_ENR, clk_cnt_ENL, clk_cnt : integer := 0;
variable phase : integer := 0;
begin
if(clk_in 'event and clk_in = '1') then
if(phase = 0) then
ff_EN0_A(0) <= rotary_q1;
ff_EN0_A(1) <= ff_EN0_A(0);
ff_EN0_S(0) <= EN0_S;
ff_EN0_S(1) <= ff_EN0_S(0);
ff_Key_01(0) <= Key_01;
ff_Key_01(1) <= ff_Key_01(0);
ff_Key_02(0) <= Key_02;
ff_Key_02(1) <= ff_Key_02(0);
if(ff_EN0_A(1) = '0' and ff_EN0_A(0) = '1') then
if(rotary_q2 = '0') then
data <= "000";
else
data <= "001";
end if;
phase := 1;
end if;
elsif(phase = 1) then
intr <= '1';
clk_cnt := clk_cnt + 1;
if(clk_cnt = 100) then
clk_cnt := 0;
intr <= '0';
phase := 0;
end if;
end if;
end if;
end process;
process(clk_in)
begin
if(clk_in 'event and clk_in = '1') then
rotary_in <= (not EN0_B) & (not EN0_A);
case rotary_in is
when "00" => rotary_q1 <= '0';
rotary_q2 <= rotary_q2;
when "01" => rotary_q1 <= rotary_q1;
rotary_q2 <= '0';
when "10" => rotary_q1 <= rotary_q1;
rotary_q2 <= '1';
when "11" => rotary_q1 <= '1';
rotary_q2 <= rotary_q2;
when others => rotary_q1 <= rotary_q1;
rotary_q2 <= rotary_q2;
end case;
end if;
end process;
end rtl;
인터페이스 로직은 일단 이렇다. 엔코더만 구현해 놓은 상태...
Syntax Highlighting을 어떻게 하는지 몰라서 보기 좀 불편하네.
엔코더를 오른쪽으로 돌리면 data 핀으로 "000"가 출력되고, 왼쪽으로 돌리면 "001"이 출력된다. 그리고 인터럽트 핀에서 한 펄스 날라간다. Nios II 에서는 이 인터럽트 시그널을 받아서 인터럽트 처리를 해주면 된다는 시나리온데...잘 되려나...
Qsys 띄워서 시작해보자.
현재 내 시스템은 이렇다. 인터럽트 입력용으로 사용할 PIO 하나 추가해보자.
이런식으로 설정했다. Rising Edge에 인터럽트가 발생하는 설정이라고 한건데...해봐야 알지 머
추가했다. 저장하고 제너레이션 해보자.
하드웨어 설정하고 만드는건 별 문제가 없는데...
정작 C 프로그래밍은 어떻게 해야되는지 간단명료하게 설명된 문서를 찾기가 너무 힘드네...
결국 Nios II Software Developer's Handbook에서 PIO Interrupt 관련 예제를 찾았다.
인터넷 뒤진다고 눈깔 빠지는줄 알았다.
우선 ISR 함수 만들고, PIO 인터럽트로 등록해주는 소스다.
소스 찾기 드럽게 힘드네...
이걸 베이스로 해서 일단 인터럽트가 발생하면 '.'을 찍어서 제대로 돌아가는지 확인해보자.
이렇게 해서 돌려봤다.
엔코더를 좌우로 돌리면 화면상에 ......이 출력된다.
흠,,, 되는거 같다.
여기에 좀 더 살을 붙여서 유저 인터페이스를 완성해야겠다.
PIO 인터럽트 하는김에 UART도 인터럽트 형태로 바꿀려고 했는데...
도저히 샘플 소스를 찾을 수가 없다...ㅠㅠ
나중에 한가해지면 핸드북 꼼꼼하게 읽어보면서 바꿀 생각이다.
오늘은 여기까지.
우선 ISR 함수 만들고, PIO 인터럽트로 등록해주는 소스다.
#include "system.h"
#include "altera_avalon_pio_regs.h"
#include "alt_types.h"
#ifdef ALT_ENHANCED_INTERRUPT_API_PRESENT
static void handle_button_interrupts(void* context)
#else
static void handle_button_interrupts(void* context, alt_u32 id)
#endif
{
/* Cast context to edge_capture's type. It is important that this
be declared volatile to avoid unwanted compiler optimization. */
volatile int* edge_capture_ptr = (volatile int*) context;
/*
* Read the edge capture register on the button PIO.
* Store value.
*/
*edge_capture_ptr =
IORD_ALTERA_AVALON_PIO_EDGE_CAP(BUTTON_PIO_BASE);
/* Write to the edge capture register to reset it. */
IOWR_ALTERA_AVALON_PIO_EDGE_CAP(BUTTON_PIO_BASE, 0);
/* Read the PIO to delay ISR exit. This is done to prevent a
spurious interrupt in systems with high processor -> pio
latency and fast interrupts. */
IORD_ALTERA_AVALON_PIO_EDGE_CAP(BUTTON_PIO_BASE);
}
#include "sys/alt_irq.h"
#include "system.h"
...
/* Declare a global variable to hold the edge capture value. */
volatile int edge_capture;
...
/* Initialize the button_pio. */
static void init_button_pio()
{
/* Recast the edge_capture pointer to match the
alt_irq_register() function prototype. */
void* edge_capture_ptr = (void*) &edge_capture;
/* Enable all 4 button interrupts. */
IOWR_ALTERA_AVALON_PIO_IRQ_MASK(BUTTON_PIO_BASE, 0xf);
/* Reset the edge capture register. */
IOWR_ALTERA_AVALON_PIO_EDGE_CAP(BUTTON_PIO_BASE, 0x0);
/* Register the ISR. */
#ifdef ALT_ENHANCED_INTERRUPT_API_PRESENT
alt_ic_isr_register(BUTTON_PIO_IRQ_INTERRUPT_CONTROLLER_ID,
BUTTON_PIO_IRQ,
handle_button_interrupts,
edge_capture_ptr, 0x0);
#else
alt_irq_register( BUTTON_PIO_IRQ,
edge_capture_ptr,
handle_button_interrupts );
#endif
}
소스 찾기 드럽게 힘드네...
이걸 베이스로 해서 일단 인터럽트가 발생하면 '.'을 찍어서 제대로 돌아가는지 확인해보자.
static void handle_UI_interrupts(void* context){
volatile int* edge_capture_ptr = (volatile int*) context;
*edge_capture_ptr = IORD_ALTERA_AVALON_PIO_EDGE_CAP(PIO_3_BASE);
alt_putchar('.');
IOWR_ALTERA_AVALON_PIO_EDGE_CAP(PIO_3_BASE, 0);
IORD_ALTERA_AVALON_PIO_EDGE_CAP(PIO_3_BASE);
}
이렇게 해서 돌려봤다.
엔코더를 좌우로 돌리면 화면상에 ......이 출력된다.
흠,,, 되는거 같다.
여기에 좀 더 살을 붙여서 유저 인터페이스를 완성해야겠다.
PIO 인터럽트 하는김에 UART도 인터럽트 형태로 바꿀려고 했는데...
도저히 샘플 소스를 찾을 수가 없다...ㅠㅠ
나중에 한가해지면 핸드북 꼼꼼하게 읽어보면서 바꿀 생각이다.
오늘은 여기까지.
안녕하세요 FPGA 공부하는 대학생입니다. 공부하면서 궁금한점이 있어서 이렇게 질문드립니다. 현재 altera DE2 보드로 실습중인데 예제 프로그램중에 sd card audio player라는게 있어요. 이거해보면서 궁금한점이 들었는데요. 보드내에 eeprom이 있어서 쿼터스에서 hw셋팅한건 전원꺼도 저장이 되어있는데nios2로 fpga에 다운로드한 프로그램은 어떻게 eeprom에 저장이 불가능한가요?
답글삭제혹시 해결방법을 알고 계신다면 답변해주시면 감사하겠습니다. :)
안녕하세요.
답글삭제FPGA에 로직을 다운로드해서 구동시키는 방법은 크게 두가지 입니다.
1. FPGA내의 SRAM에 다운로드해서 구동
2. FPGA 외부의 컨피규레이션용 시리얼 롬에 다운로드해서 구동
1번으로 할 경우 리부팅시 SRAM의 데이터는 지워지니까 이전 데이터는 사라집니다.
2번으로 할 경우 리부팅시 FPGA에서 시리얼 롬의 로직을 읽어와서 구동을 시키므로 이전에 다운로드 해놓은 로직을 계속 쓸 수 있죠.
내용을 읽어보니까 FPGA 내부의 SRAM에 다운로드해서 동작을 시키신거 같습니다.
eeprom이 달려있다는데 EPCS/EPCQ 디바이스를 말씀하시는거 같네요. 이게 알테라의 컨피규레이션용 시리얼 롬입니다.
쿼터스에서 로직 합성이 끝나면 sof 파일이 생성됩니다. 이건 FPGA내의 SRAM에 바로 다운로드해서 구동할 수 있구요,
외부 시리얼 롬에 다운로드하고 싶으면
Convert Programming File 창을 띄워서 파일을 변환해줘야 합니다.
그 후 시리얼 롬에 다운해주면 전원을 껏다 켜도 계속 로직이 동작하게 되죠.
제가 제대로 답변을 한건지 모르겠군요.
그럼 수고하세요.