This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
Hi all,
I'm working on a project where I need to implement UART communication using DMA on a MSP430F5659. Specifically, I need to reliably receive and transfer data packets of 256 bytes via UART. I understand that DMA can significantly offload the CPU and improve efficiency for such tasks.
Could anyone provide guidance or share some sample code on how to set up UART communication with DMA for handling 256-byte data transfers efficiently? I'm particularly interested in how to configure the DMA channels, UART peripheral, and any necessary interrupt handling for seamless operation.
Any insights, or code snippets would be greatly appreciated!
Thanks in advance.
I think TI doesn't provide an Example which does exactly this. I suggest you start with the Tx side, since that's a bit simpler. For that, I (still) suggest the Example msp430f665x_dma_02.c, over here:
https://dev.ti.com/tirex/explore/node?node=A__AOA7HJs5vP6JteXGeExmkQ__msp430ware__IOGqZri__LATEST
As I mentioned, this uses a rather unusual triggering mechanism (using a timer). The usual method would be to replace:
> DMACTL0 = DMA0TSEL_1; // 0-CCR2IFG
with
> DMACTL0 = DMA0TSEL_21; // UCA1TXIFG trigger per SLAS700E Table 9-13
where I got "21" from the DMA trigger table in the data sheet. I suggest also changing
> DMA0CTL = DMADT_4 | DMASRCINCR_3 | DMASBDB | DMAEN;// Rpt, inc src, enable
to
> DMA0CTL = DMADT_4 | DMASRCINCR_3 | DMASBDB | DMAEN | DMALEVEL;// Rpt, inc src, enable, level trigger
to avoid an arcane first-byte thing. The transmission will start immediately since this sets DMAEN=1. You can get rid of the timer code.
If you run this program it will send "Hello" repeatedly (handy for debugging). To do it only once, change DMADT_4 -> DMADT_0.
Hi Baseer,
Are you saying that you need to receive UART data, transfer it to memory using DMA, then use DMA again to transfer out via UART again?
I am able to provide a snippet of code that I wrote to receive UART data and transfer it to memory. I do not have code available to set up the second DMA to transfer from memory to UART TX, but the snippet can help you get to a starting point, and Bruce's input above will also be helpful. The code snippet that I will paste is written for the MSP430F6736, so you will need to check the pins and registers, but the flow should be similar as they are the same device family.
The snippet simply receives UART data at 9600 baud, and fills a buffer with the received data. When the received data fills the buffer, it begins to overwrite the beginning of the buffer. Please see below:
#include <msp430.h> #include <stdint.h> #define NUM_OF_BYTES (10) // Update this with the number of bytes to receive over // UART and store in the buffer // UART RX Values unsigned int DMA_DST[NUM_OF_BYTES] = {0x00}; int main(void) { WDTCTL = WDTPW | WDTHOLD; // Stop WDT // Setup P1.4 UCA1RXD, P1.5 UCA1TXD P1SEL |= BIT4 | BIT5; // Set P1.4, P1.5 to non-IO P1DIR |= BIT4 | BIT5; // Enable UCA1RXD, UCA1TXD // Setup eUSCI_A1 UCA1CTLW0 |= UCSWRST; // **Put state machine in reset** UCA1CTLW0 |= UCSSEL__SMCLK; // SMCLK UCA1BRW_L = 6; // 1MHz 9600 (see User's Guide) UCA1BRW_H = 0; // 1MHz 9600 UCA1MCTLW = UCBRF_13 | UCOS16; // Modln UCBRSx=0, UCBRFx=0x13, // over sampling UCA1CTLW0 &= ~UCSWRST; // **Initialize USCI state machine** // Setup DMA0 DMACTL0 = DMA0TSEL_18; // UCA1RXIFG triggered __data20_write_long((uintptr_t) &DMA0SA, (uintptr_t) &UCA1RXBUF); // Source block address __data20_write_long((uintptr_t) &DMA0DA, (uintptr_t) &DMA_DST); // Destination single address DMA0CTL &= ~DMAIFG; // Clear DMA interrupt flag DMA0SZ = NUM_OF_BYTES; // DMA0 size = 100 DMA0CTL = DMADT_4 | DMASRCINCR_0 | DMADSTINCR_3 | DMAIE | DMAEN; // Repeat single transfer, increment destination address // Unchaged source address, Repeated single transfer // Enable DMA Interrupt, DMA __bis_SR_register(LPM0_bits | GIE); while(1); } //------------------------------------------------------------------------------ // DMA Interrupt Service Routine //------------------------------------------------------------------------------ #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__) #pragma vector=DMA_VECTOR __interrupt void DMA_ISR(void) #elif defined(__GNUC__) void __attribute__ ((interrupt(DMA_VECTOR))) DMA_ISR (void) #else #error Compiler not supported! #endif { switch (__even_in_range(DMAIV, 16)) { case DMAIV_NONE: break; // No interrupts case DMAIV_DMA0IFG: // DMA0IFG = DMA Channel 0 __delay_cycles(1000000); // Optional delay __no_operation(); // Optional section for code once the 100 DMA transfers are complete break; case DMAIV_DMA1IFG: break; // DMA1IFG = DMA Channel 1 case DMAIV_DMA2IFG: break; // DMA2IFG = DMA Channel 2 case 8: break; // Reserved case 10: break; // Reserved case 12: break; // Reserved case 14: break; // Reserved case 16: break; // Reserved default: break; } }
I will add: something that held me up for a while was that the DMA will not trigger while the corresponding interrupt is enabled. So in that example, I originally had the UART RX interrupt enabled, and couldn't get the DMA to trigger. Make sure that you keep the interrupt disabled, and if you need the second DMA channel, ensure that the TX interrupt is also disabled.
Hi Dylan and Bruce,
Thanks for the help let me follow your guidelines and will get back if I face any issues. Thanks again.
**Attention** This is a public forum