Other Parts Discussed in Thread: EK-TM4C123GXL
Tool/software: Code Composer Studio
Hello everyone,
I'm working on a project that requires developing a communication method between 2 TM4C123G, kit A handles power process (ADC, PWM, etc.), kit B handles MODBUS through RS-485 to the PC. The target is frequently communication without interrupt the power process of A and MODBUS communication of B, I have gone through I2C, SPI communication. These two methods is fast and accurate, but still have flaws since the I2C don't have any FIFO and SPI communication is hard to synchronize without interrupted. I found out that the uDMA can independently process without interrupt the main program, thus, I try using the uDMA UART in order to make the communication data always accessible. I'm a newbie in the uDMA field, but I did do some studies and researches. Currently, I understand the way uDMA working, unfortunately, I can't figure out how to set up it properly. I tried to modified some code I found online but so far nothing happens yet (the code is attached below).
My idea is when data go to the Rx pin of any kit, it will trigger the uDMA so that all the data will go straight to register of uDMA and trigger a flag. In the while(1) loop, if the flag is ON, the data will be processed and response to the other kit (this is also the reason why I choose UART instead of I2C and SPI). For more details, kit B send a request package of 8 byte unsigned char to kit A, kit A after finishing the power process will check the flag. If the flag is ON, kit A will gather data and send a package of 16 (or 32 bytes) of ADC information to kit B. Which type of mode and data should I set up to satisfy these requirements?
The code online using the UART FIFO to trigger the uDMA. Is there any way to transfer data directly to the uDMA without using the UART FIFO?
Thank you.
#include <stdbool.h> #include <stdint.h> #include "inc/hw_memmap.h" #include "inc/hw_ints.h" #include "inc/hw_uart.h" #include "driverlib/gpio.h" #include "driverlib/pin_map.h" #include "driverlib/ssi.h" #include "driverlib/sysctl.h" #include "driverlib/timer.h" #include "driverlib/interrupt.h" #include "driverlib/uart.h" #include "driverlib/udma.h" static char uDMAControlTable[1024]; char buffer[] = {0,1,2,3,4,5,6,7,8,9}; void initUART0(void) { // Enable GPIO port A SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA); // Enable DMA SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA); IntEnable(INT_UDMAERR); uDMAEnable(); uDMAControlBaseSet(uDMAControlTable); // Enable UART 0 peripheral SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0); // Setup A0 and A1 as the RX and TX pins for UART 0 GPIOPinConfigure(GPIO_PA0_U0RX); GPIOPinConfigure(GPIO_PA1_U0TX); GPIOPinTypeUART(GPIO_PORTA_BASE,GPIO_PIN_0); GPIOPinTypeUART(GPIO_PORTA_BASE,GPIO_PIN_1); // Configure UART (clock from PIOSC, 115.2k 8-N-1) UARTConfigSetExpClk(UART0_BASE, SysCtlClockGet(), 115200, (UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | UART_CONFIG_PAR_EVEN)); // Trigger interrupt when FIFOs at 1/8 capacity UARTFIFOLevelSet(UART0_BASE,UART_FIFO_TX1_8,UART_FIFO_RX1_8); // Make sure interrupts are clear UARTIntClear(UART0_BASE, (UART_INT_RX | UART_INT_RT | UART_INT_TX | UART_INT_OE | UART_INT_BE | UART_INT_PE | UART_INT_FE)); // Enable UART 0 UARTEnable(UART0_BASE); // Enable DMA on UART RX UARTDMAEnable(UART0_BASE, UART_DMA_RX); // // Put the attributes in a known state for the uDMA UART TX channel. These // should already be disabled by default. // uDMAChannelAttributeDisable(UDMA_CHANNEL_UART0TX, UDMA_ATTR_ALTSELECT | UDMA_ATTR_USEBURST | UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK); // // Put the attributes in a known state for the uDMA UART RX channel. These // should already be disabled by default. // uDMAChannelAttributeDisable(UDMA_CHANNEL_UART0RX, UDMA_ATTR_ALTSELECT | UDMA_ATTR_USEBURST | UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK); uDMAChannelAttributeEnable(UDMA_CHANNEL_UART0TX, UDMA_ATTR_USEBURST); uDMAChannelControlSet(UDMA_CHANNEL_UART0TX | UDMA_PRI_SELECT, UDMA_SIZE_8 | UDMA_SRC_INC_8 | UDMA_DST_INC_NONE | UDMA_ARB_8); uDMAChannelControlSet(UDMA_CHANNEL_UART0RX | UDMA_PRI_SELECT, UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 | UDMA_ARB_8); // Enable DMA interrupts on this UART UARTIntEnable(UART0_BASE, UART_INT_DMARX | UART_INT_DMATX); // Enable interrupts on this UART IntEnable(INT_UART0); } void uartInterruptHandler(void) { // If an RX interrupt if (UARTIntStatus(UART0_BASE, true) & UART_INT_DMARX) { // Disable DMA on UART RX, and clear the interrupt UARTDMADisable(UART0_BASE, UART_DMA_RX); UARTIntClear(UART0_BASE, UART_INT_DMARX ); } // If an TX interrupt if (UARTIntStatus(UART0_BASE, true) & UART_INT_DMATX) { // Disable DMA on UART TX, and clear the interrupt UARTDMADisable(UART0_BASE, UART_DMA_TX); UARTIntClear(UART0_BASE, UART_INT_DMATX ); } } int main() { SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ); // Initialize UART initUART0(); for(;;) { /******************************************************************************* * Receive */ // Setup to receive buffer uDMAChannelTransferSet( UDMA_CHANNEL_UART0RX | UDMA_PRI_SELECT, UDMA_MODE_BASIC, (void *)(UART0_BASE + UART_O_DR), &buffer, sizeof(buffer)); // Enable DMA channel to begin receive uDMAChannelEnable(UDMA_CHANNEL_UART0RX); // Enable DMA on UART RX UARTDMAEnable(UART0_BASE, UART_DMA_RX); /******************************************************************************* * Transmit */ // Setup to send buffer uDMAChannelTransferSet( UDMA_CHANNEL_UART0TX | UDMA_PRI_SELECT, UDMA_MODE_BASIC, &buffer, (void *)(UART0_BASE + UART_O_DR), sizeof(buffer)); // DMA channel must be enabled first, or an interrupt will occur immediately uDMAChannelEnable(UDMA_CHANNEL_UART0TX); // Enable DMA on UART TX UARTDMAEnable(UART0_BASE, UART_DMA_TX); while (uDMAChannelIsEnabled(UDMA_CHANNEL_UART0RX)) { // Wait for the response before sending more } } }