Hi TI E2E Community,
I’m trying to set-up the Tiva’s uDMA to do a Ping-Pong transfer into UART0 TX Data register, I need to transfer data at high speed, hence I have configured UART0 to run at 921,600 bps. While looking at the output in the serial terminal, I’m seeing that from time to time the UART/uDMA skips a bit, shifting the test sequence being used.
Any idea why?
I have changed the baud rate to 115200 trying to identify the problem, but the same situation persists.
I would really appreciate the help of the TI community!
Thanks,
Daniel
/*
* main.c
*
* Created on: Feb 2, 2016
* Author: daniel
*/
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_ints.h"
#include "inc/hw_uart.h"
#include "inc/hw_adc.h"
#include "driverlib/debug.h"
#include "driverlib/sysctl.h"
#include "driverlib/adc.h"
#include "driverlib/gpio.h"
#include "driverlib/rom.h"
#include "driverlib/interrupt.h"
#include "driverlib/pin_map.h"
#include "driverlib/uart.h"
#include "driverlib/udma.h"
#define TARGET_IS_BLIZZARD_RB1
#define NumOfChannels 16
#define AdcTransferSize 8
#define J_LIMIT (NumOfChannels/2)-1
// uDMA control table aligned to 1024-byte boundary
#pragma DATA_ALIGN(DMAParameters, 1024)
uint8_t DMAParameters[1024];
void initAdc(void);
void initUartTransfer(void);
void initAdcTransfer(void);
void dmaErrorHandler(void);
void uartIntHandler(void);
void adcIntHandler(void);
void processData(void);
//Fill and process pointers
volatile short *fillAdc;
volatile short *processAdc;
volatile short *transmitUart;
volatile short *fillUart;
//= {17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32}
//= {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}
short AdcPingBuf[NumOfChannels];
short AdcPongBuf[NumOfChannels];
short UartTxPing[NumOfChannels] = {
0x3210,
0x7654,
0xBA98,
0xFEDC,
0x3210,
0x7654,
0xBA98,
0xFEDC,
0x3210,
0x7654,
0xBA98,
0xFEDC,
0x3210,
0x7654,
0xBA98,
0xFEDC
};
short UartTxPong[NumOfChannels] = {
0x3210,
0x7654,
0xBA98,
0xFEDC,
0x3210,
0x7654,
0xBA98,
0xFEDC,
0x3210,
0x7654,
0xBA98,
0xFEDC,
0x3210,
0x7654,
0xBA98,
0xFEDC
};
/*
* {
0x0000,
0x1111,
0x2222,
0x3333,
0x4444,
0x5555,
0x6666,
0x7777,
0x8888,
0x9999,
0xAAAA,
0xBBBB,
0xCCCC,
0xDDDD,
0xEEEE,
0xFFFF
};
*/
int adcPingCount = 0;
int adcPongCount = 0;
int uartPingCount = 0;
int uartPongCount = 0;
int adcInterruptCounter = 0;
int uartInterruptCounter = 0;
int edmaErrorCount = 0;
int *adc0Fifo = (void *) (ADC0_BASE + ADC_O_SSFIFO0);
int *adc1Fifo = (void *) (ADC1_BASE + ADC_O_SSFIFO0);
//DEBUG
volatile short dataSample;
int main(void)
{
// uint16_t ui32_ADC0_ss_3; //Channel 0
// uint16_t ui32_ADC0_ss_2[4]; //Channel 1,2,3,4
// uint16_t ui32_ADC0_ss_1[4]; //Channel 5,6,7,8
// uint16_t ui32_ADC0_ss_0[8]; //Channel 9,10,11
//
// uint16_t ui32_ADC1_ss_3; //Channel 12
// uint16_t ui32_ADC1_ss_2[4]; //Channel 13,14,15,16
// uint16_t ui32_ADC1_ss_1[4]; //Channel 17,18,19,20
// uint16_t ui32_ADC1_ss_0[8]; //Channel 21,22,23
/*
* Config clock: Choose main Osc, drive the PLL with a 16 Mhz crystal. The PLL has a frequency of 400 MHz.
* It is initially divided by two, so 200 MHz (unless there is a DIV 400). The system clock is being divided then by 4.
* Then 200/4 = 50 MHz. The system clock is configured to run at 50 MHz.
*/
SysCtlClockSet(SYSCTL_SYSDIV_4|SYSCTL_USE_PLL|SYSCTL_OSC_MAIN|SYSCTL_XTAL_16MHZ);
//Enable ADC0 and ADC1
SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC1);
// GPIO setup for UART
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC);
SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_UART0);
GPIOPinConfigure(GPIO_PC4_U1RX);
GPIOPinConfigure(GPIO_PC5_U1TX);
GPIOPinTypeUART(GPIO_PORTC_BASE, GPIO_PIN_4 | GPIO_PIN_5);
//GPIO setup for ADc
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOK);
GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_0 | GPIO_PIN_1| GPIO_PIN_2| GPIO_PIN_3);
GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_7 | GPIO_PIN_6| GPIO_PIN_5| GPIO_PIN_4| GPIO_PIN_3| GPIO_PIN_2);
GPIOPinTypeADC(GPIO_PORTB_BASE, GPIO_PIN_4 | GPIO_PIN_5);
GPIOPinTypeADC(GPIO_PORTK_BASE, GPIO_PIN_0 | GPIO_PIN_1| GPIO_PIN_2| GPIO_PIN_3);
// Enable uDMA
SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);
SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_UDMA);
IntEnable(INT_UDMAERR);
uDMAControlBaseSet(DMAParameters);
uDMAEnable();
//initAdc();
initUartTransfer();
//initAdcTransfer();
fillUart = UartTxPong;
transmitUart = UartTxPing;
IntMasterEnable();
while(1){
}
}
void initAdc(void){
/* ADCClockConfigSet Shared between ADC devices, only one required. Using PLL. Docs say that PLL/25 will be used.
* Use PIOSC at 16 Mhz, at 125 kS/s.
*/
ADCClockConfigSet(ADC0_BASE,ADC_CLOCK_SRC_PIOSC|ADC_CLOCK_RATE_EIGHTH,1);
/*
*Hardware over-sampling to take the 125 kS/s to ~2 kS/s.
* 125/64 = 1.95 kS/s ~= 2 kS/s
*/
ADCHardwareOversampleConfigure(ADC0_BASE, 64);
ADCHardwareOversampleConfigure(ADC1_BASE, 64);
//Sequencer COnfigure
ADCSequenceConfigure(ADC0_BASE, 0, ADC_TRIGGER_ALWAYS,0);
//ADCSequenceConfigure(ADC0_BASE, 1, ADC_TRIGGER_ALWAYS,1);
ADCSequenceConfigure(ADC1_BASE, 0, ADC_TRIGGER_ALWAYS,0);
//ADCSequenceConfigure(ADC1_BASE, 1, ADC_TRIGGER_ALWAYS,1);
//ADC Step Configure
//ADC0
//Sample Sequencer 0, FIFO size = 8, Channel 0-7, Arbitration size must be 8.
ADCSequenceStepConfigure(ADC0_BASE,0,0,ADC_CTL_CH0);
ADCSequenceStepConfigure(ADC0_BASE,0,1,ADC_CTL_CH1);
ADCSequenceStepConfigure(ADC0_BASE,0,2,ADC_CTL_CH2);
ADCSequenceStepConfigure(ADC0_BASE,0,3,ADC_CTL_CH3);
ADCSequenceStepConfigure(ADC0_BASE,0,4,ADC_CTL_CH4);
ADCSequenceStepConfigure(ADC0_BASE,0,5,ADC_CTL_CH5);
ADCSequenceStepConfigure(ADC0_BASE,0,6,ADC_CTL_CH6);
ADCSequenceStepConfigure(ADC0_BASE,0,7,ADC_CTL_CH7|ADC_CTL_IE|ADC_CTL_END);
//Sample Sequencer 1, FIFO size = 4, Channel 8-11, Arbitration size must be 4.
/*
ADCSequenceStepConfigure(ADC0_BASE,1,0,ADC_CTL_CH8);
ADCSequenceStepConfigure(ADC0_BASE,1,1,ADC_CTL_CH9);
ADCSequenceStepConfigure(ADC0_BASE,1,2,ADC_CTL_CH10);
ADCSequenceStepConfigure(ADC0_BASE,1,3,ADC_CTL_CH11|ADC_CTL_END|ADC_CTL_IE);
*/
//ADC1
//Sample Sequencer 0, FIFO size = 8, Channel 10-13 & 16-19, Arbitration size must be 8.
ADCSequenceStepConfigure(ADC1_BASE,0,0,ADC_CTL_CH10);
ADCSequenceStepConfigure(ADC1_BASE,0,1,ADC_CTL_CH11);
ADCSequenceStepConfigure(ADC1_BASE,0,2,ADC_CTL_CH12);
ADCSequenceStepConfigure(ADC1_BASE,0,3,ADC_CTL_CH13);
ADCSequenceStepConfigure(ADC1_BASE,0,4,ADC_CTL_CH16);
ADCSequenceStepConfigure(ADC1_BASE,0,5,ADC_CTL_CH17);
ADCSequenceStepConfigure(ADC1_BASE,0,6,ADC_CTL_CH18);
ADCSequenceStepConfigure(ADC1_BASE,0,7,ADC_CTL_CH19|ADC_CTL_IE|ADC_CTL_END);
//Sample Sequencer 1, FIFO size = 4, Channel 20-23, Arbitration size must be 4.
/*
ADCSequenceStepConfigure(ADC1_BASE,1,0,ADC_CTL_CH20);
ADCSequenceStepConfigure(ADC1_BASE,1,1,ADC_CTL_CH21);
ADCSequenceStepConfigure(ADC1_BASE,1,2,ADC_CTL_CH22);
ADCSequenceStepConfigure(ADC1_BASE,1,3,ADC_CTL_CH23|ADC_CTL_END|ADC_CTL_IE);
*/
//Enable sequencer
ADCSequenceEnable(ADC0_BASE, 0);
//ADCSequenceEnable(ADC0_BASE, 1);
ADCSequenceEnable(ADC1_BASE, 0);
//ADCSequenceEnable(ADC1_BASE, 1);
}
// Initialize UART uDMA transfer
void initUartTransfer(void){
//Clear UART TX buffers
/*int i = 0;
for(i = 0; i < NumOfChannels; i++){
UartTxPing[i] = 0;
UartTxPong[i] = 0;
}*/
// char cmd[2];
// *(cmd) = 'O';
// *(cmd + 1) = 'K';
// UartTxPing[0] = ((cmd[1])<<8)|(cmd[0]);
//UartTxPing[0] = (short) *cmd;
// Enable UART1 and make sure it can run while the CPU sleeps
SysCtlPeripheralEnable(SYSCTL_PERIPH_UART1);
SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_UART1);
// Configure and enable the UART with DMA
UARTConfigSetExpClk(UART1_BASE, SysCtlClockGet(), 921600,
UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE |
UART_CONFIG_PAR_NONE);
//FIFO's are depth 16, 1/2 trigger means 8 FIFO's are free. This can be adjusted, make sure
//to change arbitration size in uDMA config.
UARTFIFOEnable(UART1_BASE);
UARTFIFOLevelSet(UART1_BASE, UART_FIFO_TX4_8, UART_FIFO_TX4_8);
UARTEnable(UART1_BASE);
UARTDMAEnable(UART1_BASE, UART_DMA_TX);
IntEnable(INT_UART1);
// Tx channel setup for ping and pong
uDMAChannelAttributeDisable(UDMA_CHANNEL_UART1TX,
UDMA_ATTR_ALTSELECT | UDMA_ATTR_USEBURST |
UDMA_ATTR_HIGH_PRIORITY |
UDMA_ATTR_REQMASK);
uDMAChannelControlSet(UDMA_CHANNEL_UART1TX | UDMA_PRI_SELECT,
UDMA_SIZE_8 | UDMA_SRC_INC_8 | UDMA_DST_INC_NONE |
UDMA_ARB_4);
uDMAChannelControlSet(UDMA_CHANNEL_UART1TX | UDMA_ALT_SELECT,
UDMA_SIZE_8 | UDMA_SRC_INC_8 | UDMA_DST_INC_NONE |
UDMA_ARB_4);
uDMAChannelAttributeEnable(UDMA_CHANNEL_UART1TX,UDMA_ATTR_HIGH_PRIORITY|UDMA_ATTR_USEBURST);
uDMAChannelTransferSet(UDMA_CHANNEL_UART1TX | UDMA_PRI_SELECT,
UDMA_MODE_PINGPONG,UartTxPing,(void *)(UART1_BASE + UART_O_DR), NumOfChannels*2);
uDMAChannelTransferSet(UDMA_CHANNEL_UART1TX | UDMA_ALT_SELECT,
UDMA_MODE_PINGPONG,UartTxPong,(void *)(UART1_BASE + UART_O_DR), NumOfChannels*2);
// Enable TX channel
uDMAChannelEnable(UDMA_CHANNEL_UART1TX);
}
void initAdcTransfer(void){
//Clear ADC buffers
int i = 0;
for(i = 0; i < NumOfChannels; i++){
AdcPingBuf[i] = 0;
AdcPongBuf[i] = 0;
}
//Enable DMA signaling.
ADCSequenceDMAEnable(ADC0_BASE,0);
// ADCSequenceDMAEnable(ADC0_BASE,1);
ADCSequenceDMAEnable(ADC1_BASE,0);
// ADCSequenceDMAEnable(ADC1_BASE,1);
//Enable DMA interruptions, remember this get intercepted by DMA.
IntEnable(INT_ADC0SS0);
//IntEnable(INT_ADC0SS1);
IntEnable(INT_ADC1SS0);
//IntEnable(INT_ADC1SS1);
ADCIntEnableEx(ADC0_BASE,ADC_INT_DMA_SS0);
ADCIntEnableEx(ADC1_BASE,ADC_INT_DMA_SS0);
//Select secondary mapping for channel 24
uDMAChannelAssign(UDMA_CH24_ADC1_0);
// DMA ADC ping/pong configuration
uDMAChannelAttributeDisable(UDMA_CHANNEL_ADC0,
UDMA_ATTR_ALTSELECT | UDMA_ATTR_USEBURST |
UDMA_ATTR_HIGH_PRIORITY |
UDMA_ATTR_REQMASK);
uDMAChannelAttributeDisable(UDMA_SEC_CHANNEL_ADC10,
UDMA_ATTR_ALTSELECT | UDMA_ATTR_USEBURST |
UDMA_ATTR_HIGH_PRIORITY |
UDMA_ATTR_REQMASK);
uDMAChannelAttributeEnable(UDMA_CHANNEL_ADC0,UDMA_ATTR_USEBURST);
uDMAChannelAttributeEnable(UDMA_SEC_CHANNEL_ADC10,UDMA_ATTR_USEBURST);
//Configure Primary and Alternate for ADC0
uDMAChannelControlSet(UDMA_CHANNEL_ADC0 | UDMA_PRI_SELECT,
UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_16 |
UDMA_ARB_8);
uDMAChannelControlSet(UDMA_CHANNEL_ADC0 | UDMA_ALT_SELECT,
UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_16 |
UDMA_ARB_8);
uDMAChannelTransferSet(UDMA_CHANNEL_ADC0 | UDMA_PRI_SELECT,
UDMA_MODE_PINGPONG,(void *)(ADC0_BASE + ADC_O_SSFIFO0),AdcPingBuf, AdcTransferSize);
uDMAChannelTransferSet(UDMA_CHANNEL_ADC0 | UDMA_ALT_SELECT,
UDMA_MODE_PINGPONG,(void *)(ADC0_BASE + ADC_O_SSFIFO0),AdcPongBuf, AdcTransferSize);
//Configure Primary and Alternate for ADC1
uDMAChannelControlSet(UDMA_SEC_CHANNEL_ADC10 | UDMA_PRI_SELECT,
UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_16 |
UDMA_ARB_8);
uDMAChannelControlSet(UDMA_SEC_CHANNEL_ADC10 | UDMA_ALT_SELECT,
UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_16 |
UDMA_ARB_8);
uDMAChannelTransferSet(UDMA_SEC_CHANNEL_ADC10 | UDMA_PRI_SELECT,
UDMA_MODE_PINGPONG,(void *)(ADC1_BASE + ADC_O_SSFIFO0),&(AdcPingBuf[8]), AdcTransferSize);
uDMAChannelTransferSet(UDMA_SEC_CHANNEL_ADC10 | UDMA_ALT_SELECT,
UDMA_MODE_PINGPONG,(void *)(ADC1_BASE + ADC_O_SSFIFO0),&(AdcPongBuf[8]), AdcTransferSize);
// Enable ADC channels
uDMAChannelEnable(UDMA_CHANNEL_ADC0);
uDMAChannelEnable(UDMA_SEC_CHANNEL_ADC10);
}
// uDMA error handler
void dmaErrorHandler(void){
uint32_t ui32Status;
ui32Status = uDMAErrorStatusGet();
if(ui32Status)
{
uDMAErrorStatusClear();
edmaErrorCount++;
}
}
// UART interrupt handler. Called on completion of uDMA transfer
void uartIntHandler(void){
uint32_t ui32Status;
uint32_t ui32Mode;
ui32Status = UARTIntStatus(UART1_BASE, 1);
UARTIntClear(UART1_BASE, ui32Status);
//UART PING
//Determine if TX primary structure is done. If it is, reset the structure to original parameters.
ui32Mode = uDMAChannelModeGet(UDMA_CHANNEL_UART1TX | UDMA_PRI_SELECT);
if(ui32Mode == UDMA_MODE_STOP)
{
uartPingCount++;
uDMAChannelTransferSet(UDMA_CHANNEL_UART1TX | UDMA_PRI_SELECT,
UDMA_MODE_PINGPONG,UartTxPing,(void *)(UART1_BASE + UART_O_DR), NumOfChannels*2);
transmitUart = UartTxPing;
fillUart = UartTxPong;
}
//UART PONG
//Determine if TX alternate structure is done, if it is, reset the structure to original parameters.
ui32Mode = uDMAChannelModeGet(UDMA_CHANNEL_UART1TX | UDMA_ALT_SELECT);
if(ui32Mode == UDMA_MODE_STOP)
{
uartPongCount++;
uDMAChannelTransferSet(UDMA_CHANNEL_UART1TX | UDMA_ALT_SELECT,
UDMA_MODE_PINGPONG,UartTxPong,(void *)(UART1_BASE + UART_O_DR), NumOfChannels*2);
transmitUart = UartTxPong;
fillUart = UartTxPing;
}
uartInterruptCounter++;
}
void adcIntHandler(void){
volatile uint32_t ui32StatusADC0;
volatile uint32_t ui32StatusADC1;
volatile uint32_t ui32Mode;
//Determine which module initiated the interrupt and clear it.
ui32StatusADC0 = ADCIntStatus(ADC0_BASE,0,true);
ui32StatusADC1 = ADCIntStatus(ADC1_BASE,0,true);
if(ui32StatusADC0 == ADC_INT_SS0){
ADCIntClear(ADC0_BASE,0);
}
if(ui32StatusADC1 == ADC_INT_SS0){
ADCIntClear(ADC1_BASE,0);
}
/////////////////////////////////////////ADC0 Param Refill///////////////////////////////////
//PING
//Determine if ADC primary structure is done. If it is, reset the structure to original parameters.
ui32Mode = uDMAChannelModeGet(UDMA_CHANNEL_ADC0 | UDMA_PRI_SELECT);
if(ui32Mode == UDMA_MODE_STOP)
{
adcPingCount++;
uDMAChannelTransferSet(UDMA_CHANNEL_ADC0 | UDMA_PRI_SELECT,
UDMA_MODE_PINGPONG,(void *)(ADC0_BASE + ADC_O_SSFIFO0),AdcPingBuf, AdcTransferSize);
}
//PONG
//Determine if ADC alternate structure is done, if it is, reset the structure to original parameters.
ui32Mode = uDMAChannelModeGet(UDMA_CHANNEL_ADC0 | UDMA_ALT_SELECT);
if(ui32Mode == UDMA_MODE_STOP)
{
adcPongCount++;
uDMAChannelTransferSet(UDMA_CHANNEL_ADC0 | UDMA_ALT_SELECT,
UDMA_MODE_PINGPONG,(void *)(ADC0_BASE + ADC_O_SSFIFO0),AdcPongBuf, AdcTransferSize);
uDMAChannelEnable(UDMA_CHANNEL_ADC0);
}
//////////////////////////////////////ADC1 Param Refill//////////////////////////////////////
//PING
//Determine if ADC primary structure is done. If it is, reset the structure to original parameters.
ui32Mode = uDMAChannelModeGet(UDMA_SEC_CHANNEL_ADC10 | UDMA_PRI_SELECT);
if(ui32Mode == UDMA_MODE_STOP)
{
adcPingCount++;
uDMAChannelTransferSet(UDMA_SEC_CHANNEL_ADC10 | UDMA_PRI_SELECT,
UDMA_MODE_PINGPONG,(void *)(ADC1_BASE + ADC_O_SSFIFO0),&(AdcPingBuf[8]), AdcTransferSize);
}
//PONG
//Determine if ADC alternate structure is done, if it is, reset the structure to original parameters.
ui32Mode = uDMAChannelModeGet(UDMA_SEC_CHANNEL_ADC10 | UDMA_ALT_SELECT);
if(ui32Mode == UDMA_MODE_STOP)
{
adcPongCount++;
uDMAChannelTransferSet(UDMA_SEC_CHANNEL_ADC10 | UDMA_ALT_SELECT,
UDMA_MODE_PINGPONG,(void *)(ADC1_BASE + ADC_O_SSFIFO0),&(AdcPongBuf[8]), AdcTransferSize);
uDMAChannelEnable(UDMA_SEC_CHANNEL_ADC10);
}
//If ping has been executed in both ADC0 & ADC1. Reset ping counter, swap fill process.
if(adcPingCount >= 2){
adcPingCount = 0;
processAdc = AdcPingBuf;
fillAdc = AdcPongBuf;
processData();
}
if(adcPongCount >= 2){
adcPongCount = 0;
processAdc = AdcPongBuf;
fillAdc = AdcPingBuf;
processData();
}
adcInterruptCounter++;
}
void processData(void){
short onlyTwelveBitMask = 0xFFF;
short shiftToId = 0x1000;
int i = 0;
for(i = 0; i < NumOfChannels; i++){
fillUart[i] = 0;
fillUart[i] = processAdc[i];
fillUart[i] &= onlyTwelveBitMask;
fillUart[i] |= (i * shiftToId);
}
//dataSample = fillUart[0];
}