Part Number: TMS570LS3137
I am getting lost with DMA configuration for the SCI UART reception.
I have timing issue with SCI reception in interrupt mode. As SCI do not have any FIFO, I want to use DMA to gain performances and avoid data lost.
The UART may receive messages with various byte length and I don't have found a DMA channel settings which I could define a kind of timeout when transfer is started.
My guess was to use multiple DMA channels chained in a ring, but it does not work as I am expected.
Here is my DMA initialization and interrupt code:
#if ((__little_endian__ == 1) || (__LITTLE_ENDIAN__ == 1))
#define SCI_TX_ADDR ((uint32_t)(&(sciREG->TD)))
#define SCI_RX_ADDR ((uint32_t)(&(sciREG->RD)))
#else
#define SCI_TX_ADDR ((uint32_t)(&(sciREG->TD)) + 3)
#define SCI_RX_ADDR ((uint32_t)(&(sciREG->RD)) + 3)
#endif
#define SCI_SET_TX_DMA (1<<16)
#define SCI_SET_RX_DMA (1<<17)
#define SCI_SET_RX_DMA_ALL (1<<18)
#define SCI_TX_DMA_CH DMA_CH0
#define SCI_RX_DMA_COUNT (4u)
#define SCI_RX_DMA_CH_FIRST (SCI_TX_DMA_CH + 1)
#define SCI_RX_DMA_CH_LAST (SCI_RX_DMA_CH_FIRST + SCI_RX_DMA_COUNT)
#define DMA_LIN_RX (28u)
#define DMA_LIN_TX (29u)
#define DMA_SCI_RX (30u)
#define DMA_SCI_TX (31u)
#define SERIAL_DMA_BUFF_SIZE (UART_MAX_MSG_LEN)
uint8_t serial_Rx_buf[SCI_RX_DMA_COUNT];
g_dmaCTRL g_dmaCTRLPKT_Rx[SCI_RX_DMA_COUNT];
void serial_dma_init(void)
{
int i;
g_dmaCTRL *dmactrl = g_dmaCTRLPKT_Rx;
for(i = 0; i < SCI_RX_DMA_COUNT; ++i, ++dmactrl)
{
dmactrl->SADD = SCI_RX_ADDR; /* source address */
dmactrl->DADD = (uint32)(serial_Rx_buf+i); /* destination address */
dmactrl->CHCTRL = (SCI_RX_DMA_CH_FIRST + ((i + 1) % SCI_RX_DMA_COUNT)) + 1; /* next channel to be triggered */
dmactrl->FRCNT = 1; /* frame count */
dmactrl->ELCNT = 1; /* element count */
dmactrl->ELDOFFSET = 0; /* element destination offset */
dmactrl->ELSOFFSET = 0; /* element destination offset */
dmactrl->FRDOFFSET = 0; /* frame destination offset */
dmactrl->FRSOFFSET = 0; /* frame destination offset */
dmactrl->PORTASGN = 4; /* port b */
dmactrl->RDSIZE = ACCESS_8_BIT; /* read size */
dmactrl->WRSIZE = ACCESS_8_BIT; /* write size */
dmactrl->TTYPE = FRAME_TRANSFER; /* transfer type */
dmactrl->ADDMODERD = ADDR_FIXED; /* address mode read */
dmactrl->ADDMODEWR = ADDR_FIXED; /* address mode write */
dmactrl->AUTOINIT = AUTOINIT_OFF; /* autoinit */
dmaSetCtrlPacket(SCI_RX_DMA_CH_FIRST+i, dmactrl);
dmaEnableInterrupt(SCI_RX_DMA_CH_FIRST+i, BTC);
dmaSetChEnable(SCI_RX_DMA_CH_FIRST+i, DMA_HW);
dmaReqAssign(SCI_RX_DMA_CH_FIRST+i, DMA_SCI_RX);
}
sciREG->SETINT |= SCI_SET_RX_DMA | SCI_SET_RX_DMA_ALL;
dmaEnable();
}
void dmaGroupANotification(dmaInterrupt_t inttype, uint32 channel)
{
static portBASE_TYPE xHigherPriorityTaskWoken;
static uint8_t byte;
xHigherPriorityTaskWoken = pdFALSE;
switch(channel)
{
case SCI_TX_DMA_CH:
xSemaphoreGiveFromISR(uart_tx_sema4, &xHigherPriorityTaskWoken);
break;
case SCI_RX_DMA_CH_FIRST:
case SCI_RX_DMA_CH_FIRST+1:
case SCI_RX_DMA_CH_FIRST+2:
case SCI_RX_DMA_CH_FIRST+3:
byte = serial_Rx_buf[channel-SCI_RX_DMA_CH_FIRST];
xQueueSendFromISR(xRxedChars, &byte, &xHigherPriorityTaskWoken );
dmaSetChEnable(channel, DMA_HW);
break;
}
// If xHigherPriorityTaskWoken is now set to pdTRUE then a context
// switch should be requested. The macro used is port specific and
// will be either portYIELD_FROM_ISR() or portEND_SWITCHING_ISR() -
// refer to the documentation page for the port being used.
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}
The transmission with DMA works fine, but not the reception. I always get the first received byte.
Can someone tell me what I am doing wrong?
