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]; }