Interrupción de FPGA en FreeRTOS

3

Estoy usando freeRTOS en Zedboard. Soy capaz de habilitar la interrupción PL-PS en el programa de metal abierto. Realmente no pude encontrar ninguna documentación / tutorial sobre cómo vincular FreeRTOS y el sistema de interrupción PL. Actualmente estoy migrando mi software a freeRTOS pero no estoy seguro de cómo "conectar" la interrupción entre freeRTOS y la interrupción PL. Esto es lo que he hecho y estoy seguro de que está totalmente equivocado.

En lo principal:

xTaskCreate(InitInterrupt, (const char * )"Init Interrupt",
            configMINIMAL_STACK_SIZE, XPAR_PS7_SCUGIC_0_DEVICE_ID,
            tskIDLE_PRIORITY, NULL);

Función de habilitación de interrupción:

XScuGic InterruptController;
static XScuGic_Config *GicConfig;
xSemaphoreHandle DMATransfer_trigger = 0;

int SetUpInterruptSystem(XScuGic *XScuGicInstancePtr) {
    Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
            (Xil_ExceptionHandler) XScuGic_InterruptHandler,
            XScuGicInstancePtr);
    Xil_ExceptionEnable();
    //enable interrupt in ARM
    return XST_SUCCESS;
}

static void InitInterrupt( deviceID) {
    while (1) {
        int Status;

        GicConfig = XScuGic_LookupConfig(deviceID);
        if (NULL == GicConfig) {
            xil_printf("Interrupt Initialization FAILED!!\r\n");
            vTaskDelete(NULL);  //delete InitAXIDMA itself
        }

        Status = XScuGic_CfgInitialize(&InterruptController, GicConfig,
                GicConfig->CpuBaseAddress);
        if (Status != XST_SUCCESS) {
            xil_printf("Interrupt Initialization FAILED!!\r\n");
            vTaskDelete(NULL);  //delete InitAXIDMA itself
        }

        Status = SetUpInterruptSystem(&InterruptController);
        if (Status != XST_SUCCESS) {
            xil_printf("Interrupt Initialization FAILED!!\r\n");
            vTaskDelete(NULL);  //delete InitAXIDMA itself
        }

        Status = XScuGic_Connect(&InterruptController,
        XPAR_FABRIC_AXI_DMA_0_S2MM_INTROUT_INTR,
                (Xil_ExceptionHandler) InterruptHandler,
                NULL);
        if (Status != XST_SUCCESS) {
            xil_printf("Interrupt Initialization FAILED!!\r\n");
            vTaskDelete(NULL);  //delete InitAXIDMA itself
        }
        XScuGic_Enable(&InterruptController,
        XPAR_FABRIC_AXI_DMA_0_S2MM_INTROUT_INTR);
#ifdef DEBUG
        xil_printf("Interrupt Initialization Complete\r\n");
#endif
        vTaskDelete(NULL);  //delete InitAXIDMA itself
    }
}

En el controlador de interrupciones:

void InterruptHandler(void) {
u32 tmpValue;
//xil_printf("Interrupt acknowledged...\n\r);
//clear interrupt just perform a write bit to no 12 ofS2MM_DMASR
tmpValue = Xil_In32(XPAR_AXI_DMA_0_BASEADDR + 0x34);
tmpValue = tmpValue | 0x1000;
Xil_Out32( XPAR_AXI_DMA_0_BASEADDR + 0x34, tmpValue);
//Process Data Here!!

//initialize another transfer
    xSemaphoreGive(DMATransfer_trigger);
}

La fuente de interrupción es de la IP del controlador DMA AXI. Esto es lo que he intentado pero no funciona. ¿Alguien puede darme una guía sobre cómo modificar el código para manejar y configurar la interrupción de FreeRTOS desde el PL? ¡Gracias!

    
pregunta user9870

2 respuestas

1

Parece que el código Xilinx funciona siempre que el XScuGic no se reinicialice en un lugar diferente. En otras palabras, debe inicializar & utilizar xInterruptController :

extern XScuGic xInterruptController;

int main()
{
    XScuGic_Config *scuGicConfig = XScuGic_LookupConfig(0);
    XScuGic_CfgInitialize(&xInterruptController, scuGicConfig, scuGicConfig->CpuBaseAddress);
    // ...
}

ANTIGUA RESPUESTA: No puede ni debe reinicializar el controlador de interrupciones. Ya está inicializado por FreeRTOS_SetupTickInterrupt que a su vez es llamado por vTaskStartScheduler . Una vez que FreeRTOS está activo & ejecutando simplemente puede registrar interrupciones de la tarea. Adjunto el siguiente ejemplo, que es una especie de puerto de tutorial de Zynq Book (perdón por el código hacky, pero simplemente lo descubrí):

#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 (;;);
}
    
respondido por el Maciej Piechotka
1

Suponiendo que se trata de un Cortex-A9 Zynq 7000, encontrará documentación sobre cómo usar interrupciones con FreeRTOS en el siguiente enlace: enlace - con ejemplos resueltos en la descarga oficial de FreeRTOS. La información sobre cómo localizar el ejemplo dentro de la descarga oficial de FreeRTOS se puede encontrar en el siguiente enlace: enlace

    
respondido por el Richard

Lea otras preguntas en las etiquetas