Part Number: AM3352
Tool/software: Starterware
Hi Team,
My customer is using the AM3352 starterware as their application platform. The Version is AM335X_StarterWare_02_00_01_01.
Customer's application is using the AM3352 UART_EDMA demo. But during the application, they find that, if the UART_EDMA worked for a long time.
There could be a UART EDMA issue happened, which stop the application.
If the priority of the UART EDMA is set as the highest priority, the issue never happened now.
So I'm wondering if there is any similar issue reported about the UART EDMA. I would appreciate if anyone could help to provide some debugging approach. Many thanks!
+ customers' application file.
#include "uart_irda_cir.h"
#include "hw_cm_wkup.h"
#include "soc_AM335x.h"
#include "edma_event.h"
#include "beaglebone.h"
#include "interrupt.h"
#include "edma.h"
#include "uartStdio.h"
#include "Api_UartDma.h"
#include "CVTMath.h"
#include "Api_Crc.h"
#include "Api_FIFO.h"
#include "Api_Tim.h"
#include "Api_Mem.h"
#include "cache.h"
#define GetDmaRemainingNumber() (RX_BUFFER_SIZE - (short )EDMA3QdmaGetPaRAMEntry(SOC_EDMA30CC_0_REGS, EDMA3_UART_RX_CHA_NUM, EDMA3CC_PARAM_ENTRY_CCNT));
static void (*cb_Fxn[EDMA3_NUM_TCC]) (uint32_t tcc);
uint8_t g_UartRxBuffer[RX_BUFFER_SIZE];
uint8_t g_UartTxFifo[UART_FIFO_SIZE][TX_PACKET_SIZE];
uint16_t g_nUartTxLen[UART_FIFO_SIZE] = {0};
volatile uint8_t g_nUartTxFifoFront = 0;
volatile uint8_t g_nUartTxFifoBack = 0;
volatile uint8_t g_nUartTxFifoLen = 0;
volatile uint8_t g_bUartTxBusy = 0;
/*
* This function configures and sets the EDMA PaRAM set values for
* receiving data from UART RX FIFO.
*/
static void UARTRxEDMAPaRAMSetConfig(uint8_t *rxBuffer,
uint32_t length,
uint32_t tccNum,
unsigned short linkAddr,
uint32_t chNum)
{
EDMA3CCPaRAMEntry paramSet;
/* Fill the PaRAM Set with transfer specific information */
paramSet.srcAddr = (unsigned int)UART_THR_RHR_REG;
paramSet.destAddr = (unsigned int)rxBuffer;
paramSet.aCnt = (unsigned short)1;
paramSet.bCnt = (unsigned short)(RX_DMA_THRESHOLD);
paramSet.cCnt = (unsigned short)(length / RX_DMA_THRESHOLD);
paramSet.destBIdx = (short)1;
paramSet.destCIdx = (short)RX_DMA_THRESHOLD;
paramSet.srcBIdx = (short)0;
paramSet.srcCIdx = (short)0;
paramSet.linkAddr = 0x5FE0; //ͨ��255
paramSet.bCntReload = (unsigned short)0;
/* OPT PaRAM Entries. */
paramSet.opt = (unsigned int)0x0;
/* Source and Destination addressing modes are Incremental. */
/* Enable AB Synchronized Transfer. */
paramSet.opt |= (1 << EDMA3CC_OPT_SYNCDIM_SHIFT);
/* Setting the Transfer Complete Code(TCC). */
paramSet.opt |= ((tccNum << EDMA3CC_OPT_TCC_SHIFT) & EDMA3CC_OPT_TCC);
/* Enabling the Completion Interrupt. */
paramSet.opt |= (1 << EDMA3CC_OPT_TCINTEN_SHIFT);
/* Now write the PaRAM Set */
EDMA3SetPaRAM(SOC_EDMA30CC_0_REGS, chNum, ¶mSet);
EDMA3SetPaRAM(SOC_EDMA30CC_0_REGS, 255, ¶mSet);
}
#if 0
/*
* This configures the PaRAM set for the Dummy Transfer.
*/
static void TxDummyPaRAMConfEnable(void)
{
EDMA3CCPaRAMEntry dummyPaRAMSet;
EDMA3GetPaRAM(SOC_EDMA30CC_0_REGS, DUMMY_CH_NUM, &dummyPaRAMSet);
dummyPaRAMSet.aCnt = 1;
dummyPaRAMSet.bCnt = 0;
dummyPaRAMSet.cCnt = 0;
dummyPaRAMSet.srcAddr = 0;
dummyPaRAMSet.destAddr = 0;
dummyPaRAMSet.srcBIdx = 0;
dummyPaRAMSet.destBIdx = 0;
dummyPaRAMSet.srcCIdx = 0;
dummyPaRAMSet.destCIdx = 0;
dummyPaRAMSet.linkAddr = 0xFFFFu;
dummyPaRAMSet.bCntReload = 0;
dummyPaRAMSet.opt = 0;
EDMA3SetPaRAM(SOC_EDMA30CC_0_REGS, DUMMY_CH_NUM, &dummyPaRAMSet);
}
#endif
/*
** EDMA Completion Interrupt Service Routine(ISR).
*/
static void Edma3ComplHandlerIsr(void)
{
volatile uint32_t pendingIrqs;
uint32_t index = 1;
uint32_t count = 0;
if(EDMA3GetIntrStatus(SOC_EDMA30CC_0_REGS))
{
/*
** Wait for a finite time to monitor the EDMA Completion Interrupt
** status.
*/
while ((count < EDMA3CC_COMPL_HANDLER_RETRY_COUNT) && (index != 0u))
{
index = 0;
/* Get the Interrupt status. */
pendingIrqs = EDMA3GetIntrStatus(SOC_EDMA30CC_0_REGS);
while(pendingIrqs)
{
if((pendingIrqs & 1u) == TRUE)
{
/* Clear the interrupt status. */
EDMA3ClrIntr(SOC_EDMA30CC_0_REGS, index);
if(cb_Fxn[index] != NULL && index == EDMA3_UART_TX_CHA_NUM)
{
(*cb_Fxn[index])(index);
}
}
++index;
pendingIrqs >>= 1u;
}
count++;
}
}
}
/*
* EDMA Error Interrupt Service Routine(ISR).
*/
static void Edma3CCErrHandlerIsr(void)
{
volatile unsigned int pendingIrqs = 0;
uint32_t evtqueNum = 0;
uint32_t index = 1;
uint32_t Cnt = 0;
if((0 != EDMA3GetErrIntrStatus(SOC_EDMA30CC_0_REGS)) ||
(0 != (EDMA3GetCCErrStatus(SOC_EDMA30CC_0_REGS))))
{
UARTprintf("\r\n\r\nEdma3CCErrHandlerIsr\r\n\r\n\r\n\r\n");
/* Loop for EDMA3CC_ERR_HANDLER_RETRY_COUNT number of time, breaks
when no pending interrupt is found */
while ((Cnt < EDMA3CC_ERR_HANDLER_RETRY_COUNT) && (index != 0u))
{
index = 0u;
pendingIrqs = EDMA3GetErrIntrStatus(SOC_EDMA30CC_0_REGS);
while (pendingIrqs)
{
/*Process all the pending interrupts*/
if((pendingIrqs & 1u)==TRUE)
{
/* Writing to EMCR to clear the corresponding EMR bits.
Also clearing any Secondary events in SER. */
EDMA3ClrMissEvt(SOC_EDMA30CC_0_REGS, index);
if(index == EDMA3_UART_TX_CHA_NUM)
{//˵��TX�����쳣�ˣ���Ҫ�����ط���ǰ���ݰ���
//UARTprintf("1Err HandlerIsr!g_bUartTxBusy = %d,g_nUartTxFifoLen = %d \r\n",g_bUartTxBusy,g_nUartTxFifoLen);
g_bUartTxBusy = 0;
//if(g_nUartTxFifoLen > 0)
//UartDMATransmitData(g_UartTxFifo[g_nUartTxFifoFront], g_nUartTxLen[g_nUartTxFifoFront]);
}
}
++index;
pendingIrqs >>= 1u;
}
index = 0u;
pendingIrqs = EDMA3GetCCErrStatus(SOC_EDMA30CC_0_REGS);
if (pendingIrqs != 0u)
{
/* Process all the pending CC error interrupts. */
/* Queue threshold error for different event queues. */
for (evtqueNum = 0u; evtqueNum < EDMA3_0_NUM_EVTQUE; evtqueNum++)
{
if((pendingIrqs & (1u << evtqueNum)) != 0u)
{
/* Clear the error interrupt. */
EDMA3ClrCCErr(SOC_EDMA30CC_0_REGS, (1u << evtqueNum));
}
}
/* Transfer completion code error. */
if ((pendingIrqs & (1 << EDMA3CC_CCERR_TCCERR_SHIFT)) != 0u)
{
EDMA3ClrCCErr(SOC_EDMA30CC_0_REGS,
(0x01u << EDMA3CC_CCERR_TCCERR_SHIFT));
}
++index;
}
Cnt++;
}
/* Enable error to be evaluated again */
EDMA3CCErrorEvaluate(SOC_EDMA30CC_0_REGS);
}
}
/*
* This function configures the AINTC to receive EDMA3 interrupts.
*/
static void ConfigureAINTCIntEDMA3(void)
{
/* Registering EDMA3 Channel Controller 0 transfer completion interrupt. */
IntRegister(SYS_INT_EDMACOMPINT, Edma3ComplHandlerIsr);
/* Setting the priority for EDMA3CC0 completion interrupt in AINTC. */
IntPrioritySet(SYS_INT_EDMACOMPINT, 0, AINTC_HOSTINT_ROUTE_IRQ);
/* Enabling the EDMA3CC0 completion interrupt in AINTC. */
IntSystemEnable(SYS_INT_EDMACOMPINT);
/* Registering EDMA3 Channel Controller 0 Error Interrupt. */
IntRegister(SYS_INT_EDMAERRINT, Edma3CCErrHandlerIsr);
/* Setting the priority for EDMA3CC0 Error interrupt in AINTC. */
IntPrioritySet(SYS_INT_EDMAERRINT, 0, AINTC_HOSTINT_ROUTE_IRQ);
/* Enabling the EDMA3CC0 Error interrupt in AINTC. */
IntSystemEnable(SYS_INT_EDMAERRINT);
}
/*
** Powering up, initializing and registering interrupts for EDMA.
*/
static void EDMA3Initialize(void)
{
/* Initialization of EDMA3 */
EDMA3Init(SOC_EDMA30CC_0_REGS, EVT_QUEUE_NUM);
/* Register EDMA3 Interrupts */
ConfigureAINTCIntEDMA3();
}
/*
** A wrapper function performing Baud Rate settings.
*/
static void UartBaudRateSet(void)
{
uint32_t divisorValue = 0;
/* Computing the Divisor Value. */
divisorValue = UARTDivisorValCompute(UART_MODULE_INPUT_CLK,
BAUD_RATE_115200,
UART16x_OPER_MODE,
UART_MIR_OVERSAMPLING_RATE_42);
/* Programming the Divisor Latches. */
UARTDivisorLatchWrite(UART_INSTANCE_BASE_ADD, divisorValue);
}
/*
** This function initializes the UART instance for use.
*/
static void UARTInitialize(void)
{
/* Performing a module reset. */
UARTModuleReset(UART_INSTANCE_BASE_ADD);
/* Enabling DMA Mode 1. */
UARTDMAEnable(UART_INSTANCE_BASE_ADD, UART_DMA_MODE_1_ENABLE);
/* Performing Baud Rate settings. */
UartBaudRateSet();
/* Switching to Configuration Mode B. */
UARTRegConfigModeEnable(UART_INSTANCE_BASE_ADD, UART_REG_CONFIG_MODE_B);
/* Programming the Line Characteristics. */
UARTLineCharacConfig(UART_INSTANCE_BASE_ADD,
(UART_FRAME_WORD_LENGTH_8 | UART_FRAME_NUM_STB_1),
UART_PARITY_NONE);
/* Disabling write access to Divisor Latches. */
UARTDivisorLatchDisable(UART_INSTANCE_BASE_ADD);
/* Disabling Break Control. */
UARTBreakCtl(UART_INSTANCE_BASE_ADD, UART_BREAK_COND_DISABLE);
/* Switching to UART16x operating mode. */
UARTOperatingModeSelect(UART_INSTANCE_BASE_ADD, UART16x_OPER_MODE);
}
/*
** This function is used to set the PaRAM entries in EDMA3 for the Transmit Channel
** of UART. EDMA3 Enable Transfer is also called within this API.
*/
int32_t UartDMATransmitData(uint8_t* pBuf, uint32_t nLen)
{
EDMA3CCPaRAMEntry paramSet;
CacheDataCleanBuff((uint32_t)pBuf, (uint32_t)nLen); //ȷ��Cache��������Memoryһ��
if(nLen == 0)
{
UARTprintf("UART Send Data Len = %d\r\n\r\n\r\n",nLen);
return nLen;
}
/* Fill the PaRAM Set with transfer specific information */
paramSet.srcAddr = (unsigned int)pBuf;
paramSet.destAddr = UART_THR_RHR_REG;
#if 0
paramSet.aCnt = (unsigned short)nLen;
paramSet.bCnt = 1u;
paramSet.cCnt = 1u;
/* The src index should increment for every byte being transferred. */
paramSet.srcBIdx = 1u;
#else
paramSet.aCnt = 1u;
paramSet.bCnt = 1u;//(unsigned short)nLen;//(nLen+1)/2;//(unsigned short)(nLen+paramSet.aCnt-1)/paramSet.aCnt;
paramSet.cCnt = (unsigned short)nLen;
/* The src index should increment for every byte being transferred. */
paramSet.srcBIdx = 1u;
#endif
/* The dst index should not be increment since it is a h/w register*/
paramSet.destBIdx = 0u;
/* A sync Transfer Mode */
paramSet.srcCIdx = 1u ;
paramSet.destCIdx = 0u;
paramSet.linkAddr = (unsigned short)0xffff;//(unsigned short)(EDMA3CC_OPT(DUMMY_CH_NUM)); //
paramSet.bCntReload = 0u;
paramSet.opt = 0x00000000u;
paramSet.opt |= ((1 << EDMA3CC_OPT_SYNCDIM_SHIFT) & EDMA3CC_OPT_SYNCDIM); //AB
paramSet.opt |= ((EDMA3_UART_TX_CHA_NUM << EDMA3CC_OPT_TCC_SHIFT) & EDMA3CC_OPT_TCC);
paramSet.opt |= (1 << EDMA3CC_OPT_TCINTEN_SHIFT);
/* Now write the PaRAM Set */
EDMA3SetPaRAM(SOC_EDMA30CC_0_REGS, EDMA3_UART_TX_CHA_NUM, ¶mSet);
/* Configuring the PaRAM set for Dummy Transfer. */
//TxDummyPaRAMConfEnable();
/* Enable EDMA Transfer */
EDMA3EnableTransfer(SOC_EDMA30CC_0_REGS, EDMA3_UART_TX_CHA_NUM, EDMA3_TRIG_MODE_EVENT);
return nLen;
}
/*
* This function is used as a callback from EDMA3 Completion Handler.
*/
void UartTXcallback(uint32_t tccNum)
{
EDMA3DisableTransfer(SOC_EDMA30CC_0_REGS, tccNum, EDMA3_TRIG_MODE_EVENT);
#if (TX_PACKET_SIZE > 0 && UART_FIFO_SIZE > 0)
if(g_nUartTxFifoLen > 0)
{
#if 0
g_nUartTxFifoLen--;
g_nUartTxFifoFront = (g_nUartTxFifoFront + 1) % UART_FIFO_SIZE;
#endif
UartDMATransmitData(g_UartTxFifo[g_nUartTxFifoFront], g_nUartTxLen[g_nUartTxFifoFront]);
#if 1
g_nUartTxFifoFront = (g_nUartTxFifoFront + 1) % UART_FIFO_SIZE;
g_nUartTxFifoLen--;
#endif
}
else
{
g_bUartTxBusy = 0;
}
#endif
}
/*
* \brief This function is used to initialize and configure UART Module.
* \this uart is used for debug.
* \param none.
*
* \return none
*/
void UARTSetup(void)
{
volatile unsigned int regVal;
/* Enable clock for UART0 */
regVal = (HWREG(SOC_CM_WKUP_REGS + CM_WKUP_UART0_CLKCTRL) &
~(CM_WKUP_UART0_CLKCTRL_MODULEMODE));
regVal |= CM_WKUP_UART0_CLKCTRL_MODULEMODE_ENABLE;
HWREG(SOC_CM_WKUP_REGS + CM_WKUP_UART0_CLKCTRL) = regVal;
UARTStdioInit();
}
/*
*����1��ʼ��
*/
int UartDMAInit(void)
{
uint8_t i = 0;
UARTPinMuxSetup(1); /* Performing Pin Multiplexing for UART1 instance. */
UART1ModuleClkConfig(); /* Configuring the system clocks for UART1 instance. */
EDMAModuleClkConfig(); /* Configuring the system clocks for EDMA. */
UARTInitialize(); /* Initializing the UART1 instance for use. */
EDMA3Initialize(); /* Initializing the EDMA. */
/* Request DMA Channel and TCC for UART Transmit*/
EDMA3RequestChannel(SOC_EDMA30CC_0_REGS, EDMA3_CHANNEL_TYPE_DMA,
EDMA3_UART_TX_CHA_NUM, EDMA3_UART_TX_CHA_NUM,
EVT_QUEUE_NUM);
for(i = 0; i<EDMA3_NUM_TCC; i++)
{
cb_Fxn[i] = NULL;
}
/* Registering Callback Function for TX*/
cb_Fxn[EDMA3_UART_TX_CHA_NUM] = &UartTXcallback;
cb_Fxn[EDMA3_UART_RX_CHA_NUM] = NULL;
/****************** ���ô���DMA�Ľ��ղ��� ********************/
UARTDMAEnable(UART_INSTANCE_BASE_ADD, UART_DMA_MODE_1_ENABLE); /* Enabling DMA Mode 1. */
UARTRxEDMAPaRAMSetConfig(g_UartRxBuffer, RX_BUFFER_SIZE, EDMA3_UART_RX_CHA_NUM, 0xFFFF, EDMA3_UART_RX_CHA_NUM); /* Configuring the PaRAM set for reception. */
EDMA3EnableTransfer(SOC_EDMA30CC_0_REGS, EDMA3_UART_RX_CHA_NUM, EDMA3_TRIG_MODE_EVENT); /* Enable EDMA Transfer */
return 0;
}
/*
*�رմ���
*/
void UART_Close(void)
{
//�ر�ǰȷ�����������Ѿ��������
while((UART_LSR_TX_SR_E | UART_LSR_TX_FIFO_E) !=
(HWREG(UART_INSTANCE_BASE_ADD + UART_LSR) & (UART_LSR_TX_SR_E | UART_LSR_TX_FIFO_E)));
/* Request DMA Channel and TCC for UART Transmit*/
EDMA3FreeChannel(SOC_EDMA30CC_0_REGS, EDMA3_CHANNEL_TYPE_DMA,
EDMA3_UART_TX_CHA_NUM, EDMA3_UART_TX_CHA_NUM,
EDMA3_TRIG_MODE_EVENT, EVT_QUEUE_NUM);
/* Request DMA Channel and TCC for UART Receive */
EDMA3FreeChannel(SOC_EDMA30CC_0_REGS, EDMA3_CHANNEL_TYPE_DMA,
EDMA3_UART_RX_CHA_NUM, EDMA3_UART_RX_CHA_NUM,
EDMA3_TRIG_MODE_EVENT, EVT_QUEUE_NUM);
//�رմ����������
UARTDMADisable(UART_INSTANCE_BASE_ADD);
EDMA3DisableTransfer(SOC_EDMA30CC_0_REGS, EDMA3_UART_RX_CHA_NUM, EDMA3_TRIG_MODE_EVENT);
EDMA3DisableTransfer(SOC_EDMA30CC_0_REGS, EDMA3_UART_TX_CHA_NUM, EDMA3_TRIG_MODE_EVENT);
IntSystemDisable(SYS_INT_EDMACOMPINT); /* Disabling the EDMA3CC0 completion interrupt in AINTC. */
IntSystemDisable(SYS_INT_EDMAERRINT); /* Disabling the EDMA3CC0 Error interrupt in AINTC. */
}
int32_t UartSendPacket(uint8_t *pBuf, int16_t nLen)
{
if(nLen == 0)
{
//UARTprintf("1UART Send Data Len = %d\r\n\r\n\r\n",nLen);
return 0;
}
#if (TX_PACKET_SIZE > 0 && UART_FIFO_SIZE > 0)
if(g_nUartTxFifoLen >= UART_FIFO_SIZE)
{
//UARTprintf("1 UART FIFO Over!g_bUartTxIntnumber = %d,g_bUartTxSendnumber = %d ISR = %d\r\n",g_bUartTxIntnumber,g_bUartTxSendnumber,EDMA3GetIntrStatus(SOC_EDMA30CC_0_REGS));
DelayMs(g_nUartTxFifoLen * 1);
//UARTprintf("2 UART FIFO Over!g_bUartTxBusy = %d,g_nUartTxFifoLen = %d ISR = %d\r\n",g_bUartTxBusy,g_nUartTxFifoLen,EDMA3GetIntrStatus(SOC_EDMA30CC_0_REGS));
if(g_nUartTxFifoLen >= UART_FIFO_SIZE)
{
g_nUartTxFifoLen--;
g_nUartTxFifoFront = (g_nUartTxFifoFront + 1) % UART_FIFO_SIZE;
g_bUartTxBusy = 0;
}
}
MemCpy(g_UartTxFifo[g_nUartTxFifoBack], pBuf, nLen);
g_nUartTxLen[g_nUartTxFifoBack] = nLen;
g_nUartTxFifoBack = (g_nUartTxFifoBack + 1) % UART_FIFO_SIZE;
IntSystemDisable(SYS_INT_EDMACOMPINT);
g_nUartTxFifoLen++;
IntSystemEnable(SYS_INT_EDMACOMPINT);
if(g_bUartTxBusy == 0)
{
g_bUartTxBusy = 1;
UartDMATransmitData(g_UartTxFifo[g_nUartTxFifoFront], g_nUartTxLen[g_nUartTxFifoFront]);
#if 1
g_nUartTxFifoLen--;
g_nUartTxFifoFront = (g_nUartTxFifoFront + 1) % UART_FIFO_SIZE;
#endif
}
return nLen;
#else
return 0;
#endif
}
int32_t UartReceiveData(uint8_t *pBuf, uint32_t nLen)
{
static int32_t s_nLastIndex = 0;
int32_t nCurIndex;
int32_t nIndex = 0;
int32_t i = 0;
nCurIndex = GetDmaRemainingNumber();
/*
*ȷ��Cache������Memoryһ��,��ֹ����������
*�˾������ڻ�ȡnCurIndex֮�������֣���ͬ���꣬����һ�����ݼ���ʱ���¼�������δ��ͬ����
*/
CacheDataInvalidateBuff((uint32_t)g_UartRxBuffer, (uint32_t)sizeof(g_UartRxBuffer));
for(i = s_nLastIndex; i != nCurIndex && nIndex < nLen; i = (i + 1) % RX_BUFFER_SIZE)
{
pBuf[nIndex++] = g_UartRxBuffer[i];
}
s_nLastIndex = nCurIndex;
return nIndex;
}
/******************************** End of file *******************************/