Problem on pl to ps interrupt with freertos on vitis ide 2024.2

Hi everyone,

I’m working with Zynq7020 (ZC702 Board). I created a Vivado project where i generate interrupts from PL to PS. The following image shows that two debounced pushbuttons are connected to the line IRQ_F2P of Zynq7 Processing System.

I generated the bitstream, and created the platform in VITIS IDE 2024.2

Firstly I worked with a BAREMETAL platform, where I demonstrated that interrupts work. (So I figured out that the problem is not hardware!). The two interrupts line have the ID 61 and 62 respectively.

Then I generated a FREERTOS platform, but Interrupt doesn’t work anymore!

This is my code (to simplify, I’m only using interrupt from just one pushbutton).

/* ============================================================
 *  main.c  —  FreeRTOS + AXI GPIO interrupt  —  ZC702
 * ============================================================ */
 
#include "FreeRTOS.h"
#include "task.h"
#include "xgpio.h"
#include "xil_printf.h"
#include "xparameters.h"
#include "portmacro.h"
#include "xstatus.h"
#include "xil_exception.h"
#include "xil_types.h"
 
#define LED_BASE_ADDR   XPAR_LED_19_BASEADDR
#define BTN1_BASE_ADDR  XPAR_BUTTON_1_BASEADDR
#define BTN_1_INT_ID    XPS_FPGA0_INT_ID  //61
#define BTN_INT_MASK    XGPIO_IR_CH1_MASK
#define GPIO_CHANNEL    1
 
XGpio LED_Inst;
XGpio BTN1_Inst;
 
static TaskHandle_t TaskLed  = NULL;
static TaskHandle_t TaskHand = NULL;
static TaskHandle_t xHandle  = NULL;
 
static void Task_Led  (void *pvParameters);
static void Task_HAND (void *pvParameters);
static void BTN1_ISR  (void *CallBackRef);
static void BTN1_Init (void);
 
 
 
//pushbutton 1 ISR
static void BTN1_ISR(void *CallBackRef)
{
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    XGpio *GpioPtr = (XGpio *)CallBackRef;
 
    XGpio_InterruptClear(GpioPtr, BTN_INT_MASK);
 
    if (xHandle != NULL)
        vTaskNotifyGiveFromISR(xHandle, &xHigherPriorityTaskWoken);
 
    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
 
 
 
 //pushbutton 1 initializiation
 
static void BTN1_Init(void)
{
    XGpio_SetDataDirection(&BTN1_Inst, GPIO_CHANNEL, 0xFF);
    XGpio_InterruptEnable(&BTN1_Inst, BTN_INT_MASK);
    XGpio_InterruptGlobalEnable(&BTN1_Inst);
 
    xPortInstallInterruptHandler(BTN_1_INT_ID,
        (Xil_ExceptionHandler)BTN1_ISR,
        (void *)&BTN1_Inst);
 
    vPortEnableInterrupt(BTN_1_INT_ID);
}
 
 
 
int main(void)
{
    int status;
 
    status = XGpio_Initialize(&LED_Inst, LED_BASE_ADDR);
    if (status != XST_SUCCESS) { xil_printf("LED INIT FAILED\n\r"); return XST_FAILURE; }
    XGpio_SetDataDirection(&LED_Inst, GPIO_CHANNEL, 0x00);
    xil_printf("LED INIT OK\n\r");
 
    status = XGpio_Initialize(&BTN1_Inst, BTN1_BASE_ADDR);
    if (status != XST_SUCCESS) { xil_printf("BTN1 INIT FAILED\n\r"); return XST_FAILURE; }
    xil_printf("BTN1 INIT OK\n\r");
 
    xTaskCreate(Task_Led,  "Led",  configMINIMAL_STACK_SIZE,     NULL, tskIDLE_PRIORITY + 1, &TaskLed);
    xTaskCreate(Task_HAND, "HAND", configMINIMAL_STACK_SIZE * 2, NULL, tskIDLE_PRIORITY + 2, &TaskHand);
 
    vTaskStartScheduler();
    for (;;);
    return 0;
}
 
 
 
 //  TASK LED
 
static void Task_Led(void *pvParameters)
{
    const TickType_t x1second = pdMS_TO_TICKS(1000);
    uint8_t ledState = 0;
    for (;;) {
        ledState = (ledState == 0) ? 0x7F : 0x00;
        XGpio_DiscreteWrite(&LED_Inst, GPIO_CHANNEL, ledState);
        vTaskDelay(x1second);
    }
}
 
 
// TASK HANDLER
 
static void Task_HAND(void *pvParameters)
{
    xHandle = xTaskGetCurrentTaskHandle();
    BTN1_Init();
    xil_printf("Ready!, push BTN1\n\r");
    for (;;) {
        ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
        xil_printf("BTN1 pushed!\n\r");
    }
}


VITIS 2024.2 IDE has the following parameters:

XPAR_XILTIMER_ENABLED = 1

SDT = 1

Moreover, I made another trying, where I handle an interrupt generated from the TTC 0, (using xPortInstallInterruptHandler) and it works.

But the xPortInstallInterruptHandler doesn’t work with interrupt from PL!!!

PS: before trying this code, I tried to use the function “XScuGic_Connect”, but it doesn’t work witth FREERTOS because the operating system itself initiliases the GIC.

Thank you in advance!

This question is very Xilinx specific. Please reach out to Xilinx as well.

Meanwhile, does this help: Zynq 7020 interrupts under FreeRTOS v10.1.1 - #3 by Steve?

I can’t really share specific examples but I have notes to myself about just this topic:

//Zynq is finicky about setting up the FPGA interrupts
//Initialization is done before starting the scheduler
//But connection and enable are done after starting the scheduler

Basically, XScuGic_Connect and XScuGic_Enable should be called after the scheduler is started. All the other init code can be done before the scheduler. There might be a cleaner solution but this has worked for me.

1 Like