Hi Guys,
I'm struggling in getting the EDMA to work on UART1 on the OMAPL138. I have an example (from Starterware) running using UART2 and this is going fine. Now I'd like to change this example to use UART1. I have modified the code to use UART1 but transmitting data does not succeed (no interrupt is thrown when finished). I am not sure whether I configured everything properly. Note that UART1 is working well when just using the ISR without EDMA. My code is given below.
So basic questions:
- Is it possible at all to use EDMA for UART1?
- What am I doing wrong?
Thanks in advance!
Best regards,
Jeroen
/**
* \file uartEcho.c
*
* \brief This is a sample application file which invokes some APIs
* from the EDMA3 device abstraction layer as well as UART
* device abstraction layer to perform configuration, and
* transfer of data between UART and CPU RAM by the
* use of EDMA3
*/
/*
* Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
*
* Neither the name of Texas Instruments Incorporated nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "psc.h"
#include "uart.h"
#include "edma.h"
#include "string.h"
#include "hw_types.h"
#include "uartStdio.h"
#include "evmOMAPL138.h"
#include "interrupt.h"
#include "edma_event.h"
#include "soc_OMAPL138.h"
#include "hw_psc_OMAPL138.h"
/****************************************************************************/
/* INTERNAL MACRO DEFINITIONS */
/****************************************************************************/
#define UART_RBR_THR_REG ((0x01D0D000u) + (0u))
#define MAX_ACNT 1
#define MAX_CCNT 1
#define RX_BUFFER_SIZE 50
/* EDMA3 Event queue number. */
#define EVT_QUEUE_NUM 0
#define BAUD_RATE 115200
/****************************************************************************/
/* LOCAL FUNCTION PROTOTYPES */
/****************************************************************************/
static void UartTransmitData(unsigned int tccNum, unsigned int chNum,
volatile char *buffer, unsigned int buffLength);
/* Callback Function Declaration*/
static void (*cb_Fxn[EDMA3_NUM_TCC]) (unsigned int tcc, unsigned int status);
static void UartReceiveData(unsigned int tccNum, unsigned int chNum,
volatile char *buffer);
static void callback(unsigned int tccNum, unsigned int status);
static void ConfigureIntEDMA3(void);
static void Edma3ComplHandlerIsr(void);
static void Edma3CCErrHandlerIsr(void);
static void EDMA3Initialize(void);
static void SetupInt(void);
/****************************************************************************/
/* GLOBAL VARIABLES */
/****************************************************************************/
volatile unsigned int flag = 0;
/****************************************************************************/
/* LOCAL FUNCTION DEFINITIONS */
/****************************************************************************/
/*
** Main function.
*/
static void initUART1(unsigned int baudRate, unsigned int rxTrigLevel)
{
/* Enabling the PSC for UARTs.*/
PSCModuleControl(SOC_PSC_1_REGS, HW_PSC_UART1, PSC_POWERDOMAIN_ALWAYS_ON,
PSC_MDCTL_NEXT_ENABLE);
/* Setup PINMUX */
UARTPinMuxSetup(1, FALSE);
/* Enabling the transmitter and receiver*/
UARTEnable(SOC_UART_1_REGS);
/* Configuring the UART parameters*/
UARTConfigSetExpClk(SOC_UART_1_REGS, SOC_UART_1_MODULE_FREQ,
BAUD_RATE, UART_WORDL_8BITS,
UART_OVER_SAMP_RATE_16);
/* Enabling the FIFO and flushing the Tx and Rx FIFOs.*/
UARTFIFOEnable(SOC_UART_1_REGS);
/* Setting the UART Receiver Trigger Level*/
UARTFIFOLevelSet(SOC_UART_1_REGS, rxTrigLevel);
}
int main(void)
{
volatile char enter[] = {170, 7, 0, 42, 1, 50, 239};
volatile char buffer[RX_BUFFER_SIZE];
unsigned int buffLength = 0;
/* Initialize EDMA3 Controller */
EDMA3Initialize();
/* Initialize UARTs */
initUART1(BAUD_RATE, UART_RX_TRIG_LEVEL_1);
/* Request DMA Channel and TCC for UART Transmit*/
EDMA3RequestChannel(SOC_EDMA30CC_0_REGS, EDMA3_CHANNEL_TYPE_DMA,
EDMA3_CHA_UART1_TX, EDMA3_CHA_UART1_TX,
EVT_QUEUE_NUM);
/* Registering Callback Function for TX*/
cb_Fxn[EDMA3_CHA_UART1_TX] = &callback;
/* Request DMA Channel and TCC for UART Receive */
EDMA3RequestChannel(SOC_EDMA30CC_0_REGS, EDMA3_CHANNEL_TYPE_DMA,
EDMA3_CHA_UART1_RX, EDMA3_CHA_UART1_RX,
EVT_QUEUE_NUM);
/* Registering Callback Function for RX*/
cb_Fxn[EDMA3_CHA_UART1_RX] = &callback;
/* Used for bCnt */
buffLength = strlen((const char *) enter);
/* Transmit Data for Enter Message */
UartTransmitData(EDMA3_CHA_UART1_TX, EDMA3_CHA_UART1_TX,
enter, buffLength);
/* Enabling UART in DMA Mode*/
UARTDMAEnable(SOC_UART_1_REGS, UART_RX_TRIG_LEVEL_1 | \
UART_DMAMODE | \
UART_FIFO_MODE );
/* Wait for control to return from call-back function */
while(0 == flag);
flag = 0;
/* Receive Data for Input */
UartReceiveData(EDMA3_CHA_UART1_RX, EDMA3_CHA_UART1_RX, buffer);
/* Enabling UART in DMA Mode*/
UARTDMAEnable(SOC_UART_1_REGS, UART_RX_TRIG_LEVEL_1 | \
UART_DMAMODE | \
UART_FIFO_MODE );
/* Wait for return from callback */
while(0 == flag);
flag = 0;
/* Transmit Data for Entered value */
UartTransmitData(EDMA3_CHA_UART1_TX, EDMA3_CHA_UART1_TX,
buffer, RX_BUFFER_SIZE);
/* Enabling UART in DMA Mode*/
UARTDMAEnable(SOC_UART_1_REGS, UART_RX_TRIG_LEVEL_1 | \
UART_DMAMODE | \
UART_FIFO_MODE );
/* Wait for return from callback */
while(0 == flag);
flag = 0;
/* Free EDMA3 Channels for TX and RX */
EDMA3FreeChannel(SOC_EDMA30CC_0_REGS, EDMA3_CHANNEL_TYPE_DMA,
EDMA3_CHA_UART1_TX, EDMA3_TRIG_MODE_EVENT,
EDMA3_CHA_UART1_TX, EVT_QUEUE_NUM);
EDMA3FreeChannel(SOC_EDMA30CC_0_REGS, EDMA3_CHANNEL_TYPE_DMA,
EDMA3_CHA_UART1_RX, EDMA3_TRIG_MODE_EVENT,
EDMA3_CHA_UART1_RX, EVT_QUEUE_NUM);
while(1);
}
/*
** 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.
*/
static void UartTransmitData(unsigned int tccNum, unsigned int chNum,
volatile char *buffer, unsigned int buffLength)
{
EDMA3CCPaRAMEntry paramSet;
/* Fill the PaRAM Set with transfer specific information */
paramSet.srcAddr = (unsigned int) buffer;
paramSet.destAddr = UART_RBR_THR_REG;
paramSet.aCnt = MAX_ACNT;
paramSet.bCnt = (unsigned short) buffLength;
paramSet.cCnt = MAX_CCNT;
/* The src index should increment for every byte being transferred. */
paramSet.srcBIdx = (short) 1u;
/* The dst index should not be increment since it is a h/w register*/
paramSet.destBIdx = (short) 0u;
/* A sync Transfer Mode */
paramSet.srcCIdx = (short) 0u;
paramSet.destCIdx = (short) 0u;
paramSet.linkAddr = (unsigned short)0xFFFFu;
paramSet.bCntReload = (unsigned short)0u;
paramSet.opt = 0x00000000u;
paramSet.opt |= (EDMA3CC_OPT_DAM );
paramSet.opt |= ((tccNum << EDMA3CC_OPT_TCC_SHIFT) & EDMA3CC_OPT_TCC);
paramSet.opt |= (1 << EDMA3CC_OPT_TCINTEN_SHIFT);
/* Now write the PaRAM Set */
EDMA3SetPaRAM(SOC_EDMA30CC_0_REGS, chNum, ¶mSet);
/* Enable EDMA Transfer */
EDMA3EnableTransfer(SOC_EDMA30CC_0_REGS, chNum, EDMA3_TRIG_MODE_EVENT);
}
/*
** This function is used to set the PARAM SET of EDMA3 for the Receive Channel
** of UART. EDMA3 Enable Transfer is also called within this API.
*/
static void UartReceiveData(unsigned int tccNum, unsigned int chNum,
volatile char *buffer)
{
EDMA3CCPaRAMEntry paramSet;
/* Fill the PaRAM Set with transfer specific information */
paramSet.srcAddr = UART_RBR_THR_REG;
paramSet.destAddr = (unsigned int) buffer;
paramSet.aCnt = MAX_ACNT;
paramSet.bCnt = RX_BUFFER_SIZE;
paramSet.cCnt = MAX_CCNT;
/* The src index should not be increment since it is a h/w register*/
paramSet.srcBIdx = 0;
/* The dest index should incremented for every byte */
paramSet.destBIdx = 1;
/* A sync Transfer Mode */
paramSet.srcCIdx = 0;
paramSet.destCIdx = 0;
paramSet.linkAddr = (unsigned short)0xFFFFu;
paramSet.bCntReload = 0;
paramSet.opt = 0x00000000u;
paramSet.opt |= ((EDMA3CC_OPT_SAM) << EDMA3CC_OPT_SAM_SHIFT);
paramSet.opt |= ((tccNum << EDMA3CC_OPT_TCC_SHIFT) & EDMA3CC_OPT_TCC);
paramSet.opt |= (1 << EDMA3CC_OPT_TCINTEN_SHIFT);
/* Now write the PaRAM Set */
EDMA3SetPaRAM(SOC_EDMA30CC_0_REGS, chNum, ¶mSet);
/* Enable EDMA Transfer */
EDMA3EnableTransfer(SOC_EDMA30CC_0_REGS, chNum, EDMA3_TRIG_MODE_EVENT);
}
/* Function used to Initialize EDMA3 */
static void EDMA3Initialize(void)
{
/* Enabling the PSC for EDMA3CC_0.*/
PSCModuleControl(SOC_PSC_0_REGS, HW_PSC_CC0, PSC_POWERDOMAIN_ALWAYS_ON,
PSC_MDCTL_NEXT_ENABLE);
/* Enabling the PSC for EDMA3TC_0.*/
PSCModuleControl(SOC_PSC_0_REGS, HW_PSC_TC0, PSC_POWERDOMAIN_ALWAYS_ON,
PSC_MDCTL_NEXT_ENABLE);
/* Initialization of EDMA3 */
EDMA3Init(SOC_EDMA30CC_0_REGS, EVT_QUEUE_NUM);
/*
** Enable AINTC to handle interuppts. Also enable IRQ interuppt in
** ARM processor.
*/
SetupInt();
/* Register EDMA3 Interrupts */
ConfigureIntEDMA3();
}
/* Function used to Setup ARM Interuppt Controller */
static void SetupInt(void)
{
#ifdef _TMS320C6X
// Initialize the DSP Interrupt controller
IntDSPINTCInit();
// Enable DSP interrupts globally
IntGlobalEnable();
#else
/*Initialize the ARM Interrupt Controller(AINTC). */
IntAINTCInit();
/* Enable IRQ in CPSR.*/
IntMasterIRQEnable();
/* Enable the interrupts in GER of AINTC.*/
IntGlobalEnable();
/* Enable the interrupts in HIER of AINTC.*/
IntIRQEnable();
#endif
}
/* EDMA3 Completion Handler */
static void edma3ComplHandler(unsigned int baseAdd, unsigned int regionNum)
{
volatile unsigned int pendingIrqs;
volatile unsigned int isIPR = 0;
unsigned int indexl;
unsigned int Cnt = 0;
indexl = 1;
#ifdef _TMS320C6X
IntEventClear(SYS_INT_EDMA3_0_CC0_INT1);
#else
IntSystemStatusClear(SYS_INT_CCINT0);
#endif
isIPR = HWREG(baseAdd + EDMA3CC_S_IPR(regionNum));
if(isIPR)
{
while ((Cnt < EDMA3CC_COMPL_HANDLER_RETRY_COUNT)&& (indexl != 0u))
{
indexl = 0u;
pendingIrqs = HWREG(baseAdd + EDMA3CC_S_IPR(regionNum));
while (pendingIrqs)
{
if((pendingIrqs & 1u) == TRUE)
{
/**
* If the user has not given any callback function
* while requesting the TCC, its TCC specific bit
* in the IPR register will NOT be cleared.
*/
/* here write to ICR to clear the corresponding IPR bits */
HWREG(baseAdd + EDMA3CC_S_ICR(regionNum)) = (1u << indexl);
(*cb_Fxn[indexl])(indexl, EDMA3_XFER_COMPLETE);
}
++indexl;
pendingIrqs >>= 1u;
}
Cnt++;
}
}
}
static void Edma3ComplHandlerIsr(void)
{
#ifdef _TMS320C6X
// Invoke Completion Handler ISR
edma3ComplHandler(SOC_EDMA30CC_0_REGS, 1);
#else
/* Invoke Completion Handler ISR */
edma3ComplHandler(SOC_EDMA30CC_0_REGS, 0);
#endif
}
/* EDMA3 Error Handler */
static void edma3CCErrHandler(unsigned int baseAdd)
{
volatile unsigned int pendingIrqs = 0;
unsigned int regionNum = 0;
unsigned int evtqueNum = 0;
unsigned int index = 1;
unsigned int Cnt = 0;
#ifdef _TMS320C6X
IntEventClear(SYS_INT_EDMA3_0_CC0_ERRINT);
#else
IntSystemStatusClear(SYS_INT_CCERRINT);
#endif
if((HWREG(baseAdd + EDMA3CC_EMR) != 0 ) || \
(HWREG(baseAdd + EDMA3CC_QEMR) != 0) || \
(HWREG(baseAdd + EDMA3CC_CCERR) != 0))
{
/* 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 = HWREG(baseAdd + EDMA3CC_EMR);
while (pendingIrqs)
{
/*Process all the pending interrupts*/
if((pendingIrqs & 1u)==TRUE)
{
/* Write to EMCR to clear the corresponding EMR bits.*/
HWREG(baseAdd + EDMA3CC_EMCR) = (1u<<index);
/*Clear any SER*/
HWREG(baseAdd + EDMA3CC_S_SECR(regionNum)) = (1u<<index);
}
++index;
pendingIrqs >>= 1u;
}
index = 0u;
pendingIrqs = HWREG(baseAdd + EDMA3CC_QEMR);
while (pendingIrqs)
{
/*Process all the pending interrupts*/
if((pendingIrqs & 1u)==TRUE)
{
/* Here write to QEMCR to clear the corresponding QEMR bits*/
HWREG(baseAdd + EDMA3CC_QEMCR) = (1u<<index);
/*Clear any QSER*/
HWREG(baseAdd + EDMA3CC_S_QSECR(0)) = (1u<<index);
}
++index;
pendingIrqs >>= 1u;
}
index = 0u;
pendingIrqs = HWREG(baseAdd + EDMA3CC_CCERR);
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. */
HWREG(baseAdd + EDMA3CC_CCERRCLR) = (1u << evtqueNum);
}
}
/* Transfer completion code error. */
if ((pendingIrqs & (1 << EDMA3CC_CCERR_TCCERR_SHIFT)) != 0u)
{
HWREG(baseAdd + EDMA3CC_CCERRCLR) = \
(0x01u << EDMA3CC_CCERR_TCCERR_SHIFT);
}
++index;
}
Cnt++;
}
}
}
static void Edma3CCErrHandlerIsr()
{
/* Invoke CC Error Handler ISR */
edma3CCErrHandler(SOC_EDMA30CC_0_REGS);
}
/* Function to register EDMA3 Interuppts */
static void ConfigureIntEDMA3(void)
{
/* Register Interrupts Here */
//Note: _TMS320C6X is defined
#ifdef _TMS320C6X
IntRegister(C674X_MASK_INT4, Edma3ComplHandlerIsr);
IntRegister(C674X_MASK_INT5, Edma3CCErrHandlerIsr);
IntEventMap(C674X_MASK_INT4, SYS_INT_EDMA3_0_CC0_INT1);
IntEventMap(C674X_MASK_INT5, SYS_INT_EDMA3_0_CC0_ERRINT);
IntEnable(C674X_MASK_INT4);
IntEnable(C674X_MASK_INT5);
#else
IntRegister(SYS_INT_CCINT0, Edma3ComplHandlerIsr);
IntChannelSet(SYS_INT_CCINT0, 2);
IntSystemEnable(SYS_INT_CCINT0);
IntRegister(SYS_INT_CCERRINT, Edma3CCErrHandlerIsr);
IntChannelSet(SYS_INT_CCERRINT, 2);
IntSystemEnable(SYS_INT_CCERRINT);
#endif
}
/*
** This function is used as a callback from EDMA3 Completion Handler.
** UART in DMA Mode is Disabled over here.
*/
static void callback(unsigned int tccNum, unsigned int status)
{
UARTDMADisable(SOC_UART_1_REGS, (UART_RX_TRIG_LEVEL_1 | UART_FIFO_MODE));
flag = 1;
}
/********************************* End of file ******************************/