UPGRADE YOUR BROWSER

We have detected your current browser version is not the latest one. Xilinx.com uses the latest web technologies to bring you the best online experience possible. Please upgrade to a Xilinx.com supported browser:Chrome, Firefox, Internet Explorer 11, Safari. Thank you!

cancel
Showing results for 
Search instead for 
Did you mean: 
Highlighted
Adventurer
Adventurer
1,250 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
Adventurer
Adventurer
1,776 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 (;;);
}
0 Kudos
4 Replies
Observer richardbarry
Observer
1,224 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
Adventurer
Adventurer
1,777 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 (;;);
}
0 Kudos
Visitor haydendekker
Visitor
1,059 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
Adventurer
Adventurer
1,044 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.