Zybo > Interrupt > AXI Timer > LEDを点灯する処理



## 割込み

割込みを使ったTimer処理を試用した。

以下の動画で手順が紹介されている。
https://www.youtube.com/watch?v=gaZ1kRJzCok&list=PL_MJualihC5CAtnZHphK-hli8aSL3PRRz&index=39

## Vivadoでの処理

1. IPリストからZynqを追加
2. IPリストからGPIOを追加
3. Run Connection Automationからaxi_gpio_0 > S_AXIを選択
  - Clock: Auto
4. Run Connection Automationからaxi_gpio_0 > GPIOを選択
  - Select Board Part Interface: leds_4bitsを選択
5. IPリストからAXI Timerを追加
6. Run Connection Automationからaxi_timer_0 > S_AXIを選択
  - Clock: Auto
7. ZynqのIPをダブルクリック > Interruptsのページに移動
8. Fabric Interruptsをチェック
  - IRQ_F2P[15:0]をチェック
9. axi_timer_0のinterruptとZYNQのIRQ_F2Pを接続
10. Validate Designでエラーがないか確認
11. Sources > Design Sources > design_XXXにて右クリックしてCreate HDL Wrapperを選択
  - Let Vivado manage wrapper and auto-update
12. Generate Bitstream

作成したものをXSDKにExportして、XSDKを起動する。


## XSDKでの処理

1. New -> Application Project
   - Project name: Timer_LED
   - Hello Worldテンプレートで作成
2. helloworld.cを編集 (後述)
3. Program FPGA実行
4. helloworldを実行

基板上のLED(写真左下のスイッチの上にある4つのLED)が点灯していく動作が確認できた。

![DSC_0169.JPG](https://qiita-image-store.s3.amazonaws.com/0/32870/70ab10d6-da11-bde4-c398-d0c94f40a6c3.jpeg)


## 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)
    	;
}
```