2024.9.12 수업날
< btn_intc(myip) >
이번에는 버튼 인터럽트를 하는 IP를 만들어본다.
Block Diagram에서 microblaze를 더블클릭하여 endable exception을 체크하여 인터럽트로 처리하도록 한다.
microblaze를 automation으로 할 때 아래와 같이 인터럽트 부분에 체크한다.
그러면 Diagram에서 인터럽트 컨트롤러가 추가된다.
axi_gpio에서 더블클릭하여 Enable Interrupt를 체크한다.
microblaze_0_xlconcat에서 number of ports를 2로 설정한다.
다음으로 Diagram에서 axi_gpio의 하나 남은 출력단과 microblaze_0_xlconcat를 수동으로 연결해준다.
다음으로 Diagram에서 axi_uartlite의 하나 남은 출력단과 microblaze_0_xlconcat를 수동으로 연결해준다.
그리고 좌측의 Flow navigator에서 Generate Block Design을 누른 후 global을 선택하여 generate를 실행한다.
다음으로 wrapper 갱신하고, bitsteam을 실행한 후에 .xsa를 생성한다.
vitis 진행 순서
인터럽트를 활성화 시키면 플렛폼에 인터럽드 컨트롤러가 추가된다.
새로운 .xsa를 생성하였으니 이를 기반으로 한 platform을 만들고, 기존에 만들었던 btn_inc_app에서
mblaze_btn_intc_app.prj를 선택한 후 우측의 platform에서 점 3개를 클릭한다.
그리고 새롭게 만든 platform을 선택해주면 platform이 바뀐다.
굳이 app을 새롭게 만들 필요가 없다.
Mblaze_btn_intc -> helloworld.c 소스코드
#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xparameters.h"
#include "xgpio.h"
#include "xintc.h"
#include "xil_exception.h"
#include "xuartlite.h"
#define UART_ID XPAR_UARTLITE_0_DEVICE_ID
#define UART_VEC_ID XPAR_INTC_0_UARTLITE_0_VEC_ID
#define BTN_ID XPAR_GPIO_0_DEVICE_ID
#define BTN_CHANNEL 1
#define INCT_ID XPAR_MICROBLAZE_0_AXI_INTC_DEVICE_ID
#define BTN_VEC_ID XPAR_INTC_0_GPIO_0_VEC_ID
void BTN_ISR(void *CallBackRef);
void SendHandler(void *CallBackRef, unsigned int EventData);
void RecvHandler(void *CallBackRef, unsigned int EventData);
XGpio btn_instance;
XIntc intc_instance;
XUartLite uart_instance;
u32 btn_old_value;
int main()
{
init_platform();
print("Start!\n");
XUartLite_Initialize(&uart_instance, UART_ID);
XGpio_Config *cfg_ptr;
cfg_ptr = XGpio_LookupConfig(BTN_ID);
XGpio_CfgInitialize(&btn_instance, cfg_ptr, cfg_ptr->BaseAddress);
XGpio_SetDataDirection(&btn_instance, BTN_CHANNEL, 0b1111);
XIntc_Initialize(&intc_instance, INCT_ID);
XIntc_Connect(&intc_instance, BTN_VEC_ID, (XInterruptHandler)BTN_ISR, (void *)&btn_instance);
XIntc_Connect(&intc_instance, UART_VEC_ID,
(XInterruptHandler)XUartLite_InterruptHandler, (void *)&uart_instance);
XIntc_Enable(&intc_instance, BTN_VEC_ID);
XIntc_Enable(&intc_instance, UART_VEC_ID);
XIntc_Start(&intc_instance, XIN_REAL_MODE);
XGpio_InterruptEnable(&btn_instance, BTN_CHANNEL);
XGpio_InterruptGlobalEnable(&btn_instance);
Xil_ExceptionInit();
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
(Xil_ExceptionHandler)XIntc_InterruptHandler, &intc_instance);
Xil_ExceptionEnable();
XUartLite_SetRecvHandler(&uart_instance, RecvHandler, &uart_instance);
XUartLite_SetSendHandler(&uart_instance, SendHandler, &uart_instance);
XUartLite_EnableInterrupt(&uart_instance);
while(1){
// xil_printf("btn_value : %d\n\r", XGpio_DiscreteRead(&btn_instance, BTN_CHANNEL));
// print("Hello World!\n");
// MB_Sleep(1000);
}
cleanup_platform();
return 0;
}
void BTN_ISR(void *CallBackRef){
XGpio *Gpio_ptr = (XGpio *)CallBackRef;
if(XGpio_DiscreteRead(Gpio_ptr, BTN_CHANNEL)){
if(XGpio_DiscreteRead(Gpio_ptr, BTN_CHANNEL) == 0b0001) print("btn 0 pushed!\n\r");
else if(XGpio_DiscreteRead(Gpio_ptr, BTN_CHANNEL) == 0b0010) print("btn 1 pushed!\n\r");
else if(XGpio_DiscreteRead(Gpio_ptr, BTN_CHANNEL) == 0b0100) print("btn 2 pushed!\n\r");
else if(XGpio_DiscreteRead(Gpio_ptr, BTN_CHANNEL) == 0b1000) print("btn 3 pushed!\n\r");
}
else {
if(btn_old_value == 0b0001) print("btn 0 released!\n\r");
else if(btn_old_value == 0b0010) print("btn 1 released!\n\r");
else if(btn_old_value == 0b0100) print("btn 2 released!\n\r");
else if(btn_old_value == 0b1000) print("btn 3 released!\n\r");
}
// if(!XGpio_DiscreteRead(Gpio_ptr, BTN_CHANNEL)){ //btn0을 뗐을 때 인터럽트 활성화
// if(btn_old_value == 0b0001)
// print("GPIO interrupt\n\r");
// }
btn_old_value = XGpio_DiscreteRead(Gpio_ptr, BTN_CHANNEL);
// if(XGpio_DiscreteRead(Gpio_ptr, BTN_CHANNEL) & 0b0001){ //btn0을 눌렀을 때만 인터럽트 활성화
// print("Gpio interrupt\n\r");
// }
//XGpio_InterruptClear(&btn_instance, BTN_CHANNEL);
XGpio_InterruptClear(Gpio_ptr, BTN_CHANNEL);
return;
}
void SendHandler(void *CallBackRef, unsigned int EventData){
return;
}
void RecvHandler(void *CallBackRef, unsigned int EventData){
u8 rxData;
XUartLite_Recv(&uart_instance, &rxData, 1);
xil_printf("Recv %c\n\r", rxData);
return;
}
< iic(mychip) >
이번에는 I2C 통신을 사용하여 LCD에 글자를 띄우는 것을 해본다.
vivado 진행 순서
새로운 block design 생성
Diagram에서 iic를 검색해서 추가
Block Design에서 Sources의 micro_balze_iic_wrapper를 wrapper 하면 코드가 생기는데,
아래의 상자 부분을 .xdc에 추가해야한다.
Block Design의 .xdc 수정해야하는 부분
bitstream 실행하고 .xsa 생성
vitis 진행 순서
Mblaze_iic -> helloworld.c 소스코드(lcd 문자 띄우기)
#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xparameters.h"
#include "xiic.h"
#define IIC_ID XPAR_IIC_0_DEVICE_ID
#define DHT11_BASEADDR XPAR_MYIP_DHT11_0_S00_AXI_BASEADDR
#define LCD_RS 0
#define LCD_RW 1
#define LCD_E 2
#define LCD_BACKLIGHT 3
#define LCD_DEV_ADDR (0x27<<1) // address 0x27 beginning from bit 1, bit 0 is R/W_bar
#define COMMAND_DISPLAY_CLEAR 0x01
#define COMMAND_DISPLAY_ON 0x0C
#define COMMAND_DISPLAY_OFF 0x08
#define COMMAND_ENTRY_MODE 0x06
#define COMMAND_4BIT_MODE 0x28
static u8 I2C_LCD_Data;
XIic iic_instance;
void LCD_Data_4bit (u8 data);
void LCD_EnablePin();
void LCD_WriteCommand(uint8_t commandData);
void LCD_WriteData(uint8_t charData);
void LCD_Init();
void LCD_BackLightOn();
void LCD_GotoXY(uint8_t row, uint8_t col);
void LCD_WriteString(char *string);
int main()
{
init_platform();
u8 data_t[4] = {0,}; //0 -> backlight off
u8 tx_data = 0xff;
u8 cnt = 0;
print("Start!\n\r");
volatile unsigned int *dht11_instance = (volatile unsigned int) DHT11_BASEADDR;
XIic_Initialize(&iic_instance, IIC_ID);
// XIic_Send(iic_instance.BaseAddress, 0x27, data_t, 1, XIIC_STOP);
LCD_Init();
LCD_WriteString("Humidity : ??");
LCD_GotoXY(1, 0);
LCD_WriteString("Temperture : ??");
while(1){
// lcd
LCD_WriteData('a' + cnt++);
//XIic_Send(iic_instance.BaseAddress, 0x27, data_t, 1, XIIC_STOP);
print("Hello World!\n");
MB_Sleep(1000);
//XIic_Send(iic_instance.BaseAddress, 0x27, &tx_data, 1, XIIC_STOP);
MB_Sleep(1000);
}
cleanup_platform();
return 0;
}
void LCD_Data_4bit (u8 data)
{
I2C_LCD_Data = (I2C_LCD_Data & 0x0f) | (data & 0xf0); // put upper four bits
LCD_EnablePin();
I2C_LCD_Data = (I2C_LCD_Data & 0x0f) | ((data & 0x0f)<<4); // put lower four bits
LCD_EnablePin();
}
void LCD_EnablePin()
{
I2C_LCD_Data &= ~(1<<LCD_E);
XIic_Send(iic_instance.BaseAddress, 0x27, &I2C_LCD_Data, 1, XIIC_STOP);
I2C_LCD_Data |= (1<<LCD_E);
XIic_Send(iic_instance.BaseAddress, 0x27, &I2C_LCD_Data, 1, XIIC_STOP);
I2C_LCD_Data &= ~(1<<LCD_E);
XIic_Send(iic_instance.BaseAddress, 0x27, &I2C_LCD_Data, 1, XIIC_STOP);
MB_Sleep(2);
}
void LCD_WriteCommand(uint8_t commandData)
{
I2C_LCD_Data &= ~(1<<LCD_RS); // enter instruction code mode
I2C_LCD_Data &= ~(1<<LCD_RW); // enter write mode
LCD_Data_4bit(commandData); // output data
}
void LCD_WriteData(uint8_t charData)
{
I2C_LCD_Data |= (1<<LCD_RS); // enter data mode
I2C_LCD_Data &= ~(1<<LCD_RW); // enter write mode
LCD_Data_4bit(charData); // output data
}
void LCD_Init()
{
// see HD44780 datasheet page 45 for following init commands
MB_Sleep(20);
LCD_WriteCommand(0x03);
MB_Sleep(5);
LCD_WriteCommand(0x03);
MB_Sleep(1);
LCD_WriteCommand(0x03);
LCD_WriteCommand(0x02);
LCD_WriteCommand(COMMAND_4BIT_MODE);
LCD_WriteCommand(COMMAND_DISPLAY_OFF);
LCD_WriteCommand(COMMAND_DISPLAY_CLEAR);
LCD_WriteCommand(COMMAND_ENTRY_MODE);
LCD_WriteCommand(COMMAND_DISPLAY_ON);
LCD_BackLightOn();
}
void LCD_BackLightOn()
{
I2C_LCD_Data |= (1<<LCD_BACKLIGHT);
}
void LCD_GotoXY(uint8_t row, uint8_t col)
{
col %= 16; // column width is within 16
row %= 2; // row length is within 2
uint8_t address = (0x40 * row) + col; // see HD44780 datasheet page 12
uint8_t command = 0x80 + address;
LCD_WriteCommand(command);
}
void LCD_WriteString(char *string)
{
for (uint8_t i=0; string[i]; i++)
{
LCD_WriteData(string[i]);
}
}
btn_intc(myip), iic(myip) 끝!
'Harman 세미콘 아카데미 > SoC를 위한 Peripheral 설계' 카테고리의 다른 글
2024.9.12 [SoC를 위한 Peripheral 설계] 3상 교류 모터 드라이버 - CAN 통신 프로젝트 (0) | 2024.09.15 |
---|---|
2024.9.12 [SoC를 위한 Peripheral 설계]6 - dht11_lcd(myip) (1) | 2024.09.15 |
2024.9.11 [SoC를 위한 Peripheral 설계]4 - stopwatch_btn(myip), pwm_servo(myip) (0) | 2024.09.11 |
2024.9.10 [SoC를 위한 Peripheral 설계]3 - bcd_fnd, stopwatch(myip) (0) | 2024.09.10 |
2024.9.6 [SoC를 위한 Peripheral 설계]2 - led 제어2, fnd, fnd cntr(myip) (0) | 2024.09.06 |