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

Dependents:   FirstTest WaveSim IO-dma-memmem DACDMAfuncgenlib ... more

Files at this revision

API Documentation at this revision

Comitter:
AjK
Date:
Sun Mar 13 23:28:21 2011 +0000
Parent:
11:19009be5a0e7
Child:
13:846c8b6ffb7f
Commit message:
1.8 See ChangeLog.c

Changed in this revision

ChangeLog.c Show annotated file Show diff for this revision Revisions of this file
MODDMA.cpp Show annotated file Show diff for this revision Revisions of this file
MODDMA.h Show annotated file Show diff for this revision Revisions of this file
SETUP.cpp Show annotated file Show diff for this revision Revisions of this file
example1.cpp Show diff for this revision Revisions of this file
example1.h Show annotated file Show diff for this revision Revisions of this file
example2.cpp Show diff for this revision Revisions of this file
example2.h Show annotated file Show diff for this revision Revisions of this file
example3.h Show annotated file Show diff for this revision Revisions of this file
iomacros.h Show annotated file Show diff for this revision Revisions of this file
--- a/ChangeLog.c	Sun Mar 13 12:46:55 2011 +0000
+++ b/ChangeLog.c	Sun Mar 13 23:28:21 2011 +0000
@@ -1,5 +1,12 @@
 /* $Id:$
 
+1.8 - 13 Mar 2011
+
+    * Renamed example files to .h
+    * Added pseudo g2m and m2g transferTypes to support GPIO 
+      "memory moves" but triggered by peripheral timer. To 
+      support this new operating mode added example3.h
+    
 1.7 - 13 Mar 2011
 
     * Remove the test at the beginning of the channel setup.
--- a/MODDMA.cpp	Sun Mar 13 12:46:55 2011 +0000
+++ b/MODDMA.cpp	Sun Mar 13 23:28:21 2011 +0000
@@ -37,7 +37,7 @@
 bool
 MODDMA::Enabled(CHANNELS ChannelNumber)
 {
-    LPC_GPDMACH_TypeDef *pChannel = (LPC_GPDMACH_TypeDef *)Channel_p( ChannelNumber );
+    LPC_GPDMACH_TypeDef *pChannel = (LPC_GPDMACH_TypeDef *)Channel_p( ChannelNumber );    
     return (bool)(pChannel->DMACCConfig & _E);
 }
 
--- a/MODDMA.h	Sun Mar 13 12:46:55 2011 +0000
+++ b/MODDMA.h	Sun Mar 13 23:28:21 2011 +0000
@@ -64,6 +64,7 @@
     uint32_t SrcConn;           //!< Peripheral Source Connection type, used in case TransferType is chosen as
     uint32_t DstConn;           //!< Peripheral Destination Connection type, used in case TransferType is chosen as
     uint32_t DMALLI;            //!< Linker List Item structure data address if there's no Linker List, set as '0'
+    uint32_t DMACSync;          //!< DMACSync if required.
     
     // Mbed specifics.
 
@@ -81,6 +82,7 @@
         SrcConn       = 0;
         DstConn       = 0;
         DMALLI        = 0;
+        DMACSync      = 0;
     }
     
     ~MODDMA_Config() {
@@ -97,6 +99,7 @@
     class MODDMA_Config * srcConn(uint32_t n)       { SrcConn = n;           return this; }
     class MODDMA_Config * dstConn(uint32_t n)       { DstConn = n;           return this; }
     class MODDMA_Config * dmaLLI(uint32_t n)        { DMALLI = n;            return this; }
+    class MODDMA_Config * dmacSync(uint32_t n)      { DMACSync = n;          return this; }
     
     uint32_t channelNum(void)    { return ChannelNum;    }
     uint32_t transferSize(void)  { return TransferSize;  }
@@ -107,7 +110,8 @@
     uint32_t srcConn(void)       { return SrcConn;       }
     uint32_t dstConn(void)       { return DstConn;       }
     uint32_t dmaLLI(void)        { return DMALLI;        }
-
+    uint32_t dmacSync(void)      { return DMACSync; }
+    
     /**
      * Attach a callback to the TC IRQ configuration.
      *
@@ -306,7 +310,9 @@
           m2m = 0UL     /*!< Memory to memory - DMA control */
         , m2p = 1UL     /*!< Memory to peripheral - DMA control */
         , p2m = 2UL     /*!< Peripheral to memory - DMA control */
-        , p2p = 3UL     /*!< Src peripheral to dest peripheral - DMA control */        
+        , p2p = 3UL     /*!< Src peripheral to dest peripheral - DMA control */         
+        , g2m = 4UL     /*!< Psuedo special case for reading "peripheral GPIO" that's memory mapped. */
+        , m2g = 5UL     /*!< Psuedo Special case for writing "peripheral GPIO" that's memory mapped. */
     };   
 
     //! Burst size in Source and Destination definitions */
@@ -651,13 +657,15 @@
      */
     FunctionPointer isrIntErrStat;                        
     
+    uint32_t Channel_p(int channel);
+    
 protected:
    
     // Data LUTs.
     uint32_t LUTPerAddr(int n);
     uint8_t  LUTPerBurst(int n);
     uint8_t  LUTPerWid(int n);    
-    uint32_t Channel_p(int channel);
+    //uint32_t Channel_p(int channel);
     
     CHANNELS IrqProcessingChannel;
     
--- a/SETUP.cpp	Sun Mar 13 12:46:55 2011 +0000
+++ b/SETUP.cpp	Sun Mar 13 23:28:21 2011 +0000
@@ -108,6 +108,38 @@
                 | CxControl_I();
             break;
             
+        // GPIO to memory
+        case g2m:
+            // Assign GPIO source address
+            pChannel->DMACCSrcAddr = config->srcMemAddr();
+            // Assign memory destination address
+            pChannel->DMACCDestAddr = config->dstMemAddr();
+            pChannel->DMACCControl
+                = CxControl_TransferSize((uint32_t)config->transferSize()) 
+                | CxControl_SBSize((uint32_t)LUTPerBurst(config->srcConn())) 
+                | CxControl_DBSize((uint32_t)LUTPerBurst(config->srcConn())) 
+                | CxControl_SWidth((uint32_t)LUTPerWid(config->srcConn())) 
+                | CxControl_DWidth((uint32_t)LUTPerWid(config->srcConn())) 
+                | CxControl_DI() 
+                | CxControl_I();
+            break;
+            
+        // Memory to GPIO
+        case m2g:
+            // Assign physical source
+            pChannel->DMACCSrcAddr = config->srcMemAddr();
+            // Assign peripheral destination address
+            pChannel->DMACCDestAddr = config->dstMemAddr();
+            pChannel->DMACCControl
+                = CxControl_TransferSize((uint32_t)config->transferSize()) 
+                | CxControl_SBSize((uint32_t)LUTPerBurst(config->dstConn())) 
+                | CxControl_DBSize((uint32_t)LUTPerBurst(config->dstConn())) 
+                | CxControl_SWidth((uint32_t)LUTPerWid(config->dstConn())) 
+                | CxControl_DWidth((uint32_t)LUTPerWid(config->dstConn())) 
+                | CxControl_SI() 
+                | CxControl_I();
+            break;
+            
         // Do not support any more transfer type, return ERROR
         default:
             return 0;
@@ -121,7 +153,7 @@
         LPC_SC->RESERVED9 &= ~(1 << (config->srcConn() - 8));
     }
 
-    // Re-Configure DMA Request Select for Destination peripheral
+    // Re-Configure DMA Request Select for destination peripheral
     if (config->dstConn() > 15) {
         LPC_SC->RESERVED9 |= (1 << (config->dstConn() - 16));
     } 
@@ -137,11 +169,21 @@
     uint32_t tmp1 = config->srcConn(); tmp1 = ((tmp1 > 15) ? (tmp1 - 8) : tmp1);
     uint32_t tmp2 = config->dstConn(); tmp2 = ((tmp2 > 15) ? (tmp2 - 8) : tmp2);
 
+    if (config->dmacSync()) {
+        uint32_t tmp3 = config->dmacSync(); tmp3 = ((tmp3 > 15) ? (tmp3 - 8) : tmp3);
+        LPC_GPDMA->DMACSync |= Sync_Src( tmp3 );
+    }
+    
+    uint32_t tfer_type = (uint32_t)config->transferType();
+    if (tfer_type == g2m || tfer_type == m2g) {
+        tfer_type -= 2; // Adjust psuedo transferType to a real transferType.
+    }
+    
     // Configure DMA Channel, enable Error Counter and Terminate counter
     pChannel->DMACCConfig 
         = CxConfig_IE() 
         | CxConfig_ITC() 
-        | CxConfig_TransferType((uint32_t)config->transferType()) 
+        | CxConfig_TransferType(tfer_type) 
         | CxConfig_SrcPeripheral(tmp1) 
         | CxConfig_DestPeripheral(tmp2);
 
--- a/example1.cpp	Sun Mar 13 12:46:55 2011 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,92 +0,0 @@
-#ifdef COMPILE_EXAMPLE1_CODE_MODDMA
-
-#include "mbed.h"
-#include "MODDMA.h"
-#include "MODSERIAL.h"
-
-DigitalOut led1(LED1);
-DigitalOut led2(LED2);
-DigitalOut led3(LED3);
-DigitalOut led4(LED4);
-MODDMA dma;
-MODSERIAL pc(USBTX, USBRX);
-
-// Function prototypes for IRQ callbacks.
-// See definitions following main() below.
-void dmaTCCallback(void);
-void dmaERRCallback(void);
-void TC0_callback(void);
-void ERR0_callback(void);
-
-int main() {
-    char s[] = "**DMA** ABCDEFGHIJKLMNOPQRSTUVWXYZ **DMA**";
-    
-    pc.baud(PC_BAUD);
-    
-    dma.attach_tc( &dmaTCCallback );
-    dma.attach_err( &dmaERRCallback );
-    
-    MODDMA_Config *config = new MODDMA_Config;
-    config
-     ->channelNum    ( MODDMA::Channel_0 )
-     ->srcMemAddr    ( (uint32_t) &s )
-     ->dstMemAddr    ( 0 )
-     ->transferSize  ( sizeof(s) )
-     ->transferType  ( MODDMA::m2p )
-     ->transferWidth ( 0 )
-     ->srcConn       ( 0 )
-     ->dstConn       ( MODDMA::UART0_Tx )
-     ->dmaLLI        ( 0 )
-     ->attach_tc     ( &TC0_callback )
-     ->attach_err    ( &ERR0_callback )
-    ; // config end
-    
-    // Setup the configuration.
-    dma.Setup(config);
-    
-    //dma.Enable( MODDMA::Channel_0 );
-    //dma.Enable( config->channelNum() );
-    dma.Enable( config );
-    
-    while (1) {
-        led1 = !led1;
-        wait(0.25);        
-    }
-}
-
-// Main controller TC IRQ callback
-void dmaTCCallback(void) {
-    led2 = 1;
-}
-
-// Main controller ERR IRQ callback
-void dmaERRCallback(void) {
-    error("Oh no! My Mbed exploded! :( Only kidding, find the problem");
-}
-
-// Configuration callback on TC
-void TC0_callback(void) {
-    MODDMA_Config *config = dma.getConfig();
-    dma.haltAndWaitChannelComplete( (MODDMA::CHANNELS)config->channelNum());
-    dma.Disable( (MODDMA::CHANNELS)config->channelNum() );
-    
-    // Configurations have two IRQ callbacks for TC and Err so you 
-    // know which you are processing. However, if you want to use 
-    // a single callback function you can tell what type of IRQ 
-    // is being processed thus:-
-    if (dma.irqType() == MODDMA::TcIrq)  {
-        led3 = 1;
-        dma.clearTcIrq();
-    }
-    if (dma.irqType() == MODDMA::ErrIrq) {
-        led4 = 1;
-        dma.clearErrIrq();
-    }
-}
-
-// Configuration cakllback on Error
-void ERR0_callback(void) {
-    error("Oh no! My Mbed exploded! :( Only kidding, find the problem");
-}
-
-#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/example1.h	Sun Mar 13 23:28:21 2011 +0000
@@ -0,0 +1,89 @@
+#include "mbed.h"
+#include "MODDMA.h"
+#include "MODSERIAL.h"
+
+DigitalOut led1(LED1);
+DigitalOut led2(LED2);
+DigitalOut led3(LED3);
+DigitalOut led4(LED4);
+MODDMA dma;
+MODSERIAL pc(USBTX, USBRX);
+
+// Function prototypes for IRQ callbacks.
+// See definitions following main() below.
+void dmaTCCallback(void);
+void dmaERRCallback(void);
+void TC0_callback(void);
+void ERR0_callback(void);
+
+int main() {
+    char s[] = "**DMA** ABCDEFGHIJKLMNOPQRSTUVWXYZ **DMA**";
+    
+    pc.baud(PC_BAUD);
+    
+    dma.attach_tc( &dmaTCCallback );
+    dma.attach_err( &dmaERRCallback );
+    
+    MODDMA_Config *config = new MODDMA_Config;
+    config
+     ->channelNum    ( MODDMA::Channel_0 )
+     ->srcMemAddr    ( (uint32_t) &s )
+     ->dstMemAddr    ( 0 )
+     ->transferSize  ( sizeof(s) )
+     ->transferType  ( MODDMA::m2p )
+     ->transferWidth ( 0 )
+     ->srcConn       ( 0 )
+     ->dstConn       ( MODDMA::UART0_Tx )
+     ->dmaLLI        ( 0 )
+     ->attach_tc     ( &TC0_callback )
+     ->attach_err    ( &ERR0_callback )
+    ; // config end
+    
+    // Setup the configuration.
+    dma.Setup(config);
+    
+    //dma.Enable( MODDMA::Channel_0 );
+    //dma.Enable( config->channelNum() );
+    dma.Enable( config );
+    
+    while (1) {
+        led1 = !led1;
+        wait(0.25);        
+    }
+}
+
+// Main controller TC IRQ callback
+void dmaTCCallback(void) {
+    led2 = 1;
+}
+
+// Main controller ERR IRQ callback
+void dmaERRCallback(void) {
+    error("Oh no! My Mbed exploded! :( Only kidding, find the problem");
+}
+
+// Configuration callback on TC
+void TC0_callback(void) {
+    MODDMA_Config *config = dma.getConfig();
+    dma.haltAndWaitChannelComplete( (MODDMA::CHANNELS)config->channelNum());
+    dma.Disable( (MODDMA::CHANNELS)config->channelNum() );
+    
+    // Configurations have two IRQ callbacks for TC and Err so you 
+    // know which you are processing. However, if you want to use 
+    // a single callback function you can tell what type of IRQ 
+    // is being processed thus:-
+    if (dma.irqType() == MODDMA::TcIrq)  {
+        led3 = 1;
+        dma.clearTcIrq();
+    }
+    if (dma.irqType() == MODDMA::ErrIrq) {
+        led4 = 1;
+        dma.clearErrIrq();
+    }
+}
+
+// Configuration cakllback on Error
+void ERR0_callback(void) {
+    error("Oh no! My Mbed exploded! :( Only kidding, find the problem");
+}
+
--- a/example2.cpp	Sun Mar 13 12:46:55 2011 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,140 +0,0 @@
-#ifdef COMPILE_EXAMPLE2_CODE_MODDMA
-
-/*
- * This example was provided to support Mbed forum thread:-
- * http://mbed.org/forum/mbed/topic/1798
- */
- 
-#include "mbed.h"
-#include "MODDMA.h"
-
-#define SAMPLE_BUFFER_LENGTH 32
-
-DigitalOut led1(LED1);
-DigitalOut led2(LED2);
-
-MODDMA dma;
-Serial pc(USBTX, USBRX);
-
-// ISR set's this when transfer complete.
-bool dmaTransferComplete = false;
-
-// Function prototypes for IRQ callbacks.
-// See definitions following main() below.
-void TC0_callback(void);
-void ERR0_callback(void);
-
-int main() {
-
-    // Create a buffer to hold the ADC samples and clear it.
-    // Note, we are going to sample two ADC inputs so they
-    // end up in this buffer "interleaved". So you will want
-    // a buffer twice this size to a real life given sample
-    // frequency. See the printf() output for details.
-    uint32_t adcInputBuffer[SAMPLE_BUFFER_LENGTH];    
-    memset(adcInputBuffer, 0, sizeof(adcInputBuffer));
-    
-    // We use the ADC irq to trigger DMA and the manual says
-    // that in this case the NVIC for ADC must be disabled.
-    NVIC_DisableIRQ(ADC_IRQn);
-    
-    // Power up the ADC and set PCLK
-    LPC_SC->PCONP    |=  (1UL << 12);
-    LPC_SC->PCLKSEL0 &= ~(3UL << 24); // PCLK = CCLK/4 96M/4 = 24MHz
-    
-    // Enable the ADC, 12MHz,  ADC0.0 & .1
-    LPC_ADC->ADCR  = (1UL << 21) | (1UL << 8) | (3UL << 0); 
-    
-    // Set the pin functions to ADC
-    LPC_PINCON->PINSEL1 &= ~(3UL << 14);  /* P0.23, Mbed p15. */
-    LPC_PINCON->PINSEL1 |=  (1UL << 14);
-    LPC_PINCON->PINSEL1 &= ~(3UL << 16);  /* P0.24, Mbed p16. */
-    LPC_PINCON->PINSEL1 |=  (1UL << 16);
-    
-    // Setup the serial port to print out results.
-    pc.baud(115200);
-    pc.printf("ADC with DMA example\n");
-    pc.printf("====================\n");
-    
-    // Prepare an ADC configuration.
-    MODDMA_Config *conf = new MODDMA_Config;
-    conf
-     ->channelNum    ( MODDMA::Channel_0 )
-     ->srcMemAddr    ( 0 )
-     ->dstMemAddr    ( (uint32_t)adcInputBuffer )
-     ->transferSize  ( SAMPLE_BUFFER_LENGTH )
-     ->transferType  ( MODDMA::p2m )
-     ->transferWidth ( MODDMA::word )
-     ->srcConn       ( MODDMA::ADC )
-     ->dstConn       ( 0 )
-     ->dmaLLI        ( 0 )
-     ->attach_tc     ( &TC0_callback )
-     ->attach_err    ( &ERR0_callback )
-    ; // end conf.
-    
-    // Prepare configuration.
-    dma.Setup( conf );
-    
-    // Enable configuration.
-    dma.Enable( conf );
-    
-    // Enable ADC irq flag (to DMA).
-    // Note, don't set the individual flags,
-    // just set the global flag.
-    LPC_ADC->ADINTEN = 0x100;
-
-    // Enable burst mode on inputs 0 and 1.
-    LPC_ADC->ADCR |= (1UL << 16); 
-    
-    while (1) {
-        // When transfer complete do this block.
-        if (dmaTransferComplete) {
-            delete conf; // No memory leaks, delete the configuration.
-            dmaTransferComplete = false;
-            for (int i = 0; i < SAMPLE_BUFFER_LENGTH; i++) {
-                int channel = (adcInputBuffer[i] >> 24) & 0x7;
-                int iVal = (adcInputBuffer[i] >> 4) & 0xFFF;
-                double fVal = 3.3 * (double)((double)iVal) / ((double)0x1000); // scale to 0v to 3.3v
-                pc.printf("Array index %02d : ADC input channel %d = 0x%03x %01.3f volts\n", i, channel, iVal, fVal);                  
-            }
-        }
-        
-        // Just flash LED1 for something to do.
-        led1 = !led1;
-        wait(0.25);        
-    }
-}
-
-// Configuration callback on TC
-void TC0_callback(void) {
-    
-    MODDMA_Config *config = dma.getConfig();
-    
-    // Disbale burst mode and switch off the IRQ flag.
-    LPC_ADC->ADCR &= ~(1UL << 16);
-    LPC_ADC->ADINTEN = 0;    
-    
-    // Finish the DMA cycle by shutting down the channel.
-    dma.haltAndWaitChannelComplete( (MODDMA::CHANNELS)config->channelNum());
-    dma.Disable( (MODDMA::CHANNELS)config->channelNum() );
-    
-    // Tell main() while(1) loop to print the results.
-    dmaTransferComplete = true;            
-    
-    // Switch on LED2 to show transfer complete.
-    led2 = 1;        
-    
-    // Clear DMA IRQ flags.
-    if (dma.irqType() == MODDMA::TcIrq) dma.clearTcIrq();    
-    if (dma.irqType() == MODDMA::ErrIrq) dma.clearErrIrq();
-}
-
-// Configuration callback on Error
-void ERR0_callback(void) {
-    // Switch off burst conversions.
-    LPC_ADC->ADCR |= ~(1UL << 16);
-    LPC_ADC->ADINTEN = 0;
-    error("Oh no! My Mbed EXPLODED! :( Only kidding, go find the problem");
-}
-
-#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/example2.h	Sun Mar 13 23:28:21 2011 +0000
@@ -0,0 +1,137 @@
+/*
+ * This example was provided to support Mbed forum thread:-
+ * http://mbed.org/forum/mbed/topic/1798
+ */
+ 
+#include "mbed.h"
+#include "MODDMA.h"
+
+#define SAMPLE_BUFFER_LENGTH 32
+
+DigitalOut led1(LED1);
+DigitalOut led2(LED2);
+
+MODDMA dma;
+Serial pc(USBTX, USBRX);
+
+// ISR set's this when transfer complete.
+bool dmaTransferComplete = false;
+
+// Function prototypes for IRQ callbacks.
+// See definitions following main() below.
+void TC0_callback(void);
+void ERR0_callback(void);
+
+int main() {
+
+    // Create a buffer to hold the ADC samples and clear it.
+    // Note, we are going to sample two ADC inputs so they
+    // end up in this buffer "interleaved". So you will want
+    // a buffer twice this size to a real life given sample
+    // frequency. See the printf() output for details.
+    uint32_t adcInputBuffer[SAMPLE_BUFFER_LENGTH];    
+    memset(adcInputBuffer, 0, sizeof(adcInputBuffer));
+    
+    // We use the ADC irq to trigger DMA and the manual says
+    // that in this case the NVIC for ADC must be disabled.
+    NVIC_DisableIRQ(ADC_IRQn);
+    
+    // Power up the ADC and set PCLK
+    LPC_SC->PCONP    |=  (1UL << 12);
+    LPC_SC->PCLKSEL0 &= ~(3UL << 24); // PCLK = CCLK/4 96M/4 = 24MHz
+    
+    // Enable the ADC, 12MHz,  ADC0.0 & .1
+    LPC_ADC->ADCR  = (1UL << 21) | (1UL << 8) | (3UL << 0); 
+    
+    // Set the pin functions to ADC
+    LPC_PINCON->PINSEL1 &= ~(3UL << 14);  /* P0.23, Mbed p15. */
+    LPC_PINCON->PINSEL1 |=  (1UL << 14);
+    LPC_PINCON->PINSEL1 &= ~(3UL << 16);  /* P0.24, Mbed p16. */
+    LPC_PINCON->PINSEL1 |=  (1UL << 16);
+    
+    // Setup the serial port to print out results.
+    pc.baud(115200);
+    pc.printf("ADC with DMA example\n");
+    pc.printf("====================\n");
+    
+    // Prepare an ADC configuration.
+    MODDMA_Config *conf = new MODDMA_Config;
+    conf
+     ->channelNum    ( MODDMA::Channel_0 )
+     ->srcMemAddr    ( 0 )
+     ->dstMemAddr    ( (uint32_t)adcInputBuffer )
+     ->transferSize  ( SAMPLE_BUFFER_LENGTH )
+     ->transferType  ( MODDMA::p2m )
+     ->transferWidth ( MODDMA::word )
+     ->srcConn       ( MODDMA::ADC )
+     ->dstConn       ( 0 )
+     ->dmaLLI        ( 0 )
+     ->attach_tc     ( &TC0_callback )
+     ->attach_err    ( &ERR0_callback )
+    ; // end conf.
+    
+    // Prepare configuration.
+    dma.Setup( conf );
+    
+    // Enable configuration.
+    dma.Enable( conf );
+    
+    // Enable ADC irq flag (to DMA).
+    // Note, don't set the individual flags,
+    // just set the global flag.
+    LPC_ADC->ADINTEN = 0x100;
+
+    // Enable burst mode on inputs 0 and 1.
+    LPC_ADC->ADCR |= (1UL << 16); 
+    
+    while (1) {
+        // When transfer complete do this block.
+        if (dmaTransferComplete) {
+            delete conf; // No memory leaks, delete the configuration.
+            dmaTransferComplete = false;
+            for (int i = 0; i < SAMPLE_BUFFER_LENGTH; i++) {
+                int channel = (adcInputBuffer[i] >> 24) & 0x7;
+                int iVal = (adcInputBuffer[i] >> 4) & 0xFFF;
+                double fVal = 3.3 * (double)((double)iVal) / ((double)0x1000); // scale to 0v to 3.3v
+                pc.printf("Array index %02d : ADC input channel %d = 0x%03x %01.3f volts\n", i, channel, iVal, fVal);                  
+            }
+        }
+        
+        // Just flash LED1 for something to do.
+        led1 = !led1;
+        wait(0.25);        
+    }
+}
+
+// Configuration callback on TC
+void TC0_callback(void) {
+    
+    MODDMA_Config *config = dma.getConfig();
+    
+    // Disbale burst mode and switch off the IRQ flag.
+    LPC_ADC->ADCR &= ~(1UL << 16);
+    LPC_ADC->ADINTEN = 0;    
+    
+    // Finish the DMA cycle by shutting down the channel.
+    dma.haltAndWaitChannelComplete( (MODDMA::CHANNELS)config->channelNum());
+    dma.Disable( (MODDMA::CHANNELS)config->channelNum() );
+    
+    // Tell main() while(1) loop to print the results.
+    dmaTransferComplete = true;            
+    
+    // Switch on LED2 to show transfer complete.
+    led2 = 1;        
+    
+    // Clear DMA IRQ flags.
+    if (dma.irqType() == MODDMA::TcIrq) dma.clearTcIrq();    
+    if (dma.irqType() == MODDMA::ErrIrq) dma.clearErrIrq();
+}
+
+// Configuration callback on Error
+void ERR0_callback(void) {
+    // Switch off burst conversions.
+    LPC_ADC->ADCR |= ~(1UL << 16);
+    LPC_ADC->ADINTEN = 0;
+    error("Oh no! My Mbed EXPLODED! :( Only kidding, go find the problem");
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/example3.h	Sun Mar 13 23:28:21 2011 +0000
@@ -0,0 +1,125 @@
+/*
+ * Demonstrates capturing the GPIO P0.4 to P0.7 "nibble" to memory 
+ * using GPDMA. The transfers from port pins to memory buffer are
+ * triggered using Timer1 MAT1.0 match compare.
+ *
+ * In this example all inputs have pullups. So with nothing connected
+ * the P0.4/7 reads as 0xF. Connecting a wire from one or more of the four 
+ * inputs to ground will show up in the captured buffer sequence.
+ */
+ 
+#include "mbed.h"
+#include "MODDMA.h"
+#include "iomacros.h" // within MODDMA library.
+
+// How long between grabbing GPIO FIO0PIN register.
+// Value is in microseconds. (50000 is half a second).
+#define SAMPLE_PERIOD   500000
+
+#define NUM_OF_SAMPLES  5
+
+Serial pc(USBTX, USBRX);
+
+DigitalOut led1(LED1);
+DigitalOut led2(LED2);
+DigitalOut led3(LED3);
+
+uint32_t buffer[NUM_OF_SAMPLES];
+
+bool dmaTransferComplete;
+
+MODDMA dma;
+MODDMA_Config *conf;
+
+void TC0_callback(void);
+void ERR0_callback(void);
+
+int main() {
+    
+    // Macros defined in iomacros.h, saves messing with DigitalIn
+    p30_AS_INPUT; p30_MODE( PIN_PULLUP ); // P0.4
+    p29_AS_INPUT; p29_MODE( PIN_PULLUP ); // P0.5
+    p8_AS_INPUT;  p8_MODE( PIN_PULLUP );  // P0.6
+    p7_AS_INPUT;  p7_MODE( PIN_PULLUP );  // P0.7
+    
+    // Clear the buffer.
+    memset(buffer, 0, sizeof(buffer));
+    
+    // Setup the serial port to print out results.
+    pc.baud(115200);
+    pc.printf("Starting up...\n");
+    
+    // Set-up timer1 as a periodic timer.
+    LPC_SC->PCONP    |= (1UL << 2); // TIM1 On
+    LPC_SC->PCLKSEL0 |= (3UL << 4); // CCLK/8 = 12MHz
+    LPC_TIM1->PR      = 11;         // TC clocks at 1MHz.
+    LPC_TIM1->MCR     = 2;          // Reset TCR to zero on match.
+    LPC_TIM1->MR0     = SAMPLE_PERIOD;
+    
+    // Prepare the GPDMA system.
+    conf = new MODDMA_Config;
+    conf
+     ->channelNum    ( MODDMA::Channel_0 )
+     ->srcMemAddr    ( (uint32_t)&LPC_GPIO0->FIOPIN )
+     ->dstMemAddr    ( (uint32_t)&buffer[0] )
+     ->transferSize  ( NUM_OF_SAMPLES )
+     ->transferType  ( MODDMA::g2m ) // pseudo transfer code MODDMA understands.
+     ->transferWidth ( MODDMA::word )
+     ->srcConn       ( MODDMA::MAT1_0 )
+     ->dmacSync      ( MODDMA::MAT1_0 ) 
+     ->attach_tc     ( TC0_callback )
+     ->attach_err    ( ERR0_callback )
+    ; // end conf.
+    
+    // Prepare configuration.
+    if (!dma.Setup( conf )) {
+        error("Doh!");
+    }
+    
+    // Enable GPDMA to be ready for the TIM1 "ticks".       
+    dma.Enable( conf );
+    
+    // Begin.
+    LPC_TIM1->TCR = 1;
+       
+    while (1) {          
+        led1 = !led1; // Show some sort of life.
+        
+        if (dmaTransferComplete) {
+            dmaTransferComplete = false;
+            for (int i = 0; i < NUM_OF_SAMPLES; i++) {
+                int val = (buffer[i] >> 4) & 0xF; 
+                pc.printf("Buffer index %d = 0x%x\n", i, val);
+            }
+            pc.printf("Done.\n");            
+        }
+    }       
+}
+
+// Configuration callback on TC
+void TC0_callback(void) {
+    
+    // Just show sample sequence grab complete.
+    led3 = !led3; 
+    
+    // Disable firing timer.
+    LPC_TIM1->TCR = 0;
+    
+    // Get configuration pointer.
+    MODDMA_Config *config = dma.getConfig();
+    
+    // Finish the DMA cycle by shutting down the channel.
+    dma.Disable( (MODDMA::CHANNELS)config->channelNum() );
+    
+    // Tell main() while(1) loop to print the results.
+    dmaTransferComplete = true;            
+    
+    // Clear DMA IRQ flags.
+    if (dma.irqType() == MODDMA::TcIrq) dma.clearTcIrq();    
+    if (dma.irqType() == MODDMA::ErrIrq) dma.clearErrIrq();
+}
+
+// Configuration callback on Error
+void ERR0_callback(void) {
+    error("Oh no! My Mbed EXPLODED! :( Only kidding, go find the problem");
+}
--- a/iomacros.h	Sun Mar 13 12:46:55 2011 +0000
+++ b/iomacros.h	Sun Mar 13 23:28:21 2011 +0000
@@ -71,6 +71,7 @@
 /* p8 is P0.6 */
 #define p8_SEL_MASK     ~(3UL << 12)
 #define p8_SET_MASK     (1UL <<  6)
+#define p8_CLR_MASK     ~(p8_SET_MASK)
 #define p8_AS_OUTPUT    LPC_PINCON->PINSEL0&=p8_SEL_MASK;LPC_GPIO0->FIODIR|=p8_SET_MASK
 #define p8_AS_INPUT     LPC_GPIO0->FIOMASK &= p8_CLR_MASK; 
 #define p8_SET          LPC_GPIO0->FIOSET = p8_SET_MASK