割込み
割込みを使ったTimer処理を試用した。
以下の動画で手順が紹介されている。
https://www.youtube.com/watch?v=gaZ1kRJzCok&list=PL_MJualihC5CAtnZHphK-hli8aSL3PRRz&index=39
Vivadoでの処理
- IPリストからZynqを追加
- IPリストからGPIOを追加
- Run Connection Automationからaxi_gpio_0 > S_AXIを選択
- Clock: Auto
- Run Connection Automationからaxi_gpio_0 > GPIOを選択
- Select Board Part Interface: leds_4bitsを選択
- IPリストからAXI Timerを追加
- Run Connection Automationからaxi_timer_0 > S_AXIを選択
- Clock: Auto
- ZynqのIPをダブルクリック > Interruptsのページに移動
- Fabric Interruptsをチェック
- IRQ_F2P[15:0]をチェック
- axi_timer_0のinterruptとZYNQのIRQ_F2Pを接続
- Validate Designでエラーがないか確認
- Sources > Design Sources > design_XXXにて右クリックしてCreate HDL Wrapperを選択
- Let Vivado manage wrapper and auto-update
- Generate Bitstream
作成したものをXSDKにExportして、XSDKを起動する。
XSDKでの処理
- New -> Application Project
- Project name: Timer_LED
- Hello Worldテンプレートで作成
- helloworld.cを編集 (後述)
- Program FPGA実行
- helloworldを実行
基板上のLED(写真左下のスイッチの上にある4つのLED)が点灯していく動作が確認できた。
code
上記のリンクのビデオを見ながら写経した。
helloworld.c
# include <stdio.h>
# include "platform.h"
# include "xparameters.h"
# include "xgpio.h"
# include "xtmrctr.h"
# include "xscugic.h"
# include "xil_exception.h"
# include "xil_printf.h"
// Parameter definitions
# define INTC_DEVICE_ID XPAR_PS7_SCUGIC_0_DEVICE_ID
# define TMR_DEVICE_ID XPAR_TMRCTR_0_DEVICE_ID
# define LEDS_DEVICE_ID XPAR_AXI_GPIO_0_DEVICE_ID
# define INTC_TMR_INTERRUPT_ID XPAR_FABRIC_AXI_TIMER_0_INTERRUPT_INTR
# define TMR_LOAD 0xF8000000
XGpio LEDInst;
XScuGic INTCInst;
XTmrCtr TMRInst;
static int led_data;
static int tmr_count;
// -------- function prototypes
static void TMR_Intr_Handler(void *baseaddr_p);
static int IntcInitFunction(u16 DeviceId, XTmrCtr *TmrInstancePtr);
void TMR_Intr_Handler(void *data)
{
if (XTmrCtr_IsExpired(&TMRInst, 0)) {
if (tmr_count == 3) {
XTmrCtr_Stop(&TMRInst, 0);
tmr_count = 0;
led_data++;
XGpio_DiscreteWrite(&LEDInst, 1, led_data);
XTmrCtr_Reset(&TMRInst, 0);
XTmrCtr_Start(&TMRInst, 0);
} else {
tmr_count++;
}
}
}
int InterruptSystemSetup(XScuGic *XScuGicInstancePtr)
{
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
(Xil_ExceptionHandler) XScuGic_InterruptHandler,
XScuGicInstancePtr);
Xil_ExceptionEnable();
return XST_SUCCESS;
}
int IntcInitFunction(u16 DeviceId, XTmrCtr *TmrInstancePtr)
{
XScuGic_Config *IntcConfig;
int status;
// Interrupt controller initialization
IntcConfig = XScuGic_LookupConfig(DeviceId);
status = XScuGic_CfgInitialize(&INTCInst, IntcConfig,
IntcConfig->CpuBaseAddress);
if (status != XST_SUCCESS) {
return XST_FAILURE;
}
// Call to interupt setup
status = InterruptSystemSetup(&INTCInst);
if (status != XST_SUCCESS) {
return XST_FAILURE;
}
// Connect timer interrupt to handler
status = XScuGic_Connect(&INTCInst, INTC_TMR_INTERRUPT_ID,
(Xil_ExceptionHandler) TMR_Intr_Handler, (void *) TmrInstancePtr);
if (status != XST_SUCCESS) {
return XST_FAILURE;
}
// Enable timer interrupt in the controller
XScuGic_Enable(&INTCInst, INTC_TMR_INTERRUPT_ID);
return XST_SUCCESS;
}
int main()
{
init_platform();
led_data = 0;
int status;
// Init GPIO
status = XGpio_Initialize(&LEDInst, LEDS_DEVICE_ID);
if (status != XST_SUCCESS) {
return XST_FAILURE;
}
XGpio_SetDataDirection(&LEDInst, 1, 0x00);
// Init GIC
status = IntcInitFunction(INTC_DEVICE_ID, &TMRInst);
if (status != XST_SUCCESS) {
return XST_FAILURE;
}
// Setup Timer
status = XTmrCtr_Initialize(&TMRInst, TMR_DEVICE_ID);
if (status != XST_SUCCESS) {
return XST_FAILURE;
}
XTmrCtr_SetHandler(&TMRInst, (XTmrCtr_Handler) TMR_Intr_Handler, &TMRInst);
XTmrCtr_SetResetValue(&TMRInst, 0, TMR_LOAD);
XTmrCtr_SetOptions(&TMRInst, 0,
XTC_INT_MODE_OPTION | XTC_AUTO_RELOAD_OPTION);
XTmrCtr_Start(&TMRInst, 0);
while(1)
;
}