UART RX DMA

30 Sep 2010 . Edited: 30 Sep 2010

I want to send a 16byte serial message to DMA from a uart and read it once it finishes transferring. Has anyone done anything similar or know of a library I can use? Does the mbed library make use of DMA in its receiving?

30 Sep 2010

Hi Andres

I have recently been playing with UART and GPDMA, although im still getting my head around it, i used the UART-DMA example from NXP's LPC1768 driver libary found here http://ics.nxp.com/support/documents/microcontrollers/zip/lpc17xx.cmsis.driver.library.zip

It took some tweaking to get runing using the online compiler, and is not useing the mbed API in and way,

Anyway her's my work so far.

DMA_UART_example

You my be able to work with the example to fit your needs, hope this helps.

 

Matt

30 Sep 2010

I'm not really sure why you would want to use a DMA here. For one thing, the Uart has a 16byte RX FIFO. You can set it to interrupt when it gets to 1, 4, 8 or 14 characters full. But I would just use an interrupt on each RX char and store it into a buffer. Once you count in 16 set a flag (or whatever) to handle the buffer. It's pretty simple to do.

I've got code that does alot of this already and works fine when running on all 4 Uarts. For example, one Uart takes NMEA GPS messages. It stores them into a buffer and once the ISR detects the end of message ("\n") it flags the buffer for processing.

--Andy

01 Oct 2010

Thanks for the replys. I'm currently using the 16 byte fifo buffer but its slow to read the 16 byte buffer using the getc() function. I was also trying to avoid using interrupts as they disrupt the rest of my code.

01 Oct 2010

Hey Andy,

Would you mind sharing that code? I'm looking to use interrupts for parsing some uart messages.

01 Oct 2010
user Andres Camarena wrote:

Thanks for the replys. I'm currently using the 16 byte fifo buffer but its slow to read the 16 byte buffer using the getc() function. I was also trying to avoid using interrupts as they disrupt the rest of my code.

OK, to start with, getc() itself really isn't slow. What's slow is the fact that it's waiting for a character to arrive before the function returns. This is exactly what interrupts are designed to avoid. Trust me, interrupts are not going to disrupt the rest of your code unless you design it wrong. Functions liek getc() are called "blocking" functions. They basically hang your system until some condition is met.

I just knocked up a sample piece of code to show you how to collect 16bytes into a buffer using a simple ISR (interrupt service routine). I haven't actually tried this for real but it's based on other working code I have. See the way the main while(1) loop continues to operate until the buffer has 16bytes in it? It's just one way of doing it, there's plenty of variations you can make but you'll need to think slightly different when programming for the embedded enviroment unless you use something like a RTOS (real time operating system). Without an OS you pretty much have to do everything yourself.

The Mbed libraries for the most part relieve you of many burdens but they the Mbed libraries are a framework, not an OS. Learning to work with them, extend them or use homebrew code is the key.

Remember, this is just a very simple example, a starting point.

#include "mbed.h"

DigitalOut myled(LED1);

Serial mycomms(NC, p25); // Uart1
char rx_buffer[16];
int  rx_buffer_in = 0;
int  handle_buffer = 0;

int main() {
    mycomms.baud(9600);
    LPC_UART1->IER = 0x01; // enable Uart1 RX interrupts. 
     
    while(1) {
        // Each time around the loop test to see if we have
        // read 16bytes into our buffer.
        if (handle_buffer) {
            handle_buffer = 0;
            // do something with the buffer.
            LPC_UART1->IER = 0x1; // Re-enable interrupts to get another 16bytes.
        }
        // The rest of your project code goes here....
        myled = 1;
        wait(0.2);
        myled = 0;
        wait(0.2);
    }
}

extern "C" void UART1_IRQHandler(void) __irq {
    volatile uint32_t iir;
    
    iir = LPC_UART1->IIR;
    
    if (iir & 0x1) return;
    
    if (iir & 0x4) {
        while (LPC_UART1->LSR & 0x1) {
            rx_buffer[rx_buffer_in++] = (char)LPC_UART1->RBR;
            if (rx_buffer_in == 16) { // Wrap buffer in pointer and flag ready.
                rx_buffer_in  = 0;
                handle_buffer = 1;
                LPC_UART1->IER = 0; // Disable further interrupts.
            }
        } 
    }
}

 

 

 

01 Oct 2010

user Tyler Wagler wrote:

Hey Andy,

Would you mind sharing that code? I'm looking to use interrupts for parsing some uart messages.

Tyler, nearly ready to publish, just not quite there yet. I have contacted you via private message to email me and I'll send through some samples for you to look over.

01 Oct 2010

Thanks Andy,

I was having some issues with I2c when I used interrupts. And I wouldn't call getc() until available() was true so the data was there when I called it. Basically I would send a 16 byte message, wait a second to ensure the buffer had received everything, and then read all the chars from the buffer (this took 200us). Am I doing something wrong?

01 Oct 2010

Andres, thats sounds reasonable. What made you think getc() was slow then if the chars were already in the FIFO and you checked data was available?

The thing about interrupts if you're not use to handling them is usually two fold, either people make the interrupt function "do too much" or they forget to clear the flag that caused it in the first place. The former can lead to "interrupt stacking" where another IRQ arrives before you completed handling the last one and the later leads to continuous IRQs. As soon as you return it fires immediately. You could have suffered from either, don't know without more details.

So from your last post I'm not sure what you're actually looking to solve or what the nature of the problem is without a little more elaboration.

27 Oct 2010

There are 8 dma channels does this mean that you can have more than one simultaneously enabled? I'm wondering if I can read to serial streams to dma simultaneously.