cancel
Showing results for 
Search instead for 
Did you mean: 
Highlighted
Adventurer
Adventurer
1,454 Views
Registered: ‎05-12-2017

Interrupts ignored on FreeRTOS (code works in standalone mode)

Jump to solution

I'm trying to port a code that worked in standalone mode to FreeRTOS but despite my attempts (googling, looking at the demo) I cannot figure out the interrupts. Strangely sometimes I just get an interrupt at the beginning of the run (before I even get to press any buttons).

 

	intcConfig = XScuGic_LookupConfig(XPAR_PS7_SCUGIC_0_DEVICE_ID);
	CHECKX(XScuGic_CfgInitialize(&intc, intcConfig, intcConfig->CpuBaseAddress));

	Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler)XScuGic_InterruptHandler, &intc);
	Xil_ExceptionEnable();

	struct btnsIntData btnIntData = { .btns = &btns, .queue = queue };
	CHECKX(XScuGic_Connect(&intc, XPAR_FABRIC_AXI_GPIO_BTNS_IP2INTC_IRPT_INTR, (Xil_ExceptionHandler)btnsIntHandler, &btnIntData));
	struct swsIntData swsIntData = { .sws = &sws, .queue = queue };
	CHECKX(XScuGic_Connect(&intc, XPAR_FABRIC_AXI_GPIO_SWS_IP2INTC_IRPT_INTR, (Xil_ExceptionHandler)swsIntHandler, &swsIntData));

	XGpio_InterruptEnable(&btns, XGPIO_IR_CH1_MASK);
	XGpio_InterruptEnable(&sws, XGPIO_IR_CH1_MASK);
	XGpio_InterruptGlobalEnable(&btns);
	XGpio_InterruptGlobalEnable(&sws);

	XScuGic_Enable(&intc, XPAR_FABRIC_AXI_GPIO_BTNS_IP2INTC_IRPT_INTR);
	XScuGic_Enable(&intc, XPAR_FABRIC_AXI_GPIO_SWS_IP2INTC_IRPT_INTR);

I attached full example below

0 Kudos
1 Solution

Accepted Solutions
Highlighted
Adventurer
Adventurer
1,980 Views
Registered: ‎05-12-2017

Re: Interrupts ignored on FreeRTOS (code works in standalone mode)

Jump to solution

Yes. The problem was double-initialization of the interrupt controller. I neither need nor can call XScuGic_CfgInitialize but I should use xInterruptController instead (external symbol) which is initialized in FreeRTOS_SetupTickInterrupt which in turn is called by vTaskStartScheduler.

 

I attached code below for anyone who will find this thread on Google:

#include <FreeRTOS.h>
#include <task.h>
#include <queue.h>
#include <xgpio.h>
#include <xscugic.h>
#include <xuartps.h>

static void checkX(int result, const char *call, const char *file, int line)
{
	if (result != XST_SUCCESS) {
		xil_printf("%s:%d: Call %s failed with error %d\n", file, line, call, result);
		for(;;);
	}
}

#define CHECKX(call) checkX(call, #call, __FILE__, __LINE__)

static void checkRTOS(BaseType_t result, const char *call, const char *file, int line)
{
	if (result != pdPASS) {
		xil_printf("%s:%d: Call %s failed with error %d\n", file, line, call, result);
		for(;;);
	}
}

#define CHECKRTOS(call) checkRTOS(call, #call, __FILE__, __LINE__)

struct updateVal {
	enum {
		UPDATE_BTNS,
		UPDATE_SWS
	} type;
	union {
		struct {
			int btns;
		} btns;
		struct {
			int sws;
		} sws;
	};
};



struct btnsIntData {
	XGpio *btns;
	QueueHandle_t queue;
};

static void btnsIntHandler(struct btnsIntData *data)
{
	struct updateVal update;
	update.type = UPDATE_BTNS;
	update.btns.btns = XGpio_DiscreteRead(data->btns, 1);
	xQueueSendFromISR(data->queue, &update, NULL);
	XGpio_InterruptClear(data->btns, XGPIO_IR_CH1_MASK);
}

struct swsIntData {
	XGpio *sws;
	QueueHandle_t queue;
};

static void swsIntHandler(struct swsIntData *data)
{
	struct updateVal update;
	update.type = UPDATE_SWS;
	update.sws.sws = XGpio_DiscreteRead(data->sws, 1);
	xQueueSendFromISR(data->queue, &update, NULL);
	XGpio_InterruptClear(data->sws, XGPIO_IR_CH1_MASK);
}

struct ledTaskData {
	XGpio *btns, *sws, *leds;
	QueueHandle_t queue;
};

static void updateLedsTask(struct ledTaskData *data)
{
	unsigned cnt = 0, mask = 0;

	extern XScuGic xInterruptController;

	struct btnsIntData btnIntData = { .btns = data->btns, .queue = data->queue };
	CHECKX(XScuGic_Connect(&xInterruptController, XPAR_FABRIC_AXI_GPIO_BTNS_IP2INTC_IRPT_INTR, (Xil_ExceptionHandler)btnsIntHandler, &btnIntData));
	struct swsIntData swsIntData = { .sws = data->sws, .queue = data->queue };
	CHECKX(XScuGic_Connect(&xInterruptController, XPAR_FABRIC_AXI_GPIO_SWS_IP2INTC_IRPT_INTR, (Xil_ExceptionHandler)swsIntHandler, &swsIntData));

	XGpio_InterruptEnable(data->btns, XGPIO_IR_CH1_MASK);
	XGpio_InterruptEnable(data->sws, XGPIO_IR_CH1_MASK);
	XGpio_InterruptGlobalEnable(data->btns);
	XGpio_InterruptGlobalEnable(data->sws);

	XScuGic_Enable(&xInterruptController, XPAR_FABRIC_AXI_GPIO_BTNS_IP2INTC_IRPT_INTR);
	XScuGic_Enable(&xInterruptController, XPAR_FABRIC_AXI_GPIO_SWS_IP2INTC_IRPT_INTR);

	struct updateVal update;
	update.type = UPDATE_SWS;
	update.sws.sws = XGpio_DiscreteRead(data->sws, 1);
	xQueueSend(data->queue, &update, 0);

	while (1) {
		struct updateVal update;
		if (xQueueReceive(data->queue, &update, portMAX_DELAY)) {
			switch (update.type) {
			case UPDATE_BTNS:
				cnt += update.btns.btns;
				break;
			case UPDATE_SWS:
				mask = update.sws.sws;
				break;
			default:
				xil_printf("%s:%d: Unexpected update type: %d\n", __FILE__, __LINE__, update.type);
				for (;;);
			}
			XGpio_DiscreteWrite(data->leds, 1, cnt ^ mask);
		}
	}
}

int main()
{
	const size_t QUEUE_SIZE = 16;

	XGpio btns, sws, leds;
	QueueHandle_t queue;

	queue = xQueueCreate(QUEUE_SIZE, sizeof(struct updateVal));
	struct ledTaskData ledTaskData = {
		.btns = &btns,
		.sws = &sws,
		.leds = &leds,
		.queue = queue
	};
	CHECKRTOS(xTaskCreate((TaskFunction_t)updateLedsTask, "updateLedsTask", (short)configMINIMAL_STACK_SIZE, &ledTaskData, (BaseType_t)2 | portPRIVILEGE_BIT, NULL));

	CHECKX(XGpio_Initialize(&btns, XPAR_AXI_GPIO_BTNS_DEVICE_ID));
	CHECKX(XGpio_Initialize(&sws, XPAR_AXI_GPIO_SWS_DEVICE_ID));
	CHECKX(XGpio_Initialize(&leds, XPAR_AXI_GPIO_LEDS_DEVICE_ID));

	XGpio_SetDataDirection(&btns, 1, 0xFF);
	XGpio_SetDataDirection(&sws, 1, 0xFF);
	XGpio_SetDataDirection(&leds, 1, 0x00);

	vTaskStartScheduler();
	for (;;);
}

View solution in original post

0 Kudos
5 Replies
Highlighted
Observer
Observer
1,428 Views
Registered: ‎04-26-2008

Re: Interrupts ignored on FreeRTOS (code works in standalone mode)

Jump to solution

Did you see the section on interrupt handling on this page: https://www.freertos.org/Using-FreeRTOS-on-Cortex-A-Embedded-Processors.html

 

Also there are several pre-configured examples you can use as references.  For examples https://www.freertos.org/RTOS-Xilinx-Zynq.html and https://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/TCPIP_FAT_Examples_Xilinx_Zynq.html - these examples use interrupts.

Regards,
Richard.

+ http://www.FreeRTOS.org
The de facto standard, downloaded every 4.2 minutes during 2015.

+ http://www.FreeRTOS.org/plus
IoT, Trace, Certification, TCP/IP, FAT FS, Training, and more...
0 Kudos
Highlighted
Adventurer
Adventurer
1,981 Views
Registered: ‎05-12-2017

Re: Interrupts ignored on FreeRTOS (code works in standalone mode)

Jump to solution

Yes. The problem was double-initialization of the interrupt controller. I neither need nor can call XScuGic_CfgInitialize but I should use xInterruptController instead (external symbol) which is initialized in FreeRTOS_SetupTickInterrupt which in turn is called by vTaskStartScheduler.

 

I attached code below for anyone who will find this thread on Google:

#include <FreeRTOS.h>
#include <task.h>
#include <queue.h>
#include <xgpio.h>
#include <xscugic.h>
#include <xuartps.h>

static void checkX(int result, const char *call, const char *file, int line)
{
	if (result != XST_SUCCESS) {
		xil_printf("%s:%d: Call %s failed with error %d\n", file, line, call, result);
		for(;;);
	}
}

#define CHECKX(call) checkX(call, #call, __FILE__, __LINE__)

static void checkRTOS(BaseType_t result, const char *call, const char *file, int line)
{
	if (result != pdPASS) {
		xil_printf("%s:%d: Call %s failed with error %d\n", file, line, call, result);
		for(;;);
	}
}

#define CHECKRTOS(call) checkRTOS(call, #call, __FILE__, __LINE__)

struct updateVal {
	enum {
		UPDATE_BTNS,
		UPDATE_SWS
	} type;
	union {
		struct {
			int btns;
		} btns;
		struct {
			int sws;
		} sws;
	};
};



struct btnsIntData {
	XGpio *btns;
	QueueHandle_t queue;
};

static void btnsIntHandler(struct btnsIntData *data)
{
	struct updateVal update;
	update.type = UPDATE_BTNS;
	update.btns.btns = XGpio_DiscreteRead(data->btns, 1);
	xQueueSendFromISR(data->queue, &update, NULL);
	XGpio_InterruptClear(data->btns, XGPIO_IR_CH1_MASK);
}

struct swsIntData {
	XGpio *sws;
	QueueHandle_t queue;
};

static void swsIntHandler(struct swsIntData *data)
{
	struct updateVal update;
	update.type = UPDATE_SWS;
	update.sws.sws = XGpio_DiscreteRead(data->sws, 1);
	xQueueSendFromISR(data->queue, &update, NULL);
	XGpio_InterruptClear(data->sws, XGPIO_IR_CH1_MASK);
}

struct ledTaskData {
	XGpio *btns, *sws, *leds;
	QueueHandle_t queue;
};

static void updateLedsTask(struct ledTaskData *data)
{
	unsigned cnt = 0, mask = 0;

	extern XScuGic xInterruptController;

	struct btnsIntData btnIntData = { .btns = data->btns, .queue = data->queue };
	CHECKX(XScuGic_Connect(&xInterruptController, XPAR_FABRIC_AXI_GPIO_BTNS_IP2INTC_IRPT_INTR, (Xil_ExceptionHandler)btnsIntHandler, &btnIntData));
	struct swsIntData swsIntData = { .sws = data->sws, .queue = data->queue };
	CHECKX(XScuGic_Connect(&xInterruptController, XPAR_FABRIC_AXI_GPIO_SWS_IP2INTC_IRPT_INTR, (Xil_ExceptionHandler)swsIntHandler, &swsIntData));

	XGpio_InterruptEnable(data->btns, XGPIO_IR_CH1_MASK);
	XGpio_InterruptEnable(data->sws, XGPIO_IR_CH1_MASK);
	XGpio_InterruptGlobalEnable(data->btns);
	XGpio_InterruptGlobalEnable(data->sws);

	XScuGic_Enable(&xInterruptController, XPAR_FABRIC_AXI_GPIO_BTNS_IP2INTC_IRPT_INTR);
	XScuGic_Enable(&xInterruptController, XPAR_FABRIC_AXI_GPIO_SWS_IP2INTC_IRPT_INTR);

	struct updateVal update;
	update.type = UPDATE_SWS;
	update.sws.sws = XGpio_DiscreteRead(data->sws, 1);
	xQueueSend(data->queue, &update, 0);

	while (1) {
		struct updateVal update;
		if (xQueueReceive(data->queue, &update, portMAX_DELAY)) {
			switch (update.type) {
			case UPDATE_BTNS:
				cnt += update.btns.btns;
				break;
			case UPDATE_SWS:
				mask = update.sws.sws;
				break;
			default:
				xil_printf("%s:%d: Unexpected update type: %d\n", __FILE__, __LINE__, update.type);
				for (;;);
			}
			XGpio_DiscreteWrite(data->leds, 1, cnt ^ mask);
		}
	}
}

int main()
{
	const size_t QUEUE_SIZE = 16;

	XGpio btns, sws, leds;
	QueueHandle_t queue;

	queue = xQueueCreate(QUEUE_SIZE, sizeof(struct updateVal));
	struct ledTaskData ledTaskData = {
		.btns = &btns,
		.sws = &sws,
		.leds = &leds,
		.queue = queue
	};
	CHECKRTOS(xTaskCreate((TaskFunction_t)updateLedsTask, "updateLedsTask", (short)configMINIMAL_STACK_SIZE, &ledTaskData, (BaseType_t)2 | portPRIVILEGE_BIT, NULL));

	CHECKX(XGpio_Initialize(&btns, XPAR_AXI_GPIO_BTNS_DEVICE_ID));
	CHECKX(XGpio_Initialize(&sws, XPAR_AXI_GPIO_SWS_DEVICE_ID));
	CHECKX(XGpio_Initialize(&leds, XPAR_AXI_GPIO_LEDS_DEVICE_ID));

	XGpio_SetDataDirection(&btns, 1, 0xFF);
	XGpio_SetDataDirection(&sws, 1, 0xFF);
	XGpio_SetDataDirection(&leds, 1, 0x00);

	vTaskStartScheduler();
	for (;;);
}

View solution in original post

0 Kudos
Highlighted
Visitor
Visitor
1,263 Views
Registered: ‎04-03-2018

Re: Interrupts ignored on FreeRTOS (code works in standalone mode)

Jump to solution

You absolutely saved my day on this!

 

Maybe someone could update the source code for the xuartps_intr_example.c to include a note on the SetupInterruptSystem to state that when setting up IRQ handlers and using freeRTOS there is you cannot call XScuGic_CfgInitialize,Instead the XscuGic instance can be referenced by extern XScuGic xInterruptController.

 

Wow what a pain that was.

0 Kudos
Highlighted
Adventurer
Adventurer
1,248 Views
Registered: ‎05-12-2017

Re: Interrupts ignored on FreeRTOS (code works in standalone mode)

Jump to solution

@haydendekker
I would add that you don't need to wait until start of scheduler and you can initialize xInterruptController yourself as it has protection against double initialization.

Highlighted
Advisor
Advisor
35 Views
Registered: ‎02-12-2013

Re: Interrupts ignored on FreeRTOS (code works in standalone mode)

Jump to solution

Really this subject needs a lot of clarification by Xilinx.  I have been playing around for over a week trying to generate interrupts under FreeRTOS. 

I did the same thing as this gentleman.  I first got hardware interrupts from the PL running in a stand-alone project. Then I tried to merge that into the FreeRTOS Hello World example but I have not succeeded. 

Obviously, freertos is using interrupts from the a timer in the PS for the clock tick.  My interrupt goes into an AXI Interrupt Controller which drives the PS interrupt input. 

A lot of folks post little fractional descriptions of tricks they used but I don't see a description of the standard recommended way that interrupts are to be added to a freertos project.

----------------------------------------
DSP in hardware and software
-----------------------------------------
0 Kudos