MODSERIAL_dma

Table of Contents

    When MODSERIAL is compiled with MODDMA extra methods are provided to allow for blocks of data contained in char * buffers to easily sent using the GPDMA peripheral.

    In order to learn how to send a data block start with the example_dma.cpp program.

    First, import both MODSERIAL and MODDMA into your compiler.

    Import libraryMODDMA

    MODDMA GPDMA Controller New features: transfer pins to memory buffer under periodic timer control and send double buffers to DAC

    Import libraryMODSERIAL

    Bug fix release

    Next we include the usual #includes:-

    #include "mbed."
    #include "MODDMA.h"     // Before MODSERIAL.h
    #include "MODSERIAL.h"  // After MODDMA.h
    

    Note, the order in which you place these is important. Fot MODSERIAL to compile with DMA support, MODDMA.h must be placed before MODSERIAL.h By ordering them, the MODDMA controller class becomes visible to MODSERIAL allowing for it's extra methods to be defined.

    After doing the standard MODSERIAL setup next comes setting up MODDMA. This takes the form:-

    MODDMA dma;
    

    Fairly straight forward. However, it's important that your application only ever has one instance of MODDMA in your application. The Mbed's LPC1768 device afterall only has one GPDMA unit. If you define a second instance of MODDMA the Mbed will halt, flash the "blue LEDs of death" and issue a warning out of <stdout> (usually the USBTX/USBRX serial port).

    Now assuming we have created a MODSERIAL instance called "pc" we must register the MODDMA instance with it in order to use it. This is simply done thus:-

    int main() {
        char s[] = "Test Buffer to send!";
        pc.MODDMA( &dma );
        ...
    

    Now, to send the test buffer we simply do:-

        pc.dmaSend(s, sizeof(s));
    

    So, what happens to the standard TX buffer that MODSERIAL uses? Well, methods that send data out of the serial port, such as .printf() and putc() will still continue to work. However, they will place the data into the TX buffer with the usual blocking rules. If there is room within the TX buffer your functions will return almost immediately. If the TX buffer is full they will wait until there is room.

    But while DMA is sending data from a buffer supplied with dmaSend() no data is transferred from the TX buffer to the TX FIFOs. The DMA transfer effectively blocks the TX buffer output operation. As soon as the DMA transfer is complete normal TX buffer to TX FIFO operations resume and if there is any data in the TX buffer it will start transmitting as soon as the DMA transmit operation is complete.

    MODSERIAL Callbacks

    An additional feature is the ability to "callback" to your program when the DMA transfer from your buffer to DMA FIFOs -> TX FIFOs is complete. The easiest way is to show by example:-

    #include "mbed.h"
    #include "MODDMA.h"
    #include "MODSERIAL.h"
    
    DigitalOut led1(LED1);
    DigitalOut led4(LED4);
    MODSERIAL pc(USBTX, USBRX);
    MODDMA    dma;
    
    // When DMA transfer is complete switch on LED4
    void dmaCallback(MODSERIAL_IRQ_INFO *q) { led4 = 1; }
    
    int main() {
        char s[] = "TEST BUFFER";
        pc.baud( 115200 );
        pc.MODDMA( &dma );
        pc.attach_dmaSendComplete( &dmaCallback );
        pc.dmaSend( s, sizeof(s) );
    
        while(1) {
          led1 = !led1;
          wait(0.2);
        }
    }
    

    MODSERIAL can work fine sending bulk data in this fashion. However, MODDMA is able to do a lot more, especially in terms of callbacks. The MODDMA controller can callback for any channel event and each channel event can raise it's own callback individually. The MODDMA project page lists the API and the MODDMA cookbook page shows the use of MODDMA in more detail.

    Users who are familiar with Mbed library callbacks will know that it's possible to attach callbacks to class/methods. MODSERIAL supports this feature also. Here is the above example but where the callback is a method within a class:-

    #include "mbed.h"
    #include "MODDMA.h"
    #include "MODSERIAL.h"
    
    DigitalOut led1(LED1);
    DigitalOut led4(LED4);
    MODSERIAL pc(USBTX, USBRX);
    MODDMA    dma;
    
    class FOO {
    public:
      void dmaCallback(MODSERIAL_IRQ_INFO *q) { led4 = 1; }
    }
    
    // Create an instance of FOO called foo;
    FOO foo;
    
    int main() {
        char s[] = "TEST BUFFER";
        pc.baud( 115200 );
        pc.MODDMA( &dma );
        pc.attach_dmaSendComplete( &foo, &FOO::dmaCallback );
        pc.dmaSend( s, sizeof(s) );
    
        while(1) {
          led1 = !led1;
          wait(0.2);
        }
    }
    

    All wikipages