Initial version.
This commit is contained in:
@@ -0,0 +1,452 @@
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* Description: A simple AXI DMA api.
|
||||
*
|
||||
* Author: Fan Hao
|
||||
* Date: 2022-06-18 16:37
|
||||
* LastEditors: Fan Hao
|
||||
* LastEditTime: 2022-06-18 17:38
|
||||
* Revisions: Rev 0.0
|
||||
* History:
|
||||
* [2022-06-18]: Initial version.
|
||||
*
|
||||
* Copyright(c) 2022 Beijing Institute of Technology.
|
||||
* Lab of Communication and Networking
|
||||
*
|
||||
******************************************************************************/
|
||||
/***************************** Include Files *********************************/
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "xaxidma.h"
|
||||
// #include "xtime_l.h" //Adjutment for microblaze
|
||||
#include "xil_cache.h"
|
||||
|
||||
#include "axi_dma.h"
|
||||
#include "../error.h"
|
||||
#include "../common.h"
|
||||
|
||||
/************************** Constant Definitions *****************************/
|
||||
/***************** Macros (Inline Functions) Definitions *********************/
|
||||
/************************** Function Prototypes ******************************/
|
||||
/**************************** Type Definitions *******************************/
|
||||
/************************** Variable Definitions *****************************/
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Initialize the DMA descriptor instance, allocate space for
|
||||
* descriptor.
|
||||
*
|
||||
* @param instPtr a second rank pointer to DMA descriptor instance
|
||||
* @param configPtr a pointer to DMA descriptor instance configuration
|
||||
* set.
|
||||
*
|
||||
* @return SUCCESS
|
||||
* ENOMEM memory allocate failed.
|
||||
* other error codes
|
||||
*
|
||||
******************************************************************************/
|
||||
int32_t Dma_Init(DMA_DESC** instPtr, const DMA_CONFIG* configPtr){
|
||||
ASSERT(configPtr != NULL);
|
||||
int32_t Status = SUCCESS;
|
||||
|
||||
*instPtr = (DMA_DESC*) malloc(sizeof(DMA_DESC));
|
||||
if ((*instPtr) == NULL) {
|
||||
goto err;
|
||||
}
|
||||
(*instPtr)->isTxDone = false;
|
||||
(*instPtr)->isRxDone = false;
|
||||
(*instPtr)->isError = false;
|
||||
(*instPtr)->isListening = false;
|
||||
memcpy(&((*instPtr)->configs), configPtr, sizeof(DMA_CONFIG));
|
||||
|
||||
(*instPtr)->axiDmaPtr = (XAxiDma*) malloc(sizeof(XAxiDma));
|
||||
if ((*instPtr)->axiDmaPtr == NULL) {
|
||||
free((*instPtr)->axiDmaPtr);
|
||||
goto err;
|
||||
}
|
||||
|
||||
XAxiDma_Config* damConfigPtr = NULL;
|
||||
damConfigPtr = XAxiDma_LookupConfig(configPtr->devId);
|
||||
if (damConfigPtr == NULL) {
|
||||
DBG_PRINT("No config found for %d\r\n", configPtr->devId);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Initialize DMA engine */
|
||||
Status = XAxiDma_CfgInitialize((*instPtr)->axiDmaPtr, damConfigPtr);
|
||||
if (Status != SUCCESS) {
|
||||
DBG_ERROR("DMA initialize failed. device id: %d\r\n", configPtr->devId);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if(XAxiDma_HasSg((*instPtr)->axiDmaPtr)){
|
||||
DBG_ERROR("DMA Device configured as SG mode \r\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Clear all interrupts before setup */
|
||||
XAxiDma_IntrAckIrq((*instPtr)->axiDmaPtr, XAXIDMA_IRQ_ALL_MASK,
|
||||
XAXIDMA_DMA_TO_DEVICE);
|
||||
XAxiDma_IntrAckIrq((*instPtr)->axiDmaPtr, XAXIDMA_IRQ_ALL_MASK,
|
||||
XAXIDMA_DEVICE_TO_DMA);
|
||||
|
||||
/* Disable all interrupts before setup */
|
||||
XAxiDma_IntrDisable((*instPtr)->axiDmaPtr, XAXIDMA_IRQ_ALL_MASK,
|
||||
XAXIDMA_DMA_TO_DEVICE);
|
||||
XAxiDma_IntrDisable((*instPtr)->axiDmaPtr, XAXIDMA_IRQ_ALL_MASK,
|
||||
XAXIDMA_DEVICE_TO_DMA);
|
||||
|
||||
(*instPtr)->isInitialized = true;
|
||||
|
||||
return SUCCESS;
|
||||
err:
|
||||
free(*instPtr);
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Enable DMA IRQs.
|
||||
*
|
||||
* @param instPtr a pointer to DMA descriptor instance.
|
||||
*
|
||||
* @return SUCCESS
|
||||
* EDINVAL device not initialized.
|
||||
*
|
||||
******************************************************************************/
|
||||
int32_t Dma_IrqEnable(DMA_DESC* instPtr){
|
||||
if(instPtr == NULL || instPtr->isInitialized == false){
|
||||
return EDINVAL;
|
||||
}
|
||||
/* Enable all interrupts */
|
||||
XAxiDma_IntrEnable(instPtr->axiDmaPtr, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DMA_TO_DEVICE);
|
||||
XAxiDma_IntrEnable(instPtr->axiDmaPtr, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DEVICE_TO_DMA);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Enable DMA listening feature and start a receive procedure.
|
||||
*
|
||||
* @param instPtr a pointer to DMA descriptor instance.
|
||||
* @param dataBuff a pointer to data buffer.
|
||||
*
|
||||
* @return SUCCESS
|
||||
* EDINVAL device not initialized.
|
||||
*
|
||||
******************************************************************************/
|
||||
int32_t Dma_ListenEnable(DMA_DESC* instPtr, uint8_t* dataBuff){
|
||||
if(instPtr == NULL || instPtr->isInitialized == false || dataBuff == NULL){
|
||||
return EDINVAL;
|
||||
}
|
||||
instPtr->isListening = true;
|
||||
instPtr->listenBuff = dataBuff;
|
||||
// if(XAxiDma_Busy(instPtr->axiDmaPtr, XAXIDMA_DEVICE_TO_DMA) == false){
|
||||
return XAxiDma_SimpleTransfer(instPtr->axiDmaPtr,(uintptr_t)instPtr->listenBuff,
|
||||
instPtr->configs.defaultTransLen, XAXIDMA_DEVICE_TO_DMA);
|
||||
// }
|
||||
// else{
|
||||
// return SUCCESS;
|
||||
// }
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Disable DMA listening feature and start a receive procedure.
|
||||
*
|
||||
* @param instPtr a pointer to DMA descriptor instance.
|
||||
*
|
||||
* @return SUCCESS
|
||||
* EDINVAL device not initialized.
|
||||
*
|
||||
******************************************************************************/
|
||||
int32_t Dma_ListenDisable(DMA_DESC* instPtr){
|
||||
if(instPtr == NULL || instPtr->isInitialized == false){
|
||||
return EDINVAL;
|
||||
}
|
||||
instPtr->isListening = false;
|
||||
instPtr->listenBuff = NULL;
|
||||
if(XAxiDma_Busy(instPtr->axiDmaPtr, XAXIDMA_DEVICE_TO_DMA) == true){
|
||||
DBG_WARNING("an unfinished transfer is on going.\r\n");
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Transfer a specific length of data (DMA->Device), none-blocking
|
||||
* transfer.
|
||||
*
|
||||
* @param instPtr a pointer to DMA descriptor instance.
|
||||
* @param dataBuff a pointer to data buffer.
|
||||
* @param dataLen length of data need to be transfer.
|
||||
*
|
||||
* @return SUCCESS
|
||||
* EDINVAL device not initialized.
|
||||
*
|
||||
******************************************************************************/
|
||||
int32_t Dma_SendData(DMA_DESC* instPtr, uint8_t* dataBuff, int32_t dataLen){
|
||||
int32_t Status;
|
||||
if(dataLen > instPtr->configs.transMax){
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
// Flush the SrcBuffer before the DMA transfer
|
||||
// Xil_DCacheFlushRange((uintptr_t)dataBuff, dataLen);
|
||||
|
||||
// Set txDone flage to false, before transmission
|
||||
instPtr->isTxDone = false;
|
||||
// Assert a send trigger
|
||||
Status = XAxiDma_SimpleTransfer(instPtr->axiDmaPtr, (uintptr_t)dataBuff,
|
||||
dataLen, XAXIDMA_DMA_TO_DEVICE);
|
||||
if (Status != SUCCESS) {
|
||||
return FAILURE;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Transfer a specific length of data (DMA->Device), blocking transfer.
|
||||
*
|
||||
* @param instPtr a pointer to DMA descriptor instance.
|
||||
* @param dataBuff a pointer to data buffer.
|
||||
* @param dataLen length of data need to be transfer.
|
||||
*
|
||||
* @return SUCCESS
|
||||
* ETIMEOUT transfer timeout.
|
||||
* other error codes.
|
||||
*
|
||||
******************************************************************************/
|
||||
int32_t Dma_BlockingSendData(DMA_DESC* instPtr, uint8_t* dataBuff, int32_t dataLen){
|
||||
int32_t Status;
|
||||
if(dataLen > instPtr->configs.transMax){
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
Status = Dma_SendData(instPtr, dataBuff, dataLen);
|
||||
if(Status == SUCCESS){
|
||||
DBG_ERROR("Failed to setup a DMA transfer (DMA->Device).\r\n");
|
||||
return Status;
|
||||
}
|
||||
//Adjutment for microblaze
|
||||
// XTime tCur = 0;
|
||||
// XTime tTimeOut = 0;
|
||||
// XTime_GetTime(&tCur);
|
||||
// tTimeOut = tCur + instPtr->configs.timeoutTh;
|
||||
|
||||
while(instPtr->isTxDone == false && instPtr->isError == false){
|
||||
//Adjutment for microblaze
|
||||
// XTime_GetTime(&tCur);
|
||||
// if(tCur >= tTimeOut){
|
||||
// return ETIMEOUT;
|
||||
// }
|
||||
}
|
||||
if(instPtr->isError == true){
|
||||
return FAILURE;
|
||||
}
|
||||
// Set txDone flage to false, after transmission
|
||||
instPtr->isTxDone = false;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Transfer a specific length of data (Device->DMA), none-blocking
|
||||
* transfer.
|
||||
*
|
||||
* @param instPtr a pointer to DMA descriptor instance.
|
||||
* @param dataBuff a pointer to data buffer.
|
||||
* @param dataLen length of data need to be transfer.
|
||||
*
|
||||
* @return SUCCESS
|
||||
* EDINVAL device not initialized.
|
||||
*
|
||||
******************************************************************************/
|
||||
int32_t Dma_RecvData(DMA_DESC* instPtr, uint8_t* dataBuff, int32_t dataLen){
|
||||
int32_t Status;
|
||||
if(dataLen > instPtr->configs.transMax){
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
// Set txDone flage to false, before transmission
|
||||
instPtr->isRxDone = false;
|
||||
// Assert a send trigger
|
||||
Status = XAxiDma_SimpleTransfer(instPtr->axiDmaPtr,(uintptr_t)dataBuff,
|
||||
dataLen, XAXIDMA_DEVICE_TO_DMA);
|
||||
if (Status != SUCCESS) {
|
||||
return FAILURE;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Transfer a specific length of data (Device->DMA), blocking transfer.
|
||||
*
|
||||
* @param instPtr a pointer to DMA descriptor instance.
|
||||
* @param dataBuff a pointer to data buffer.
|
||||
* @param dataLen length of data need to be transfer.
|
||||
*
|
||||
* @return SUCCESS
|
||||
* EDINVAL device not initialized.
|
||||
*
|
||||
******************************************************************************/
|
||||
int32_t Dma_BlockingRecvData(DMA_DESC* instPtr, uint8_t* dataBuff, int32_t dataLen){
|
||||
int32_t Status;
|
||||
if(dataLen > instPtr->configs.transMax){
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
Status = Dma_RecvData(instPtr, dataBuff, dataLen);
|
||||
if(Status == SUCCESS){
|
||||
DBG_ERROR("Failed to setup a DMA transfer (Device->DMA).\r\n");
|
||||
return Status;
|
||||
}
|
||||
|
||||
//Adjutment for microblaze
|
||||
// XTime tCur = 0;
|
||||
// XTime tTimeOut = 0;
|
||||
// XTime_GetTime(&tCur);
|
||||
// tTimeOut = tCur + instPtr->configs.timeoutTh;
|
||||
|
||||
while(instPtr->isTxDone == false && instPtr->isError == false){
|
||||
//Adjutment for microblaze
|
||||
// XTime_GetTime(&tCur);
|
||||
// if(tCur >= tTimeOut){
|
||||
// return ETIMEOUT;
|
||||
// }
|
||||
}
|
||||
if(instPtr->isError == true){
|
||||
return FAILURE;
|
||||
}
|
||||
// Set txDone flage to false, after transmission
|
||||
instPtr->isTxDone = false;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Handler for DMA->Device transfer.
|
||||
*
|
||||
* @param instPtr a pointer to DMA descriptor instance.
|
||||
*
|
||||
* @return SUCCESS
|
||||
* error codes
|
||||
*
|
||||
******************************************************************************/
|
||||
int32_t Dma_SendIrqHandler(DMA_DESC* instPtr){
|
||||
if(instPtr == NULL || instPtr->isInitialized == false){
|
||||
return FAILURE;
|
||||
}
|
||||
int32_t Status = SUCCESS;
|
||||
uint32_t IrqStatus = 0;
|
||||
/* Read pending interrupts */
|
||||
IrqStatus = XAxiDma_IntrGetIrq(instPtr->axiDmaPtr, XAXIDMA_DMA_TO_DEVICE);
|
||||
|
||||
/* Acknowledge pending interrupts */
|
||||
XAxiDma_IntrAckIrq(instPtr->axiDmaPtr, IrqStatus, XAXIDMA_DMA_TO_DEVICE);
|
||||
|
||||
/* If no interrupt is asserted, we do not do anything */
|
||||
if (!(IrqStatus & XAXIDMA_IRQ_ALL_MASK)) {
|
||||
return EIGNORE;
|
||||
}
|
||||
|
||||
/* If error interrupt is asserted, raise error flag, reset the
|
||||
* hardware to recover from the error, and return with no further
|
||||
* processing.
|
||||
*/
|
||||
if ((IrqStatus & XAXIDMA_IRQ_ERROR_MASK)) {
|
||||
|
||||
instPtr->isError = true;
|
||||
|
||||
/* Reset should never fail for transmit channel */
|
||||
XAxiDma_Reset(instPtr->axiDmaPtr);
|
||||
while (XAxiDma_ResetIsDone(instPtr->axiDmaPtr) == false) {
|
||||
// FIXME: Add time out check
|
||||
}
|
||||
return EUNEXP;
|
||||
}
|
||||
|
||||
/* If Completion interrupt is asserted, then set the TxDone flag */
|
||||
if ((IrqStatus & XAXIDMA_IRQ_IOC_MASK)) {
|
||||
instPtr->isTxDone = true;
|
||||
}
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* @brief Handler for Device->DMA transfer.
|
||||
*
|
||||
* @param instPtr a pointer to DMA descriptor instance.
|
||||
*
|
||||
* @return SUCCESS
|
||||
* error codes
|
||||
*
|
||||
******************************************************************************/
|
||||
int32_t Dma_RecvIrqHandler(DMA_DESC* instPtr){
|
||||
if(instPtr == NULL || instPtr->isInitialized == false){
|
||||
return FAILURE;
|
||||
}
|
||||
int32_t Status = SUCCESS;
|
||||
uint32_t IrqStatus = 0;
|
||||
|
||||
/* Read pending interrupts */
|
||||
IrqStatus = XAxiDma_IntrGetIrq(instPtr->axiDmaPtr, XAXIDMA_DEVICE_TO_DMA);
|
||||
|
||||
/* Acknowledge pending interrupts */
|
||||
XAxiDma_IntrAckIrq(instPtr->axiDmaPtr, IrqStatus, XAXIDMA_DEVICE_TO_DMA);
|
||||
|
||||
/* If no interrupt is asserted, we do not do anything */
|
||||
if (!(IrqStatus & XAXIDMA_IRQ_ALL_MASK)) {
|
||||
return EIGNORE;
|
||||
}
|
||||
|
||||
/* If error interrupt is asserted, raise error flag, reset the
|
||||
* hardware to recover from the error, and return with no further
|
||||
* processing.
|
||||
*/
|
||||
if ((IrqStatus & XAXIDMA_IRQ_ERROR_MASK)) {
|
||||
|
||||
instPtr->isError = true;
|
||||
|
||||
/* Reset should never fail for transmit channel */
|
||||
XAxiDma_Reset(instPtr->axiDmaPtr);
|
||||
while (XAxiDma_ResetIsDone(instPtr->axiDmaPtr)) {
|
||||
// FIXME: Add time out check
|
||||
}
|
||||
return EUNEXP;
|
||||
}
|
||||
|
||||
/* If completion interrupt is asserted, then set RxDone flag */
|
||||
if ((IrqStatus & XAXIDMA_IRQ_IOC_MASK)) {
|
||||
// // Invalid the DestBuffer after the DMA transfer
|
||||
// int RingIndex = 0;
|
||||
// uintptr_t dstAddr;
|
||||
// uint32_t transLen;
|
||||
// dstAddr = XAxiDma_ReadReg(instPtr->axiDmaPtr->RxBdRing[RingIndex].ChanBase, XAXIDMA_DESTADDR_OFFSET);
|
||||
// if (instPtr->axiDmaPtr->AddrWidth > 32){
|
||||
// dstAddr |= ((uintptr_t)(XAxiDma_ReadReg(instPtr->axiDmaPtr->RxBdRing[RingIndex].ChanBase,
|
||||
// XAXIDMA_DESTADDR_MSB_OFFSET))<<32);
|
||||
// }
|
||||
// transLen = XAxiDma_ReadReg(InstancePtr->RxBdRing[RingIndex].ChanBase, XAXIDMA_BUFFLEN_OFFSET)
|
||||
// Xil_DCacheInvalidateRange(dstAddr, transLen);
|
||||
instPtr->isRxDone = true;
|
||||
}
|
||||
if(instPtr->isListening == true){
|
||||
// Continuous receiving
|
||||
Status = XAxiDma_SimpleTransfer(instPtr->axiDmaPtr,(uintptr_t)instPtr->listenBuff,
|
||||
instPtr->configs.defaultTransLen, XAXIDMA_DEVICE_TO_DMA);
|
||||
if(Status != SUCCESS){
|
||||
DBG_ERROR("Failed to start a new SimpleTransfer in XAXIDMA_DEVICE_TO_DMA channel.\r\n");
|
||||
}
|
||||
}
|
||||
return Status;
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* Description: A simple AXI DMA api.
|
||||
* prototypes.
|
||||
*
|
||||
* Author: Fan Hao
|
||||
* Date: 2022-06-18 16:37
|
||||
* LastEditors: Fan Hao
|
||||
* LastEditTime: 2022-06-18 17:40
|
||||
* Revisions: Rev 0.0
|
||||
* History:
|
||||
* [2022-06-18]: Initial version.
|
||||
*
|
||||
* Copyright(c) 2022 Beijing Institute of Technology.
|
||||
* Lab of Communication and Networking
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef AXI_DMA_H_
|
||||
#define AXI_DMA_H_
|
||||
|
||||
|
||||
/***************************** Include Files *********************************/
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "xaxidma.h"
|
||||
|
||||
/************************** Constant Definitions *****************************/
|
||||
/***************** Macros (Inline Functions) Definitions *********************/
|
||||
/**************************** Type Definitions *******************************/
|
||||
typedef struct{
|
||||
uint32_t devId;
|
||||
uint32_t transMax;
|
||||
uint32_t defaultTransLen;
|
||||
uint32_t timeoutTh;
|
||||
}DMA_CONFIG;
|
||||
|
||||
typedef struct{
|
||||
bool isTxDone;
|
||||
bool isRxDone;
|
||||
bool isError;
|
||||
bool isListening;
|
||||
bool isInitialized;
|
||||
uint8_t* listenBuff;
|
||||
XAxiDma* axiDmaPtr;
|
||||
DMA_CONFIG configs;
|
||||
}DMA_DESC;
|
||||
|
||||
/************************** Variable Definitions *****************************/
|
||||
|
||||
/************************** Function Prototypes ******************************/
|
||||
int32_t Dma_Init(DMA_DESC** instPtr, const DMA_CONFIG* configPtr);
|
||||
int32_t Dma_IrqEnable(DMA_DESC* instPtr);
|
||||
int32_t Dma_ListenEnable(DMA_DESC* instPtr, uint8_t* dataBuff);
|
||||
int32_t Dma_ListenDisable(DMA_DESC* instPtr);
|
||||
int32_t Dma_SendData(DMA_DESC* instPtr, uint8_t* dataBuff, int32_t dataLen);
|
||||
int32_t Dma_BlockingSendData(DMA_DESC* instPtr, uint8_t* dataBuff, int32_t dataLen);
|
||||
int32_t Dma_RecvData(DMA_DESC* instPtr, uint8_t* dataBuff, int32_t dataLen);
|
||||
int32_t Dma_BlockingRecvData(DMA_DESC* instPtr, uint8_t* dataBuff, int32_t dataLen);
|
||||
int32_t Dma_SendIrqHandler(DMA_DESC* instPtr);
|
||||
int32_t Dma_RecvIrqHandler(DMA_DESC* instPtr);
|
||||
#endif //AXI_DMA_H_
|
||||
Reference in New Issue
Block a user