простая программа опроса прерываний благодаря AXI DMA IP

Программа передает массив данных из Zynq-7000 PS DDR в память BRAM IP (блочная RAM) в PL-части FPGA из-за PL AXI DMA IP. Используя драйвер dma xilinx axi (не режим разброса-сбора), контроллер прерываний и функцию printf поставщика, массив данных переносится из DDR в BRAM.

main.c

#include "xstatus.h"

#include "platform_.h"
#include "axi_dma_intr_poll.h"

#define TX_BUFFER               (uint32_t *) 0x01100000
#define RX_BUFFER               (uint32_t *) XPAR_BRAM_0_BASEADDR

#define RESET_TIMEOUT_CNTR_VAL  0x1000
#define MAX_TX_VALUE            0x100
#define PAYLOAD_SIZE            MAX_TX_VALUE

volatile _Bool tx_done_flag, rx_done_flag, tx_error, rx_error;

axi_dma_init_str init;
axi_dma_poll_str poll;
axi_dma_handler_str handler;

static void tx_intr_handler(void *callback);
static void rx_intr_handler(void *callback);

static inline void printf_array(uint32_t *p_array, size_t size);

int main(void) {

    uint8_t mul_coefficient = 0;
    const uint8_t c_ascii_num_offset = 0x30;
    uint32_t i = 0;

    memset((uint8_t *) XPAR_BRAM_0_BASEADDR,0,0x100);

    init.dma_id = XPAR_AXIDMA_0_DEVICE_ID;
    init.rx_intr_handler = rx_intr_handler;
    init.tx_intr_handler = tx_intr_handler;
    init.rx_intr_id = XPAR_FABRIC_AXIDMA_0_S2MM_INTROUT_VEC_ID;
    init.tx_intr_id = XPAR_FABRIC_AXIDMA_0_MM2S_INTROUT_VEC_ID;

    poll.p_tx_buf = TX_BUFFER;
    poll.p_rx_buf = RX_BUFFER;
    poll.size = PAYLOAD_SIZE;

    axi_dma_init(&init, &handler);

    while(1) {
        xil_printf("AXI DMA %d: ready. Insert multiplier coefficient (1 - 9): ", init.dma_id);

        mul_coefficient = inbyte();
        mul_coefficient -= c_ascii_num_offset;

        if ((0 == mul_coefficient) || (mul_coefficient > 9)) {
            xil_printf("nrAXI DMA %d ERROR: the coefficient must have a value from 1 to 9nr", init.dma_id);
            continue;
        }
        
        xil_printf("%dnr", mul_coefficient);

        for(i = 0; i < MAX_TX_VALUE; i++) {
            poll.p_tx_buf[i] = (i * mul_coefficient) % MAX_TX_VALUE;
        }

        tx_done_flag = FALSE;
        rx_done_flag = FALSE;

        axi_dma_poll(&poll, &handler.axi_dma, init.dma_id);

        xil_printf("AXI DMA %d: waiting completion of the poll...", init.dma_id);

        while((FALSE == tx_done_flag) || (FALSE == rx_done_flag)) {
            asm("NOP");
        }

        if ((TRUE == tx_error) || (TRUE == rx_error)) {
            xil_printf("AXI DMA %d ERROR: the polling ERROR", init.dma_id);
        }
        else {
            xil_printf("nnrAXI DMA %d: the tx buffer:nr", init.dma_id);
            printf_array(TX_BUFFER ,PAYLOAD_SIZE);

            xil_printf("nnrAXI DMA %d: the rx buffer:nr", init.dma_id);
            printf_array(RX_BUFFER, PAYLOAD_SIZE);
        }

        xil_printf("nnr");
    }

    return XST_SUCCESS;
}

static void tx_intr_handler(void *callback) {

    uint32_t status = 0;
    int reset_cntr = RESET_TIMEOUT_CNTR_VAL;
    XAxiDma *axi_dma = (XAxiDma *) callback;

    status = XAxiDma_IntrGetIrq(axi_dma, XAXIDMA_DMA_TO_DEVICE);

    XAxiDma_IntrAckIrq(axi_dma, status, XAXIDMA_DMA_TO_DEVICE);

    tx_done_flag = TRUE;

    if (FALSE != (status & XAXIDMA_IRQ_ALL_MASK) &&
       (TRUE == (status & XAXIDMA_IRQ_ERROR_MASK))) {
        tx_error = TRUE;
        XAxiDma_Reset(axi_dma);

        while (reset_cntr--) {
            if (XAxiDma_ResetIsDone(axi_dma)) {
                break;
            }

        }
    }
}


static void rx_intr_handler(void *callback)
{
    uint32_t status = 0;
    int reset_cntr = RESET_TIMEOUT_CNTR_VAL;
    XAxiDma *axi_dma = (XAxiDma *) callback;

    status = XAxiDma_IntrGetIrq(axi_dma, XAXIDMA_DEVICE_TO_DMA);

    XAxiDma_IntrAckIrq(axi_dma, status, XAXIDMA_DEVICE_TO_DMA);

    rx_done_flag = TRUE;

    if ((FALSE != (status & XAXIDMA_IRQ_ALL_MASK)) &&
       (TRUE == (status & XAXIDMA_IRQ_ERROR_MASK))) {
        rx_error = TRUE;
        XAxiDma_Reset(axi_dma);

        while (reset_cntr--) {
            if (XAxiDma_ResetIsDone(axi_dma)) {
                break;
            }
        }
    }
}

static inline void printf_array(uint32_t *p_array, size_t size) {
    const uint8_t c_values_per_line = 10;
    uint32_t i = 0;

    for(i = 0; i < size; i++) {
        xil_printf("%d ", *(TX_BUFFER + i));

        if (FALSE == (i % c_values_per_line) && (0 != i)) {
            xil_printf("nr");
        }
    }
}

axi_dma_intr_poll.c

#include "xil_exception.h"

#include "axi_dma_intr_poll.h"

static int enable_intr_(axi_dma_handler_str *p_handler, axi_dma_init_str *p_init);

int axi_dma_init(axi_dma_init_str *p_init, axi_dma_handler_str *p_handler) {

    if ((NULL == p_init) || (NULL == p_handler)) {
        xil_printf("AXI DMA %d ERROR: the entire axi_dma_init function ERRORrn", p_init->dma_id);
        return XST_FAILURE;
    }

    memset(p_handler, 0, sizeof(axi_dma_handler_str));

    p_handler->p_config = XAxiDma_LookupConfig(p_init->dma_id);
    if (NULL == p_handler->p_config) {
        xil_printf("AXI DMA %d ERROR: the dma lookup config FAILEDrn", p_init->dma_id);
        return XST_FAILURE;
    }

    if (XST_SUCCESS != XAxiDma_CfgInitialize(&(p_handler->axi_dma), p_handler->p_config)) {
        xil_printf("AXI DMA %d ERROR: the dma initialization FAILEDrn", p_init->dma_id);
        return XST_FAILURE;
    }

    if(TRUE == XAxiDma_HasSg(&(p_handler->axi_dma))){
        xil_printf("AXI DMA %d ERROR: the device configured as SG modern", p_init->dma_id);
        return XST_FAILURE;
    }

    if (XST_SUCCESS != enable_intr_(p_handler, p_init)) {
        xil_printf("AXI DMA %d ERROR: the interrupt setup FAILEDrn");
        return XST_FAILURE;
    }

    return XST_SUCCESS;
}

int axi_dma_poll(axi_dma_poll_str *p_poll, XAxiDma *p_axi_dma, uint32_t dma_id) {

    if ((NULL == p_poll) || (NULL == p_axi_dma)) {
        xil_printf("AXI DMA %d ERROR: the entire axi_dma_poll function ERRORrn", dma_id);
        return XST_FAILURE;
    }

    Xil_DCacheFlushRange((UINTPTR) (p_poll->p_tx_buf), p_poll->size);

    if (XST_SUCCESS != XAxiDma_SimpleTransfer(p_axi_dma,(UINTPTR) (p_poll->p_tx_buf),
                                              p_poll->size, XAXIDMA_DMA_TO_DEVICE)) {
        xil_printf("AXI DMA %d ERROR: the tx buffer setting FAILEDrn", dma_id);
        return XST_FAILURE;
    }

    if (XST_SUCCESS != XAxiDma_SimpleTransfer(p_axi_dma,(UINTPTR) (p_poll->p_rx_buf),
                                              p_poll->size, XAXIDMA_DEVICE_TO_DMA)) {
        xil_printf("AXI DMA %d ERROR: the rx buffer setting FAILEDrn", dma_id);
        return XST_FAILURE;
    }

    return XST_SUCCESS;
}

int axi_dma_release(XScuGic *p_scu_gic, uint32_t tx_intr_id, uint32_t rx_intr_id) {

    if ((NULL == p_scu_gic) || (0 == tx_intr_id) || (0 == rx_intr_id)) {
        xil_printf("AXI DMA %d ERROR: the entire axi_dma_release function ERRORrn", p_scu_gic->Config->DeviceId);
        return XST_FAILURE;
    }

    XScuGic_Disconnect(p_scu_gic, tx_intr_id);
    XScuGic_Disconnect(p_scu_gic, rx_intr_id);

    return XST_SUCCESS;
}

static int enable_intr_(axi_dma_handler_str *p_handler, axi_dma_init_str *p_init) {

    const uint8_t c_priority = 0xA0, c_trigger_type = 0x3;

    p_handler->p_intc_config = XScuGic_LookupConfig(XPAR_SCUGIC_SINGLE_DEVICE_ID);
    if (NULL == p_handler->p_intc_config) {
        xil_printf("AXI DMA %d ERROR: the scu gic lookup config FAILEDrn", p_init->dma_id);
        return XST_FAILURE;
    }

    if (XST_SUCCESS != XScuGic_CfgInitialize(&(p_handler->scu_gic), p_handler->p_intc_config,
                                               p_handler->p_intc_config->CpuBaseAddress)) {
        xil_printf("AXI DMA %d ERROR: the scu gic initialization FAILEDrn", p_init->dma_id);
        return XST_FAILURE;
    }

    XScuGic_SetPriorityTriggerType(&(p_handler->scu_gic), p_init->tx_intr_id, c_priority, c_trigger_type);
    XScuGic_SetPriorityTriggerType(&(p_handler->scu_gic), p_init->rx_intr_id, c_priority, c_trigger_type);

    if (XST_SUCCESS != XScuGic_Connect(&(p_handler->scu_gic), p_init->tx_intr_id,
                                      (Xil_InterruptHandler)p_init->tx_intr_handler,
                                      &(p_handler->axi_dma))) {
        xil_printf("AXI DMA %d ERROR: the scu gic tx connection FAILEDrn", p_init->dma_id);
        return XST_FAILURE;
    }

    if (XST_SUCCESS != XScuGic_Connect(&(p_handler->scu_gic), p_init->rx_intr_id,
                                      (Xil_InterruptHandler)p_init->rx_intr_handler,
                                      &(p_handler->axi_dma))) {
        xil_printf("AXI DMA %d ERROR: the scu gic rx connection FAILEDrn", p_init->dma_id);
        return XST_FAILURE;
    }

    XScuGic_Enable(&(p_handler->scu_gic), p_init->tx_intr_id);
    XScuGic_Enable(&(p_handler->scu_gic), p_init->rx_intr_id);

    Xil_ExceptionInit();
    Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler)XScuGic_InterruptHandler,
                                (void *)&(p_handler->scu_gic));

    Xil_ExceptionEnable();

    XAxiDma_IntrDisable(&(p_handler->axi_dma), XAXIDMA_IRQ_ALL_MASK,
                       XAXIDMA_DMA_TO_DEVICE);

    XAxiDma_IntrDisable(&(p_handler->axi_dma), XAXIDMA_IRQ_ALL_MASK,
                       XAXIDMA_DEVICE_TO_DMA);

    XAxiDma_IntrEnable(&(p_handler->axi_dma), XAXIDMA_IRQ_ALL_MASK,
                      XAXIDMA_DMA_TO_DEVICE);

    XAxiDma_IntrEnable(&(p_handler->axi_dma), XAXIDMA_IRQ_ALL_MASK,
                      XAXIDMA_DEVICE_TO_DMA);

    return XST_SUCCESS;
}

axi_dma_intr_poll.h

#ifndef INC_AXI_DMA_POLL_H
#define INC_AXI_DMA_POLL_H

#include "xaxidma.h"
#include "xscugic.h"

#include "platform_.h"

typedef struct {
    uint32_t *p_tx_buf;
    uint32_t *p_rx_buf;
    size_t size;
} axi_dma_poll_str;

typedef struct {
    uint32_t tx_intr_id;
    uint32_t rx_intr_id;
    void (*rx_intr_handler)(void *);
    void (*tx_intr_handler)(void *);
    uint32_t dma_id;
} axi_dma_init_str;

typedef struct {
    XAxiDma axi_dma;
    XAxiDma_Config *p_config;
    XScuGic scu_gic;
    XScuGic_Config *p_intc_config;
} axi_dma_handler_str;

int axi_dma_init(axi_dma_init_str *p_init, axi_dma_handler_str *p_handler);
int axi_dma_poll(axi_dma_poll_str *p_poll, XAxiDma *p_axi_dma, uint32_t dma_id);
int axi_dma_release(XScuGic *p_scu_gic, uint32_t tx_intr_id, uint32_t rx_intr_id);

#endif

0

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *