AXI TimerでPWMを使う


ポイントはXTC_CSR_ENABLE_PWM_MASKとXTC_CSR_EXT_GENERATE_MASKを入れてやること
(後者に気づかずにハマった)

PWMがONになる立ち上がりとOFFになる立ち下がりでハンドラが呼ばれる
どちらのエッジかを検出するステータスフラグを用意してやれば、COMPA_vectとOVF_vectのような割込ハンドラが実装できそう

#include <stdio.h>
#include "platform.h"
#include "xil_types.h"
#include "xtmrctr.h"
#include "xparameters.h"
#include "xil_io.h"
#include "xil_exception.h"
#include "xscugic.h"
#include <stdbool.h>

#define XTC_CSR_ENABLE_PWM_MASK		0x00000200
#define XTC_CSR_EXT_GENERATE_MASK	0x00000004

XScuGic InterruptController; /* Instance of the Interrupt Controller */
static XScuGic_Config *GicConfig;/* The configuration parameters of the controller */
void Timer_InterruptHandler(void *data, u8 TmrCtrNumber)
{
	print(" Interrupt acknowledged\n\r");
}
void Timer_InterruptHandler2(void *data, u8 TmrCtrNumber)
{
	print(" Interrupt 2 acknowledged\n\r");
}

int SetUpInterruptSystem(XScuGic *XScuGicInstancePtr)
{
	Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
			(Xil_ExceptionHandler) XScuGic_InterruptHandler,
			XScuGicInstancePtr);
	Xil_ExceptionEnable();
	return XST_SUCCESS;
}
int ScuGicInterrupt_Init(u16 DeviceId,XTmrCtr *TimerInstancePtr, XTmrCtr *TimerInstancePtr2)
{
	int Status;
	GicConfig = XScuGic_LookupConfig(DeviceId);
	if (NULL == GicConfig) {
		return XST_FAILURE;
	}
	Status = XScuGic_CfgInitialize(&InterruptController, GicConfig,
			GicConfig->CpuBaseAddress);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}
	Status = SetUpInterruptSystem(&InterruptController);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}
	Status = XScuGic_Connect(&InterruptController,
			61U,
			(Xil_ExceptionHandler)XTmrCtr_InterruptHandler,
			(void *)TimerInstancePtr);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	XScuGic_Enable(&InterruptController, 61U);
	return XST_SUCCESS;
}
int main()
{

	XTmrCtr TimerInstancePtr;
	XTmrCtr TimerInstancePtr2;
	int xStatus;

	print("##### Application Starts #####\n\r");
	print("\r\n");
	xStatus = XTmrCtr_Initialize(&TimerInstancePtr,XPAR_AXI_TIMER_0_DEVICE_ID);
	if(XST_SUCCESS != xStatus)
		print("TIMER INIT FAILED \n\r");
	xStatus = XTmrCtr_Initialize(&TimerInstancePtr2,XPAR_AXI_TIMER_0_DEVICE_ID);
	if(XST_SUCCESS != xStatus)
		print("TIMER INIT FAILED \n\r");

	XTmrCtr_SetHandler(&TimerInstancePtr,
			Timer_InterruptHandler,
			&TimerInstancePtr);

	XTmrCtr_SetHandler(&TimerInstancePtr2,
			Timer_InterruptHandler2,
			&TimerInstancePtr2);

	//enable interrupt & auto reload
	XTmrCtr_SetOptions(&TimerInstancePtr,
			0,
			(XTC_INT_MODE_OPTION | XTC_AUTO_RELOAD_OPTION | XTC_DOWN_COUNT_OPTION));

	u32 CounterControlReg = Xil_In32(TimerInstancePtr.BaseAddress + XTmrCtr_Offsets[0] + XTC_TCSR_OFFSET);
	CounterControlReg = CounterControlReg | XTC_CSR_ENABLE_PWM_MASK | XTC_CSR_EXT_GENERATE_MASK;
	Xil_Out32(TimerInstancePtr.BaseAddress + XTmrCtr_Offsets[0] + XTC_TCSR_OFFSET, CounterControlReg);

	XTmrCtr_SetOptions(&TimerInstancePtr2,
			1,
			(XTC_INT_MODE_OPTION | XTC_AUTO_RELOAD_OPTION | XTC_DOWN_COUNT_OPTION));

	CounterControlReg = Xil_In32(TimerInstancePtr2.BaseAddress + XTmrCtr_Offsets[1] + XTC_TCSR_OFFSET);
	CounterControlReg = CounterControlReg | XTC_CSR_ENABLE_PWM_MASK | XTC_CSR_EXT_GENERATE_MASK;
	Xil_Out32(TimerInstancePtr2.BaseAddress + XTmrCtr_Offsets[1] + XTC_TCSR_OFFSET, CounterControlReg);

	XTmrCtr_SetResetValue(&TimerInstancePtr,
			0, //Change with generic value
			0x5f5e100);
		XTmrCtr_SetResetValue(&TimerInstancePtr2,
				1, //Change with generic value
				0x1f78a40);

	xStatus=ScuGicInterrupt_Init(XPAR_PS7_SCUGIC_0_DEVICE_ID,&TimerInstancePtr,&TimerInstancePtr2);
	if(XST_SUCCESS != xStatus)
		print(" :( SCUGIC INIT FAILED \n\r");

	XTmrCtr_Start(&TimerInstancePtr,0);
	print("timer start \n\r");
	XTmrCtr_Start(&TimerInstancePtr2,1);
	print("timer 2 start \n\r");

	print("Wait for the Timer interrupt to tigger \r\n");
	print("########################################\r\n");
	print(" \r\n");

	while(1)
	{
	}
	cleanup_platform();
	return 0;
}