FPGA
[FPGA] AVR+FPGA+LCD Shift register 설계
썽우디
2021. 11. 12. 19:29
Editor : Vivado 2020.2
FPGA Board : Cmod A7-35t (xc7a35tcpg236-1)
AVR Board : ATmega128A
LCD : HD44780U (Dot Matrix Liquid Crystal Display Controller)
[ 요구사항 ]
1. LCD 에 "Hello FPGA!" 출력
2. LCD 는 SPI통신 -> Interfacing to a 4bit MPU
3. FPGA -> shift register module 설계
참고) 74HC595 datasheet
1. 구조 다이어그램
2. Shift register
[ Timing Sequence ]
< Sequence 설명 >
1) SS -> Low 일때만 data 저장
2) MOSI -> data 1bit 단위로 shift_clk 발생시에 SHIFT REGISTER에 data 저장 ( data : 11001010 )
3) SS -> High 일때 SHIFT REGISTER 에 저장된 값을 STORAGE REGISTER에 저장
[ Logic Diagram ]
[ Vivado CODE ]
`timescale 1ns / 1ps
module shift_register(
input i_mosi,
input i_shift_clk,
input i_ss,
output [7:0] o_data
);
reg [7:0] r_data = 0;
reg [7:0] t_data = 0;
assign o_data = t_data;
always @(posedge i_shift_clk ) begin
if(i_shift_clk) begin
r_data <= {r_data[6:0], i_mosi};
end
end
always @(posedge i_ss) begin
if(i_ss) begin
t_data <= r_data;
end
end
endmodule
3. LCD
[ Timing Sequence ]
< Sequence 설명 >
1) RS -> HIGH 이면 LCD 액정에 글자(data)를 출력, LOW 이면 register에 data 저장. 즉, HIGH 설정
2) RW -> LCD 액정에 출력하기 위해 Write 동작. 즉, LOW 설정
3) E -> data 동기화 신호
4) DB7 -> data line
[ AVR CODE ]
#include "lcd_4bit.h"
uint8_t lcdData = 0;
void slaveSelect(uint8_t state)
{
if (state == LOW)
{
LCD_SS_PORT &= ~(1<<LCD_SS);
}
else
{
LCD_SS_PORT |= (1<<LCD_SS);
}
}
void shiftClock()
{
LCD_SHIFT_CLK_PORT |= (1<<LCD_SHIFT_CLK);
LCD_SHIFT_CLK_PORT &= ~(1<<LCD_SHIFT_CLK);
}
void LCD_Data(uint8_t data)
{
//LCD_DATA_PORT = data; // 8bit 데이터 전송
// 8bit serial 전송, msb부터 전송
// 0b11001010
//i_ss핀을 low 만든다.
slaveSelect(LOW);
for (int i=0; i<8; i++)
{
if (data & (0x80>>i)) LCD_MOSI_PORT |= (1<<LCD_MOSI);
else LCD_MOSI_PORT &= ~(1<<LCD_MOSI);
shiftClock();
}
//i_ss핀을 high 만든다.
slaveSelect(HIGH);
}
void LCD_Data4bit(uint8_t data)
{
lcdData = (lcdData & 0x0f) | (data & 0xf0); // 상위 4bit 출력
LCD_EnablePin();
lcdData = (lcdData & 0x0f) | ((data & 0x0f) << 4); // 하위 4bit 출력
LCD_EnablePin();
}
void LCD_Data4bitInit(uint8_t data)
{
lcdData = (lcdData & 0x0f) | (data & 0xf0); // 상위 4bit 출력
LCD_EnablePin();
}
void LCD_WriteMode()
{
lcdData &= ~(1<<LCD_RW);
}
void LCD_EnablePin()
{
lcdData &= ~(1<<LCD_E);
LCD_Data(lcdData);
lcdData |= (1<<LCD_E);
LCD_Data(lcdData);
lcdData &= ~(1<<LCD_E);
LCD_Data(lcdData);
_delay_us(1600);
}
void LCD_WriteCommand(uint8_t commadData)
{
lcdData &= ~(1<<LCD_RS);
LCD_WriteMode();
LCD_Data4bit(commadData);
}
void LCD_WriteCommandInit(uint8_t commadData)
{
lcdData &= ~(1<<LCD_RS);
LCD_WriteMode();
LCD_Data4bitInit(commadData);
}
void LCD_WriteData(uint8_t charData)
{
lcdData |= (1<<LCD_RS);
LCD_WriteMode();
LCD_Data4bit(charData);
}
[ LCD Initializing ]
[ AVR CODE ]
void LCD_Init()
{
LCD_DATA_DDR = 0xff;
LCD_RS_DDR |= (1<<LCD_RS);
LCD_RW_DDR |= (1<<LCD_RW);
LCD_E_DDR |= (1<<LCD_E);
LCD_SHIFT_CLK_DDR |= (1<<LCD_SHIFT_CLK);
LCD_MOSI_DDR |= (1<<LCD_MOSI);
LCD_SS_DDR |= (1<<LCD_SS);
_delay_ms(20);
LCD_WriteCommand(0x03);
_delay_ms(5);
LCD_WriteCommand(0x03);
_delay_ms(1);
LCD_WriteCommand(0x03);
LCD_WriteCommand(0x02);
LCD_WriteCommand(COMMAND_4_BIT_MODE);
LCD_WriteCommand(COMMAND_DISPLAY_OFF);
LCD_WriteCommand(COMMAND_DISPLAY_CLEAR);
LCD_WriteCommand(COMMAND_ENTRY_MODE);
LCD_WriteCommand(COMMAND_DISPLAY_ON);
}
4. 동작영상 및 사진