SPI RAM 23LC1024 (Microchip) with DMA

Dependencies:   mbed

Fork of SPIRAM_23LC1024 by Suga koubou

Files at this revision

API Documentation at this revision

Comitter:
okini3939
Date:
Wed Dec 05 07:56:09 2012 +0000
Parent:
1:a7b1803dfa44
Commit message:
DMX

Changed in this revision

MODDMA/CONFIG.h Show annotated file Show diff for this revision Revisions of this file
MODDMA/ChangeLog.c Show annotated file Show diff for this revision Revisions of this file
MODDMA/DATALUTS.cpp Show annotated file Show diff for this revision Revisions of this file
MODDMA/INIT.cpp Show annotated file Show diff for this revision Revisions of this file
MODDMA/MODDMA.cpp Show annotated file Show diff for this revision Revisions of this file
MODDMA/MODDMA.h Show annotated file Show diff for this revision Revisions of this file
MODDMA/SETUP.cpp Show annotated file Show diff for this revision Revisions of this file
MODDMA/example1.h Show annotated file Show diff for this revision Revisions of this file
MODDMA/example2.h Show annotated file Show diff for this revision Revisions of this file
MODDMA/example3.h Show annotated file Show diff for this revision Revisions of this file
MODDMA/example4.h Show annotated file Show diff for this revision Revisions of this file
MODDMA/iomacros.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MODDMA/CONFIG.h	Wed Dec 05 07:56:09 2012 +0000
@@ -0,0 +1,95 @@
+/*
+    Copyright (c) 2010 Andy Kirkham
+ 
+    Permission is hereby granted, free of charge, to any person obtaining a copy
+    of this software and associated documentation files (the "Software"), to deal
+    in the Software without restriction, including without limitation the rights
+    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+    copies of the Software, and to permit persons to whom the Software is
+    furnished to do so, subject to the following conditions:
+ 
+    The above copyright notice and this permission notice shall be included in
+    all copies or substantial portions of the Software.
+ 
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+    THE SOFTWARE.
+*/
+
+#ifdef NOCOMPILE
+
+#ifndef MODDMA_CONFIG_H
+#define MODDMA_CONFIG_H
+
+#include "mbed.h"
+
+namespace AjK {
+
+// Forward reference.
+class MODDMA;
+
+class  MODDMA_Channel_CFG_t {
+public:
+
+    // *****************************************
+    // From GPDMA by NXP MCU SW Application Team
+    // *****************************************
+    
+    uint32_t ChannelNum;        //!< DMA channel number, should be in range from 0 to 7. 
+    uint32_t TransferSize;      //!< Length/Size of transfer 
+    uint32_t TransferWidth;     //!< Transfer width - used for TransferType is GPDMA_TRANSFERTYPE_m2m only 
+    uint32_t SrcMemAddr;        //!< Physical Src Addr, used in case TransferType is chosen as MODDMA::GPDMA_TRANSFERTYPE::m2m or MODDMA::GPDMA_TRANSFERTYPE::m2p 
+    uint32_t DstMemAddr;        //!< Physical Destination Address, used in case TransferType is chosen as MODDMA::GPDMA_TRANSFERTYPE::m2m or MODDMA::GPDMA_TRANSFERTYPE::p2m 
+    uint32_t TransferType;      //!< Transfer Type
+    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'
+    
+    // Mbed specifics.
+    
+    MODDMA_Channel_CFG_t() {
+        isrIntTCStat  = new FunctionPointer;
+        isrIntErrStat = new FunctionPointer;
+    }
+    
+    ~MODDMA_Channel_CFG_t() {
+        delete(isrIntTCStat);
+        delete(isrIntErrStat);
+    }
+        
+    class MODDMA_Channel_CFG_t * channelNum(uint32_t n)    { ChannelNum = n;    return this; }
+    class MODDMA_Channel_CFG_t * transferSize(uint32_t n)  { TransferSize = n;  return this; }
+    class MODDMA_Channel_CFG_t * transferWidth(uint32_t n) { TransferWidth = n; return this; }
+    class MODDMA_Channel_CFG_t * srcMemAddr(uint32_t n)    { SrcMemAddr = n;    return this; }
+    class MODDMA_Channel_CFG_t * dstMemAddr(uint32_t n)    { DstMemAddr = n;    return this; }
+    class MODDMA_Channel_CFG_t * transferType(uint32_t n)  { TransferType = n;  return this; }
+    class MODDMA_Channel_CFG_t * srcConn(uint32_t n)       { SrcConn = n;       return this; }
+    class MODDMA_Channel_CFG_t * dstConn(uint32_t n)       { DstConn = n;       return this; }
+    class MODDMA_Channel_CFG_t * dmaLLI(uint32_t n)        { DMALLI = n;        return this; }
+    
+    uint32_t channelNum(void) { return ChannelNum; }
+    
+    FunctionPointer *isrIntTCStat;                        
+    FunctionPointer *isrIntErrStat;                        
+};
+
+/**
+ * @brief GPDMA Linker List Item structure type definition
+ */
+class GPDMA_LLI_t 
+{
+public:
+    uint32_t SrcAddr;    //!< Source Address 
+    uint32_t DstAddr;    //!< Destination address 
+    uint32_t NextLLI;    //!< Next LLI address, otherwise set to '0' 
+    uint32_t Control;    //!< GPDMA Control of this LLI 
+};
+
+}; // namespace AjK ends.
+
+#endif 
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MODDMA/ChangeLog.c	Wed Dec 05 07:56:09 2012 +0000
@@ -0,0 +1,74 @@
+/* $Id:$
+
+1.12- 14 Mar 2011
+
+    * Added example4.h that demonstrates alternately sending
+      two buffers (double buffering) to the DAC. All those
+      people building MP3 players may find this of interest.
+      
+1.11- 13 Mar 2011
+
+    * Fixed a silly typo in the documentation of example3.h
+    
+1.10- 13 Mar 2011
+
+    * The rescheduling showed the timer being stopped and restarted
+      to perform a new scheduled grab. This was changed to show the 
+      timer free running and the reschedules being setup.
+
+1.9 - 13 Mar 2011
+
+    * Improved example3.h to add rescheduling additional grabs
+      based on the timer setup.
+      
+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.
+    
+1.6 - 8 Mar 2011
+      
+    * Fixed a typo bug. Reported by Wim van der Vegt
+      http://mbed.org/forum/mbed/topic/1798/?page=1#comment-9845
+      
+1.5 - 5 Feb 2011
+
+    * Found a bug in the NXP library that I had copied over.
+      http://mbed.org/forum/mbed/topic/1798
+    * Added example2.cpp to support that forum thread.
+      
+1.4 - 23/11/2010
+
+    * Added some extra overloaded methods to make calling certain
+      userland API methods simpler.
+      
+1.3 - 23/10/2010
+
+    * Added the LLI class wrapper.
+    * Added checking channel's LLI for non-null before auto-disable
+      of a channel with the ISR.
+    * Tested with MODSERIAL which is now natively MODDMA "aware".
+      MODSERIAL can now, using MODDMA, send blocks of bytes out
+      of it's TX port under DMA control.
+        
+1.2 - 23/10/2010
+
+    * Improved the IRQ callback attachment API to make 
+      easier attachments when creating configurations.
+      
+1.1 - 23/10/2010
+
+    * Tidied up example1.cpp
+    * Removed some unneeded methoids that cause compiler errs.
+    
+1.0 - 23/11/2010
+
+    * First release
+
+*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MODDMA/DATALUTS.cpp	Wed Dec 05 07:56:09 2012 +0000
@@ -0,0 +1,147 @@
+/*
+    Copyright (c) 2010 Andy Kirkham
+ 
+    Permission is hereby granted, free of charge, to any person obtaining a copy
+    of this software and associated documentation files (the "Software"), to deal
+    in the Software without restriction, including without limitation the rights
+    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+    copies of the Software, and to permit persons to whom the Software is
+    furnished to do so, subject to the following conditions:
+ 
+    The above copyright notice and this permission notice shall be included in
+    all copies or substantial portions of the Software.
+ 
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+    THE SOFTWARE.
+*/
+
+#include "MODDMA.h"
+
+#ifndef MBED_H
+#include "mbed.h"
+#endif
+
+#ifndef MODDMA_CONFIG_H
+#include "CONFIG.h"
+#endif
+
+namespace AjK {
+
+uint32_t
+MODDMA::LUTPerAddr(int n)
+{
+    const uint32_t lut[] = { 
+          (uint32_t)&LPC_SSP0->DR         // SSP0 Tx
+        , (uint32_t)&LPC_SSP0->DR         // SSP0 Rx
+        , (uint32_t)&LPC_SSP1->DR         // SSP1 Tx
+        , (uint32_t)&LPC_SSP1->DR         // SSP1 Rx
+        , (uint32_t)&LPC_ADC->ADGDR       // ADC
+        , (uint32_t)&LPC_I2S->I2STXFIFO   // I2S Tx
+        , (uint32_t)&LPC_I2S->I2SRXFIFO   // I2S Rx
+        , (uint32_t)&LPC_DAC->DACR        // DAC
+        , (uint32_t)&LPC_UART0->THR       // UART0 Tx
+        , (uint32_t)&LPC_UART0->RBR       // UART0 Rx
+        , (uint32_t)&LPC_UART1->THR       // UART1 Tx
+        , (uint32_t)&LPC_UART1->RBR       // UART1 Rx
+        , (uint32_t)&LPC_UART2->THR       // UART2 Tx
+        , (uint32_t)&LPC_UART2->RBR       // UART2 Rx
+        , (uint32_t)&LPC_UART3->THR       // UART3 Tx
+        , (uint32_t)&LPC_UART3->RBR       // UART3 Rx
+        , (uint32_t)&LPC_TIM0->MR0        // MAT0.0
+        , (uint32_t)&LPC_TIM0->MR1        // MAT0.1
+        , (uint32_t)&LPC_TIM1->MR0        // MAT1.0
+        , (uint32_t)&LPC_TIM1->MR1        // MAT1.1
+        , (uint32_t)&LPC_TIM2->MR0        // MAT2.0
+        , (uint32_t)&LPC_TIM2->MR1        // MAT2.1
+        , (uint32_t)&LPC_TIM3->MR0        // MAT3.0
+        , (uint32_t)&LPC_TIM3->MR1        // MAT3.1   
+    };
+    return lut[n & 0xFF];    
+}
+
+uint32_t
+MODDMA::Channel_p(int channel)
+{
+    const uint32_t lut[] = {
+          (uint32_t)LPC_GPDMACH0
+        , (uint32_t)LPC_GPDMACH1
+        , (uint32_t)LPC_GPDMACH2
+        , (uint32_t)LPC_GPDMACH3
+        , (uint32_t)LPC_GPDMACH4
+        , (uint32_t)LPC_GPDMACH5
+        , (uint32_t)LPC_GPDMACH6
+        , (uint32_t)LPC_GPDMACH7
+    };
+    return lut[channel & 0xFF];
+}
+
+uint8_t
+MODDMA::LUTPerBurst(int n)
+{
+    const uint8_t lut[] = {
+          (uint8_t)_4       // SSP0 Tx 
+        , (uint8_t)_4       // SSP0 Rx
+        , (uint8_t)_4       // SSP1 Tx
+        , (uint8_t)_4       // SSP1 Rx
+        , (uint8_t)_1       // ADC
+        , (uint8_t)_32      // I2S channel 0
+        , (uint8_t)_32      // I2S channel 1
+        , (uint8_t)_1       // DAC
+        , (uint8_t)_1       // UART0 Tx
+        , (uint8_t)_1       // UART0 Rx
+        , (uint8_t)_1       // UART1 Tx
+        , (uint8_t)_1       // UART1 Rx
+        , (uint8_t)_1       // UART2 Tx
+        , (uint8_t)_1       // UART2 Rx
+        , (uint8_t)_1       // UART3 Tx
+        , (uint8_t)_1       // UART3 Rx
+        , (uint8_t)_1       // MAT0.0
+        , (uint8_t)_1       // MAT0.1
+        , (uint8_t)_1       // MAT1.0
+        , (uint8_t)_1       // MAT1.1
+        , (uint8_t)_1       // MAT2.0
+        , (uint8_t)_1       // MAT2.1
+        , (uint8_t)_1       // MAT3.0
+        , (uint8_t)_1       // MAT3.1
+    };
+    return lut[n & 0xFFF];
+}
+
+uint8_t
+MODDMA::LUTPerWid(int n)
+{
+    const uint8_t lut[] = {
+          (uint8_t)byte      // SSP0 Tx
+        , (uint8_t)byte      // SSP0 Rx
+        , (uint8_t)byte      // SSP1 Tx
+        , (uint8_t)byte      // SSP1 Rx
+        , (uint8_t)word      // ADC
+        , (uint8_t)word      // I2S channel 0
+        , (uint8_t)word      // I2S channel 1
+        , (uint8_t)word      // DAC 
+        , (uint8_t)byte      // UART0 Tx
+        , (uint8_t)byte      // UART0 Rx
+        , (uint8_t)byte      // UART1 Tx
+        , (uint8_t)byte      // UART1 Rx
+        , (uint8_t)byte      // UART2 Tx
+        , (uint8_t)byte      // UART2 Rx
+        , (uint8_t)byte      // UART3 Tx
+        , (uint8_t)byte      // UART3 Rx  
+        , (uint8_t)word      // MAT0.0
+        , (uint8_t)word      // MAT0.1
+        , (uint8_t)word      // MAT1.0
+        , (uint8_t)word      // MAT1.1
+        , (uint8_t)word      // MAT2.0
+        , (uint8_t)word      // MAT2.1
+        , (uint8_t)word      // MAT3.0
+        , (uint8_t)word      // MAT3.1  
+    };
+    return lut[n & 0xFFF];
+}
+
+}; // namespace AjK ends
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MODDMA/INIT.cpp	Wed Dec 05 07:56:09 2012 +0000
@@ -0,0 +1,69 @@
+/*
+    Copyright (c) 2010 Andy Kirkham
+ 
+    Permission is hereby granted, free of charge, to any person obtaining a copy
+    of this software and associated documentation files (the "Software"), to deal
+    in the Software without restriction, including without limitation the rights
+    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+    copies of the Software, and to permit persons to whom the Software is
+    furnished to do so, subject to the following conditions:
+ 
+    The above copyright notice and this permission notice shall be included in
+    all copies or substantial portions of the Software.
+ 
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+    THE SOFTWARE.
+*/
+
+#include "MODDMA.h"
+
+namespace AjK {
+
+extern uint32_t oldDMAHandler;
+extern "C" void MODDMA_IRQHandler(void);
+extern class MODDMA *moddma_p;
+
+void
+MODDMA::init(bool isConstructorCalling, int Channels, int Tc, int Err)
+{
+    if (isConstructorCalling) {    
+        if (LPC_SC->PCONP & (1UL << 29)) {
+            if (LPC_GPDMA->DMACConfig & 1) {
+                error("Only one instance of MODDMA can exist.");
+            }
+        }
+        LPC_SC->PCONP |= (1UL << 29);
+        LPC_GPDMA->DMACConfig = 1;
+        moddma_p = this;
+        for (int i = 0; i < 8; i++) {
+            setups[i] = (MODDMA_Config *)NULL;
+        }        
+    }
+    
+    // Reset channel configuration register(s)
+    if (Channels & 0x01) LPC_GPDMACH0->DMACCConfig = 0;
+    if (Channels & 0x02) LPC_GPDMACH1->DMACCConfig = 0;
+    if (Channels & 0x04) LPC_GPDMACH2->DMACCConfig = 0;
+    if (Channels & 0x08) LPC_GPDMACH3->DMACCConfig = 0;
+    if (Channels & 0x10) LPC_GPDMACH4->DMACCConfig = 0;
+    if (Channels & 0x20) LPC_GPDMACH5->DMACCConfig = 0;
+    if (Channels & 0x40) LPC_GPDMACH6->DMACCConfig = 0;
+    if (Channels & 0x80) LPC_GPDMACH7->DMACCConfig = 0;
+
+    /* Clear DMA interrupt and error flag */
+    LPC_GPDMA->DMACIntTCClear = Tc;
+    LPC_GPDMA->DMACIntErrClr  = Err;
+    
+    if (isConstructorCalling) {    
+        oldDMAHandler = NVIC_GetVector(DMA_IRQn);
+        NVIC_SetVector(DMA_IRQn, (uint32_t)MODDMA_IRQHandler);
+        NVIC_EnableIRQ(DMA_IRQn);
+    }
+}
+
+}; // namespace AjK ends
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MODDMA/MODDMA.cpp	Wed Dec 05 07:56:09 2012 +0000
@@ -0,0 +1,157 @@
+/*
+    Copyright (c) 2010 Andy Kirkham
+ 
+    Permission is hereby granted, free of charge, to any person obtaining a copy
+    of this software and associated documentation files (the "Software"), to deal
+    in the Software without restriction, including without limitation the rights
+    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+    copies of the Software, and to permit persons to whom the Software is
+    furnished to do so, subject to the following conditions:
+ 
+    The above copyright notice and this permission notice shall be included in
+    all copies or substantial portions of the Software.
+ 
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+    THE SOFTWARE.
+*/
+#include "iomacros.h"
+#include "MODDMA.h"
+
+namespace AjK {
+
+// Create a "hook" for our ISR to make callbacks. Set by init()
+class MODDMA *moddma_p = (class MODDMA *)NULL;
+
+void
+MODDMA::Enable(CHANNELS ChannelNumber)
+{
+    LPC_GPDMACH_TypeDef *pChannel = (LPC_GPDMACH_TypeDef *)Channel_p( ChannelNumber );
+    pChannel->DMACCConfig |= _E;
+}
+
+bool
+MODDMA::Enabled(CHANNELS ChannelNumber)
+{
+    LPC_GPDMACH_TypeDef *pChannel = (LPC_GPDMACH_TypeDef *)Channel_p( ChannelNumber );    
+    return (bool)(pChannel->DMACCConfig & _E);
+}
+
+void
+MODDMA::Disable(CHANNELS ChannelNumber)
+{
+    LPC_GPDMACH_TypeDef *pChannel = (LPC_GPDMACH_TypeDef *)Channel_p( ChannelNumber );
+    pChannel->DMACCConfig &= ~(_E);
+}
+
+bool
+MODDMA::isActive(CHANNELS ChannelNumber)
+{
+    LPC_GPDMACH_TypeDef *pChannel = (LPC_GPDMACH_TypeDef *)Channel_p( ChannelNumber );
+    return (bool)( pChannel->DMACCConfig & CxConfig_A() ) ;
+}
+
+void 
+MODDMA::haltChannel(CHANNELS ChannelNumber)
+{
+    LPC_GPDMACH_TypeDef *pChannel = (LPC_GPDMACH_TypeDef *)Channel_p( ChannelNumber );
+    pChannel->DMACCConfig |= CxConfig_H();
+}
+
+uint32_t 
+MODDMA::getControl(CHANNELS ChannelNumber)
+{
+    LPC_GPDMACH_TypeDef *pChannel = (LPC_GPDMACH_TypeDef *)Channel_p( ChannelNumber );
+    return pChannel->DMACCControl;
+}
+
+uint32_t oldDMAHandler = 0;
+typedef void (*MODDMA_FN)(void);
+
+extern "C" void MODDMA_IRQHandler(void) {
+    uint32_t channel_mask;
+        
+    if (moddma_p == (class MODDMA *)NULL) {
+        if (oldDMAHandler) {
+            ((MODDMA_FN)oldDMAHandler)();
+            return;
+        }
+        else {
+            error("Interrupt without instance");
+        }
+    }
+    
+    for (int channel_number = 0; channel_number < 8; channel_number++) {
+        channel_mask = (1UL << channel_number);
+        if (LPC_GPDMA->DMACIntStat & channel_mask) {
+            if (LPC_GPDMA->DMACIntTCStat & channel_mask) {
+                if (moddma_p->setups[channel_number] != (MODDMA_Config *)NULL) {
+                    moddma_p->setIrqProcessingChannel((MODDMA::CHANNELS)channel_number);
+                    moddma_p->setIrqType(MODDMA::TcIrq);
+                    moddma_p->setups[channel_number]->isrIntTCStat->call();
+                    moddma_p->isrIntTCStat.call();
+                    // The user callback should clear the IRQ. But if they forget
+                    // then the Mbed will lockup. So, check to see if the IRQ has
+                    // been dismissed, if not, we will dismiss it here.
+                    if (LPC_GPDMA->DMACIntTCStat & channel_mask) {
+                        LPC_GPDMA->DMACIntTCClear = channel_mask;
+                    }
+                    // If the user has left the channel enabled, disable it.
+                    // Note, we don't check Active here as it may block inside
+                    // an ISR, we just shut it down immediately. If the user
+                    // must wait for completion they should implement their
+                    // own ISR. But only disable if the LLI linked list register
+                    // is null otherwise we can crap out a series of transfers.
+                    if (moddma_p->Enabled( (MODDMA::CHANNELS)channel_number )) {
+                        if (moddma_p->lli( (MODDMA::CHANNELS)channel_number ) == 0 ) {
+                            moddma_p->Disable( (MODDMA::CHANNELS)channel_number ); 
+                        }
+                    }
+                }            
+            }
+            
+            if (LPC_GPDMA->DMACIntErrStat & channel_mask) {
+                if (moddma_p->setups[channel_number] != (MODDMA_Config *)NULL) {
+                    moddma_p->setIrqProcessingChannel((MODDMA::CHANNELS)channel_number);
+                    moddma_p->setIrqType(MODDMA::ErrIrq);
+                    moddma_p->setups[channel_number]->isrIntErrStat->call();
+                    moddma_p->isrIntErrStat.call();
+                    // The user callback should clear the IRQ. But if they forget
+                    // then the Mbed will lockup. So, check to see if the IRQ has
+                    // been dismissed, if not, we will dismiss it here.
+                    if (LPC_GPDMA->DMACIntErrStat & channel_mask) {
+                        LPC_GPDMA->DMACIntErrClr = channel_mask;
+                    }
+                    // If the user has left the channel enabled, disable it.
+                    // Not, we don't check Active here as it may block inside
+                    // an ISR, we just shut it down immediately. If the user
+                    // must wait for completion they should implement their
+                    // own ISR. But only disable if the LLI linked list register
+                    // is null otherwise we can crap out a series of transfers.
+                    if (moddma_p->Enabled( (MODDMA::CHANNELS)channel_number )) {
+                        if (moddma_p->lli( (MODDMA::CHANNELS)channel_number ) == 0 ) {
+                            moddma_p->Disable( (MODDMA::CHANNELS)channel_number ); 
+                        }
+                    }
+                }            
+            }
+        }
+    }
+    
+    /* IRQ should be handled by now, check to make sure. */
+    if (LPC_GPDMA->DMACIntStat) {
+        ((MODDMA_FN)oldDMAHandler)();
+        LPC_GPDMA->DMACIntTCClear = (uint32_t)0xFF; /* If not, clear anyway! */
+    }
+    if (LPC_GPDMA->DMACIntErrStat) {
+        ((MODDMA_FN)oldDMAHandler)();
+        LPC_GPDMA->DMACIntErrClr = (uint32_t)0xFF; /* If not, clear anyway! */
+    }
+}
+
+}; // namespace AjK ends
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MODDMA/MODDMA.h	Wed Dec 05 07:56:09 2012 +0000
@@ -0,0 +1,693 @@
+/*
+    Copyright (c) 2010 Andy Kirkham
+ 
+    Permission is hereby granted, free of charge, to any person obtaining a copy
+    of this software and associated documentation files (the "Software"), to deal
+    in the Software without restriction, including without limitation the rights
+    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+    copies of the Software, and to permit persons to whom the Software is
+    furnished to do so, subject to the following conditions:
+ 
+    The above copyright notice and this permission notice shall be included in
+    all copies or substantial portions of the Software.
+ 
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+    THE SOFTWARE.
+    
+    @file          MODDMA.h 
+    @purpose       Adds DMA controller and multiple transfer configurations
+    @version       see ChangeLog.c
+    @date          Nov 2010
+    @author        Andy Kirkham    
+*/
+
+#ifndef MODDMA_H
+#define MODDMA_H
+
+/** @defgroup API The MODDMA API */
+/** @defgroup MISC Misc MODSERIAL functions */
+/** @defgroup INTERNALS MODSERIAL Internals */
+
+#include "mbed.h"
+#include "iomacros.h"
+
+namespace AjK {
+
+/**
+ * @brief The MODDMA configuration system
+ * @author Andy Kirkham
+ * @see http://mbed.org/cookbook/MODDMA_Config
+ * @see MODDMA
+ * @see API 
+ *
+ * <b>MODDMA_Config</b> defines a configuration that can be passed to the MODDMA controller
+ * instance to perform a GPDMA data transfer.
+ */
+class  MODDMA_Config {
+protected:
+
+    // *****************************************
+    // From GPDMA by NXP MCU SW Application Team
+    // *****************************************
+    
+    uint32_t ChannelNum;        //!< DMA channel number, should be in range from 0 to 7. 
+    uint32_t TransferSize;      //!< Length/Size of transfer 
+    uint32_t TransferWidth;     //!< Transfer width - used for TransferType is GPDMA_TRANSFERTYPE_m2m only 
+    uint32_t SrcMemAddr;        //!< Physical Src Addr, used in case TransferType is chosen as MODDMA::GPDMA_TRANSFERTYPE::m2m or MODDMA::GPDMA_TRANSFERTYPE::m2p 
+    uint32_t DstMemAddr;        //!< Physical Destination Address, used in case TransferType is chosen as MODDMA::GPDMA_TRANSFERTYPE::m2m or MODDMA::GPDMA_TRANSFERTYPE::p2m 
+    uint32_t TransferType;      //!< Transfer Type
+    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.
+
+public: 
+   
+    MODDMA_Config() {
+        isrIntTCStat  = new FunctionPointer;
+        isrIntErrStat = new FunctionPointer;
+        ChannelNum    = 0xFFFF;
+        TransferSize  = 0;
+        TransferWidth = 0;
+        SrcMemAddr    = 0;
+        DstMemAddr    = 0;
+        TransferType  = 0;
+        SrcConn       = 0;
+        DstConn       = 0;
+        DMALLI        = 0;
+        DMACSync      = 0;
+    }
+    
+    ~MODDMA_Config() {
+        delete(isrIntTCStat);
+        delete(isrIntErrStat);
+    }
+        
+    class MODDMA_Config * channelNum(uint32_t n)    { ChannelNum = n & 0x7;  return this; }
+    class MODDMA_Config * transferSize(uint32_t n)  { TransferSize = n;      return this; }
+    class MODDMA_Config * transferWidth(uint32_t n) { TransferWidth = n;     return this; }
+    class MODDMA_Config * srcMemAddr(uint32_t n)    { SrcMemAddr = n;        return this; }
+    class MODDMA_Config * dstMemAddr(uint32_t n)    { DstMemAddr = n;        return this; }
+    class MODDMA_Config * transferType(uint32_t n)  { TransferType = n;      return this; }
+    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;  }
+    uint32_t transferWidth(void) { return TransferWidth; }
+    uint32_t srcMemAddr(void)    { return SrcMemAddr;    }
+    uint32_t dstMemAddr(void)    { return DstMemAddr;    }
+    uint32_t transferType(void)  { return TransferType;  }
+    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.
+     *
+     * @param fptr A function pointer to call
+     * @return this
+     */
+    class MODDMA_Config * attach_tc(void (*fptr)(void)) {  
+        isrIntTCStat->attach(fptr); 
+        return this;
+    }
+    
+    /**
+     * Attach a callback to the ERR IRQ configuration.
+     *
+     * @param fptr A function pointer to call
+     * @return this
+     */
+    class MODDMA_Config * attach_err(void (*fptr)(void)) {  
+        isrIntErrStat->attach(fptr);         
+        return this;
+    }
+    
+    /**
+     * Attach a callback to the TC IRQ configuration.
+     *
+     * @param tptr A template pointer to the calling object
+     * @param mptr A method pointer within the object to call.
+     * @return this
+     */
+    template<typename T>
+    class MODDMA_Config * attach_tc(T* tptr, void (T::*mptr)(void)) {  
+        if((mptr != NULL) && (tptr != NULL)) {
+            isrIntTCStat->attach(tptr, mptr);
+        }
+        return this;
+    }
+    
+    /**
+     * Attach a callback to the ERR IRQ configuration.
+     *
+     * @param tptr A template pointer to the calling object
+     * @param mptr A method pointer within the object to call.
+     * @return this
+     */
+    template<typename T>
+    class MODDMA_Config * attach_err(T* tptr, void (T::*mptr)(void)) {  
+        if((mptr != NULL) && (tptr != NULL)) {
+            isrIntErrStat->attach(tptr, mptr);
+        }
+        return this;
+    }
+    FunctionPointer *isrIntTCStat;                        
+    FunctionPointer *isrIntErrStat;                        
+};
+
+/**
+ * @brief The MODDMA configuration system (linked list items)
+ * @author Andy Kirkham
+ * @see http://mbed.org/cookbook/MODDMA_Config
+ * @see MODDMA
+ * @see MODDMA_Config
+ * @see API 
+ */
+class MODDMA_LLI {
+public:
+    class MODDMA_LLI *srcAddr(uint32_t n) { SrcAddr = n; return this; }
+    class MODDMA_LLI *dstAddr(uint32_t n) { DstAddr = n; return this; }
+    class MODDMA_LLI *nextLLI(uint32_t n) { NextLLI = n; return this; }
+    class MODDMA_LLI *control(uint32_t n) { Control = n; return this; }
+    uint32_t srcAddr(void) { return SrcAddr; }
+    uint32_t dstAddr(void) { return DstAddr; }
+    uint32_t nextLLI(void) { return NextLLI; }
+    uint32_t control(void) { return Control; }
+
+    uint32_t SrcAddr;    //!< Source Address 
+    uint32_t DstAddr;    //!< Destination address 
+    uint32_t NextLLI;    //!< Next LLI address, otherwise set to '0' 
+    uint32_t Control;    //!< GPDMA Control of this LLI 
+};
+
+
+
+ /**
+ * @brief MODDMA GPDMA Controller
+ * @author Andy Kirkham
+ * @see http://mbed.org/cookbook/MODDMA
+ * @see example1.cpp
+ * @see API 
+ *
+ * <b>MODDMA</b> defines a GPDMA controller and multiple DMA configurations that allow for DMA
+ * transfers from memory to memory, memory to peripheral or peripheral to memory.
+ *
+ * At the heart of the library is the MODDMA class that defines a single instance controller that
+ * manages all the GPDMA hardware registers and interrupts. The controller can accept multiple
+ * configurations that define the channel transfers. Each configuration specifies the source and 
+ * destination information and other associated parts to maintain the transfer process.
+ *
+ * Standard example:
+ * @code
+ * #include "mbed.h"
+ * #include "MODDMA.h"
+ *
+ * DigitalOut led1(LED1);
+ * Serial pc(USBTX, USBRX); // tx, rx
+ * MODDMA dma;
+ *
+ * int main() {
+ *
+ *     // Create a string buffer to send directly to a Uart/Serial
+ *     char s[] = "***DMA*** ABCDEFGHIJKLMNOPQRSTUVWXYZ ***DMA***";
+ *
+ *     // Create a transfer configuarion
+ *     MODDMA_Config *config = new MODDMA_Config;
+ *
+ *     // Provide a "minimal" setup for demo purposes.
+ *     config
+ *      ->channelNum    ( MODDMA::Channel_0 )   // The DMA channel to use.
+ *      ->srcMemAddr    ( (uint32_t) &s )       // A pointer to the buffer to send.
+ *      ->transferSize  ( sizeof(s) )           // The size of that buffer.
+ *      ->transferType  ( MODDMA::m2p )         // Source is memory, destination is peripheral
+ *      ->dstConn       ( MODDMA::UART0_Tx )    // Specifically, peripheral is Uart0 TX (USBTX, USBRX)
+ *    ; // config end.
+ *
+ *    // Pass the configuration to the MODDMA controller.
+ *    dma.Setup( config );
+ *
+ *    // Enable the channel and begin transfer.
+ *    dma.Enable( config->channelNum() );
+ *
+ *    while(1) {
+ *         led1 = !led1;
+ *         wait(0.25);
+ *     }
+ * }
+ * @endcode
+ */
+class MODDMA
+{
+public:
+
+    //! Channel definitions.
+    enum CHANNELS {
+          Channel_0 = 0     /*!< Channel 0 */ 
+        , Channel_1         /*!< Channel 1 */ 
+        , Channel_2         /*!< Channel 2 */ 
+        , Channel_3         /*!< Channel 3 */ 
+        , Channel_4         /*!< Channel 4 */ 
+        , Channel_5         /*!< Channel 5 */ 
+        , Channel_6         /*!< Channel 6 */ 
+        , Channel_7         /*!< Channel 7 */ 
+    };
+    
+    //! Interrupt callback types.
+    enum IrqType_t {
+          TcIrq = 0     /*!< Terminal Count interrupt */
+        , ErrIrq        /*!< Error interrupt */
+    };
+    
+    //! Return status codes.
+    enum Status {
+          Ok            = 0     /*!< Ok, suceeded */
+        , Error         = -1    /*!< General error */
+        , ErrChInUse    = -2    /*!< Specific error, channel in use */
+    };
+    
+    //! DMA Connection number definitions 
+    enum GPDMA_CONNECTION {
+          SSP0_Tx       = 0UL   /*!< SSP0 Tx */
+        , SSP0_Rx       = 1UL   /*!< SSP0 Rx */
+        , SSP1_Tx       = 2UL   /*!< SSP1 Tx */
+        , SSP1_Rx       = 3UL   /*!< SSP1 Rx */
+        , ADC           = 4UL   /*!< ADC */
+        , I2S_Channel_0 = 5UL   /*!< I2S channel 0 */
+        , I2S_Channel_1 = 6UL   /*!< I2S channel 1 */
+        , DAC           = 7UL   /*!< DAC */
+        , UART0_Tx      = 8UL   /*!< UART0 Tx */
+        , UART0_Rx      = 9UL   /*!< UART0 Rx */
+        , UART1_Tx      = 10UL  /*!< UART1 Tx */
+        , UART1_Rx      = 11UL  /*!< UART1 Rx */
+        , UART2_Tx      = 12UL  /*!< UART2 Tx */
+        , UART2_Rx      = 13UL  /*!< UART2 Rx */
+        , UART3_Tx      = 14UL  /*!< UART3 Tx */
+        , UART3_Rx      = 15UL  /*!< UART3 Rx */
+        , MAT0_0        = 16UL  /*!< MAT0.0 */
+        , MAT0_1        = 17UL  /*!< MAT0.1 */
+        , MAT1_0        = 18UL  /*!< MAT1.0 */
+        , MAT1_1        = 19UL  /*!< MAT1.1 */
+        , MAT2_0        = 20UL  /**< MAT2.0 */
+        , MAT2_1        = 21UL  /*!< MAT2.1 */
+        , MAT3_0        = 22UL  /*!< MAT3.0 */
+        , MAT3_1        = 23UL  /*!< MAT3.1 */
+    };
+
+    //! GPDMA Transfer type definitions 
+    enum  GPDMA_TRANSFERTYPE {
+          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 */         
+        , 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 */
+    enum GPDMA_BSIZE {
+          _1    = 0UL   /*!< Burst size = 1 */
+        , _4    = 1UL   /*!< Burst size = 4 */
+        , _8    = 2UL   /*!< Burst size = 8 */
+        , _16   = 3UL   /*!< Burst size = 16 */
+        , _32   = 4UL   /*!< Burst size = 32 */
+        , _64   = 5UL   /*!< Burst size = 64 */
+        , _128  = 6UL   /*!< Burst size = 128 */
+        , _256  = 7UL   /*!< Burst size = 256 */
+    };
+    
+    //! Width in Src transfer width and Dest transfer width definitions */
+    enum GPDMA_WIDTH {
+          byte     = 0UL    /*!< Width = 1 byte */
+        , halfword = 1UL    /*!< Width = 2 bytes */
+        , word     = 2UL    /*!< Width = 4 bytes */
+    };
+    
+    //! DMA Request Select Mode definitions. */
+    enum GPDMA_REQSEL {
+          uart  = 0UL   /*!< UART TX/RX is selected */
+        , timer = 1UL   /*!< Timer match is selected */
+    };
+
+    //! GPDMA Control register bits.
+    enum Config {
+          _E = 1        /*!< DMA Controller enable */
+        , _M = 2        /*!< AHB Master endianness configuration */
+    };    
+
+    //! GPDMA Channel config register bits.
+    enum CConfig {
+          _CE  = (1UL << 0)     /*!< Channel enable */
+        , _IE  = (1UL << 14)    /*!< Interrupt error mask */
+        , _ITC = (1UL << 15)    /*!< Terminal count interrupt mask */
+        , _L   = (1UL << 16)    /*!< Lock */
+        , _A   = (1UL << 17)    /*!< Active */
+        , _H   = (1UL << 18)    /*!< Halt */
+    };
+    
+    /**
+     * The MODDMA constructor is used to initialise the DMA controller object.
+     */    
+    MODDMA() { init(true); }
+    
+    /**
+     * The MODDMA destructor.
+     */    
+    ~MODDMA() {}
+    
+    /**
+     * Used to setup the DMA controller to prepare for a data transfer.
+     *
+     * @ingroup API
+     * @param isConstructorCalling Set true when called from teh constructor
+     * @param 
+     */
+    void init(bool isConstructorCalling, int Channels = 0xFF, int Tc = 0xFF, int Err = 0xFF);
+    
+    /**
+     * Used to setup and enable the DMA controller.
+     *
+     * @see Setup
+     * @see Enable
+     * @ingroup API
+     * @param c A pointer to an instance of MODDMA_Config to setup.
+     */
+    uint32_t Prepare(MODDMA_Config *c) {
+        uint32_t u = Setup(c);
+        if (u) Enable(c);
+        return u;
+    }
+    
+    /**
+     * Used to setup the DMA controller to prepare for a data transfer.
+     *
+     * @ingroup API
+     * @param c A pointer to an instance of MODDMA_Config to setup.
+     */
+    uint32_t Setup(MODDMA_Config *c);
+    
+    /**
+     * Enable and begin data transfer.
+     *
+     * @ingroup API
+     * @param ChannelNumber Type CHANNELS, the channel number to enable
+     */
+    void Enable(CHANNELS ChannelNumber);
+    
+    /**
+     * Enable and begin data transfer (overloaded function)
+     *
+     * @ingroup API
+     * @param ChannelNumber Type uin32_t, the channel number to enable
+     */
+    void Enable(uint32_t ChannelNumber) { Enable((CHANNELS)(ChannelNumber & 0x7)); }
+    
+    /**
+     * Enable and begin data transfer (overloaded function)
+     *
+     * @ingroup API
+     * @param config A pointer to teh configuration
+     */
+    void Enable(MODDMA_Config *config) { Enable( config->channelNum() ); }
+        
+    
+    /**
+     * Disable a channel and end data transfer.
+     *
+     * @ingroup API
+     * @param ChannelNumber Type CHANNELS, the channel number to enable
+     */
+    void Disable(CHANNELS ChannelNumber);
+    
+    /**
+     * Disable a channel and end data transfer (overloaded function)
+     *
+     * @ingroup API
+     * @param ChannelNumber Type uin32_t, the channel number to disable
+     */
+    void Disable(uint32_t ChannelNumber) { Disable((CHANNELS)(ChannelNumber & 0x7)); }
+    
+    /**
+     * Is the specified channel enabled?
+     *
+     * @ingroup API
+     * @param ChannelNumber Type CHANNELS, the channel number to test
+     * @return bool true if enabled, false otherwise.
+     */
+    bool Enabled(CHANNELS ChannelNumber);
+    
+    /**
+     * Is the specified channel enabled? (overloaded function)
+     *
+     * @ingroup API
+     * @param ChannelNumber Type uin32_t, the channel number to test
+     * @return bool true if enabled, false otherwise.
+     */
+    bool Enabled(uint32_t ChannelNumber) { return Enabled((CHANNELS)(ChannelNumber & 0x7)); }
+    
+    __INLINE uint32_t IntStat(uint32_t n)            { return (1UL << n) & 0xFF; }
+    __INLINE uint32_t IntTCStat_Ch(uint32_t n)       { return (1UL << n) & 0xFF; }
+    __INLINE uint32_t IntTCClear_Ch(uint32_t n)      { return (1UL << n) & 0xFF; }
+    __INLINE uint32_t IntErrStat_Ch(uint32_t n)      { return (1UL << n) & 0xFF; }
+    __INLINE uint32_t IntErrClr_Ch(uint32_t n)       { return (1UL << n) & 0xFF; }
+    __INLINE uint32_t RawIntErrStat_Ch(uint32_t n)   { return (1UL << n) & 0xFF; }
+    __INLINE uint32_t EnbldChns_Ch(uint32_t n)       { return (1UL << n) & 0xFF; }
+    __INLINE uint32_t SoftBReq_Src(uint32_t n)       { return (1UL << n) & 0xFFFF; }
+    __INLINE uint32_t SoftSReq_Src(uint32_t n)       { return (1UL << n) & 0xFFFF; }
+    __INLINE uint32_t SoftLBReq_Src(uint32_t n)      { return (1UL << n) & 0xFFFF; }
+    __INLINE uint32_t SoftLSReq_Src(uint32_t n)      { return (1UL << n) & 0xFFFF; }
+    __INLINE uint32_t Sync_Src(uint32_t n)           { return (1UL << n) & 0xFFFF; }
+    __INLINE uint32_t ReqSel_Input(uint32_t n)       { return (1UL << (n - 8)) & 0xFF; }
+    
+
+    __INLINE uint32_t CxControl_TransferSize(uint32_t n)     { return (n & 0xFFF) << 0; }
+    __INLINE uint32_t CxControl_SBSize(uint32_t n)           { return (n & 0x7) << 12; }
+    __INLINE uint32_t CxControl_DBSize(uint32_t n)           { return (n & 0x7) << 15; }
+    __INLINE uint32_t CxControl_SWidth(uint32_t n)           { return (n & 0x7) << 18; }
+    __INLINE uint32_t CxControl_DWidth(uint32_t n)           { return (n & 0x7) << 21; }
+    __INLINE uint32_t CxControl_SI()                         { return (1UL << 26); }
+    __INLINE uint32_t CxControl_DI()                         { return (1UL << 27); }
+    __INLINE uint32_t CxControl_Prot1()                      { return (1UL << 28); }
+    __INLINE uint32_t CxControl_Prot2()                      { return (1UL << 29); }
+    __INLINE uint32_t CxControl_Prot3()                      { return (1UL << 30); }
+    __INLINE uint32_t CxControl_I()                          { return (1UL << 31); }
+    __INLINE uint32_t CxControl_E()                          { return (1UL << 0); }
+    __INLINE uint32_t CxConfig_SrcPeripheral(uint32_t n)     { return (n & 0x1F) << 1; }
+    __INLINE uint32_t CxConfig_DestPeripheral(uint32_t n)    { return (n & 0x1F) << 6; }
+    __INLINE uint32_t CxConfig_TransferType(uint32_t n)      { return (n & 0x7) << 11; }
+    __INLINE uint32_t CxConfig_IE()                          { return (1UL << 14); }
+    __INLINE uint32_t CxConfig_ITC()                         { return (1UL << 15); }
+    __INLINE uint32_t CxConfig_L()                           { return (1UL << 16); }
+    __INLINE uint32_t CxConfig_A()                           { return (1UL << 17); }
+    __INLINE uint32_t CxConfig_H()                           { return (1UL << 18); }
+    
+    /**
+     * A store for up to 8 (8 channels) of configurations.
+     * @see MODDMA_Config
+     */
+    MODDMA_Config *setups[8];
+    
+    /**
+     * Get a pointer to the current configuration the ISR is servicing.
+     *
+     * @ingroup API
+     * @return MODDMA_Config * A pointer to the setup the ISR is currently servicing.
+     */
+    MODDMA_Config *getConfig(void) { return setups[IrqProcessingChannel]; }
+    
+    /**
+     * Set which channel the ISR is currently servicing.
+     *
+     * *** USED INTERNALLY. DO NOT CALL FROM USER PROGRAMS ***
+     *
+     * Must be public so the extern "C" ISR can use it.
+     */
+    void setIrqProcessingChannel(CHANNELS n) { IrqProcessingChannel = n; }
+    
+    /**
+     * Gets which channel the ISR is currently servicing.
+     *
+     * @ingroup API
+     * @return CHANNELS The current channel the ISR is servicing.
+     */
+    CHANNELS irqProcessingChannel(void) { return IrqProcessingChannel; }
+    
+    /**
+     * Sets which type of IRQ the ISR is making a callback for.
+     *
+     * *** USED INTERNALLY. DO NOT CALL FROM USER PROGRAMS ***
+     *
+     * Must be public so the extern "C" ISR can use it.
+     */ 
+    void setIrqType(IrqType_t n) { IrqType = n; }
+    
+    /**
+     * Get which type of IRQ the ISR is calling you about,
+     * terminal count or error.
+     */
+    IrqType_t irqType(void) { return IrqType; }
+    
+    /**
+     * Clear the interrupt after handling.
+     *
+     * @param CHANNELS The channel the IQR occured on.
+     */
+    void clearTcIrq(CHANNELS n) { LPC_GPDMA->DMACIntTCClear = (uint32_t)(1UL << n); } 
+    
+    /**
+     * Clear the interrupt the ISR is currently handing..
+     */
+    void clearTcIrq(void) { clearTcIrq( IrqProcessingChannel ); }
+    
+    /**
+     * Clear the error interrupt after handling.
+     *
+     * @ingroup API
+     * @param CHANNELS The channel the IQR occured on.
+     */
+    void clearErrIrq(CHANNELS n) { LPC_GPDMA->DMACIntTCClear = (uint32_t)(1UL << n); } 
+    
+    /**
+     * Clear the error interrupt the ISR is currently handing.
+     * @ingroup API
+     */
+    void clearErrIrq(void) { clearErrIrq( IrqProcessingChannel ); }
+   
+    /**
+     * Is the supplied channel currently active?
+     *
+     * @ingroup API
+     * @param CHANNELS The channel to inquire about.
+     * @return bool true if active, false otherwise.
+     */     
+    bool isActive(CHANNELS ChannelNumber);
+    
+    /**
+     * Halt the supplied channel. 
+     *
+     * @ingroup API
+     * @param CHANNELS The channel to halt.
+     */
+    void haltChannel(CHANNELS ChannelNumber);
+    
+    /**
+     * get a channels control register. 
+     *
+     * @ingroup API
+     * @param CHANNELS The channel to get the control register for.
+     */
+    uint32_t getControl(CHANNELS ChannelNumber);
+    
+    /**
+     * Wait for channel transfer to complete and then halt.
+     *
+     * @ingroup API
+     * @param CHANNELS The channel to wait for then halt.
+     */
+    void haltAndWaitChannelComplete(CHANNELS n) { haltChannel(n); while (isActive(n)); }
+    
+    /**
+     * Attach a callback to the TC IRQ controller.
+     *
+     * @ingroup API
+     * @param fptr A function pointer to call
+     * @return this
+     */
+    void attach_tc(void (*fptr)(void)) {  
+        isrIntTCStat.attach(fptr);         
+    }
+    
+    /**
+     * Attach a callback to the TC IRQ controller.
+     *
+     * @ingroup API
+     * @param tptr A template pointer to the calling object
+     * @param mptr A method pointer within the object to call.
+     * @return this
+     */
+    template<typename T>
+    void attach_tc(T* tptr, void (T::*mptr)(void)) {  
+        if((mptr != NULL) && (tptr != NULL)) {
+            isrIntTCStat.attach(tptr, mptr);         
+        }        
+    }
+       
+    /**
+     * The MODDMA controllers terminal count interrupt callback.
+     */
+    FunctionPointer isrIntTCStat;                        
+    
+    /**
+     * Attach a callback to the ERR IRQ controller.
+     *
+     * @ingroup API
+     * @param fptr A function pointer to call
+     * @return this
+     */
+    void attach_err(void (*fptr)(void)) {  
+        isrIntErrStat.attach(fptr);                 
+    }
+    
+    /**
+     * Attach a callback to the ERR IRQ controller.
+     *
+     * @ingroup API
+     * @param tptr A template pointer to the calling object
+     * @param mptr A method pointer within the object to call.
+     * @return this
+     */
+    template<typename T>
+    void attach_err(T* tptr, void (T::*mptr)(void)) {  
+        if((mptr != NULL) && (tptr != NULL)) {
+            isrIntErrStat.attach(tptr, mptr);         
+        }
+    }
+    
+    /**
+     * Get the Linked List index regsiter for the requested channel.
+     *
+     * @param channelNum The channel number.
+     * @return uint32_t The value of the DMACCLLI register
+     */
+    uint32_t lli(CHANNELS ChannelNumber, MODDMA_LLI *set = 0) { 
+        LPC_GPDMACH_TypeDef *pChannel = (LPC_GPDMACH_TypeDef *)Channel_p( ChannelNumber & 0x7 );
+        if (set) pChannel->DMACCLLI = (uint32_t)set;
+        return pChannel->DMACCLLI; 
+    }
+    
+    /**
+     * The MODDMA controllers error interrupt callback.
+     */
+    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);
+    
+    CHANNELS IrqProcessingChannel;
+    
+    IrqType_t IrqType;
+};
+
+}; // namespace AjK ends.
+
+using namespace AjK;
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MODDMA/SETUP.cpp	Wed Dec 05 07:56:09 2012 +0000
@@ -0,0 +1,194 @@
+/*
+    Copyright (c) 2010 Andy Kirkham
+ 
+    Permission is hereby granted, free of charge, to any person obtaining a copy
+    of this software and associated documentation files (the "Software"), to deal
+    in the Software without restriction, including without limitation the rights
+    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+    copies of the Software, and to permit persons to whom the Software is
+    furnished to do so, subject to the following conditions:
+ 
+    The above copyright notice and this permission notice shall be included in
+    all copies or substantial portions of the Software.
+ 
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+    THE SOFTWARE.
+*/
+
+#include "MODDMA.h"
+
+namespace AjK {
+
+uint32_t
+MODDMA::Setup(MODDMA_Config *config)
+{
+    LPC_GPDMACH_TypeDef *pChannel = (LPC_GPDMACH_TypeDef *)Channel_p( config->channelNum() );
+    
+    setups[config->channelNum() & 0x7] = config;
+    
+    // Reset the Interrupt status
+    LPC_GPDMA->DMACIntTCClear = IntTCClear_Ch( config->channelNum() );
+    LPC_GPDMA->DMACIntErrClr  = IntErrClr_Ch ( config->channelNum() );
+
+    // Clear DMA configure
+    pChannel->DMACCControl = 0x00;
+    pChannel->DMACCConfig  = 0x00;
+
+    // Assign Linker List Item value 
+    pChannel->DMACCLLI = config->dmaLLI();
+
+    // Set value to Channel Control Registers 
+    switch (config->transferType()) {
+    
+        // Memory to memory
+        case m2m:
+            // Assign physical source and destination address
+            pChannel->DMACCSrcAddr  = config->srcMemAddr();
+            pChannel->DMACCDestAddr = config->dstMemAddr();
+            pChannel->DMACCControl
+                = CxControl_TransferSize(config->transferSize()) 
+                | CxControl_SBSize(_32) 
+                | CxControl_DBSize(_32) 
+                | CxControl_SWidth(config->transferWidth()) 
+                | CxControl_DWidth(config->transferWidth()) 
+                | CxControl_SI() 
+                | CxControl_DI() 
+                | CxControl_I();
+            break;
+        
+        // Memory to peripheral
+        case m2p:
+            // Assign physical source
+            pChannel->DMACCSrcAddr = config->srcMemAddr();
+            // Assign peripheral destination address
+            pChannel->DMACCDestAddr = (uint32_t)LUTPerAddr(config->dstConn());
+            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;
+            
+        // Peripheral to memory
+        case p2m:
+            // Assign peripheral source address
+            pChannel->DMACCSrcAddr = (uint32_t)LUTPerAddr(config->srcConn());
+            // 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;
+            
+        // Peripheral to peripheral
+        case p2p:
+            // Assign peripheral source address
+            pChannel->DMACCSrcAddr = (uint32_t)LUTPerAddr(config->srcConn());
+            // Assign peripheral destination address
+            pChannel->DMACCDestAddr = (uint32_t)LUTPerAddr(config->dstConn());
+            pChannel->DMACCControl
+                = CxControl_TransferSize((uint32_t)config->transferSize()) 
+                | CxControl_SBSize((uint32_t)LUTPerBurst(config->srcConn())) 
+                | CxControl_DBSize((uint32_t)LUTPerBurst(config->dstConn())) 
+                | CxControl_SWidth((uint32_t)LUTPerWid(config->srcConn())) 
+                | CxControl_DWidth((uint32_t)LUTPerWid(config->dstConn())) 
+                | 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;
+    }
+/*
+     // Re-Configure DMA Request Select for source peripheral 
+    if (config->srcConn() > 15) {
+        LPC_SC->RESERVED9 |= (1 << (config->srcConn() - 16));
+    } 
+    else {
+        LPC_SC->RESERVED9 &= ~(1 << (config->srcConn() - 8));
+    }
+
+    // Re-Configure DMA Request Select for destination peripheral
+    if (config->dstConn() > 15) {
+        LPC_SC->RESERVED9 |= (1 << (config->dstConn() - 16));
+    } 
+    else {
+        LPC_SC->RESERVED9 &= ~(1 << (config->dstConn() - 8));
+    }
+*/
+    // Enable DMA channels, little endian 
+    LPC_GPDMA->DMACConfig = _E;
+    while (!(LPC_GPDMA->DMACConfig & _E));
+
+    // Calculate absolute value for Connection number
+    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(tfer_type) 
+        | CxConfig_SrcPeripheral(tmp1) 
+        | CxConfig_DestPeripheral(tmp2);
+
+    return pChannel->DMACCControl;
+}
+
+}; // namespace AjK ends
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MODDMA/example1.h	Wed Dec 05 07:56:09 2012 +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");
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MODDMA/example2.h	Wed Dec 05 07:56:09 2012 +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/MODDMA/example3.h	Wed Dec 05 07:56:09 2012 +0000
@@ -0,0 +1,131 @@
+/*
+ * 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. (500000 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() {
+    volatile int life_counter = 0;
+     
+    // 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) { 
+        if (life_counter++ > 1000000) {
+            led1 = !led1; // Show some sort of life.
+            life_counter = 0;
+        }
+        
+        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");
+            
+            // Schedule another grab.
+            if (dma.Setup( conf )) {        
+                dma.Enable( conf );                
+            }            
+        }
+    }       
+}
+
+// Configuration callback on TC
+void TC0_callback(void) {
+    
+    // Just show sample sequence grab complete.
+    led3 = !led3; 
+        
+    // 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");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MODDMA/example4.h	Wed Dec 05 07:56:09 2012 +0000
@@ -0,0 +1,156 @@
+/*
+ * Demonstrates sending a buffer repeatedly to the DAC using DMA.
+ * Connect an oscilloscope to Mbed pin 18. This example doesn't
+ * output anything else (nothing on any serial ports).
+ */
+#include "mbed.h"
+#include "MODDMA.h"
+
+// Make the buffer size match the number of degrees
+// in a circle since we are going to output a sinewave.
+#define BUFFER_SIZE 360
+
+// Set DAC output power mode.
+#define DAC_POWER_MODE  (1 << 16)
+
+DigitalOut led1(LED1);
+DigitalOut led3(LED3);
+DigitalOut led4(LED4);
+
+int buffer[2][BUFFER_SIZE];
+
+AnalogOut signal(p18);
+
+MODDMA dma;
+MODDMA_Config *conf0, *conf1;
+
+void TC0_callback(void);
+void ERR0_callback(void);
+
+void TC1_callback(void);
+void ERR1_callback(void);
+
+int main() {
+    volatile int life_counter = 0;
+    
+    // Create a sinewave buffer for testing.
+    for (int i =   0; i <=  90; i++) buffer[0][i] =  (512 * sin(3.14159/180.0 * i)) + 512;                
+    for (int i =  91; i <= 180; i++) buffer[0][i] =  buffer[0][180 - i];
+    for (int i = 181; i <= 270; i++) buffer[0][i] =  512 - (buffer[0][i - 180] - 512);
+    for (int i = 271; i <  360; i++) buffer[0][i] =  512 - (buffer[0][360 - i] - 512);
+    
+    // Adjust the sinewave buffer for use with DAC hardware.
+    for (int i = 0; i < 360; i++) {
+        buffer[0][i] = DAC_POWER_MODE | ((buffer[0][i] << 6) & 0xFFC0);
+        buffer[1][i] = buffer[0][i]; // Just create a copy of buffer0 to continue sinewave.
+    }
+    
+    // Prepare the GPDMA system for buffer0.
+    conf0 = new MODDMA_Config;
+    conf0
+     ->channelNum    ( MODDMA::Channel_0 )
+     ->srcMemAddr    ( (uint32_t) &buffer[0] )
+     ->dstMemAddr    ( MODDMA::DAC )
+     ->transferSize  ( 360 )
+     ->transferType  ( MODDMA::m2p )
+     ->dstConn       ( MODDMA::DAC )
+     ->attach_tc     ( &TC0_callback )
+     ->attach_err    ( &ERR0_callback )     
+    ; // config end
+    
+    
+    // Prepare the GPDMA system for buffer1.
+    conf1 = new MODDMA_Config;
+    conf1
+     ->channelNum    ( MODDMA::Channel_1 )
+     ->srcMemAddr    ( (uint32_t) &buffer[1] )
+     ->dstMemAddr    ( MODDMA::DAC )
+     ->transferSize  ( 360 )
+     ->transferType  ( MODDMA::m2p )
+     ->dstConn       ( MODDMA::DAC )
+     ->attach_tc     ( &TC1_callback )
+     ->attach_err    ( &ERR1_callback )     
+    ; // config end
+
+    
+    // Calculating the transfer frequency:
+    // By default, the Mbed library sets the PCLK_DAC clock value
+    // to 24MHz. One complete sinewave cycle in each buffer is 360
+    // points long. So, for a 1Hz wave we would need to transfer 360
+    // values per second. That would be 24000000/360 which is approx
+    // 66,666. But that's no good! The count val is only 16bits in size
+    // so bare this in mind. If you need to go slower you will need to
+    // alter PCLK_DAC from CCLK/4 to CCLK/8.
+    // For our demo we are going to have the sinewave run at 1kHz.
+    // That's 24000000/360000 which is approx 66. Experimentation
+    // however showed 65 to get closer to 1kHz (on my Mbed and scope 
+    // at least).
+    LPC_DAC->DACCNTVAL = 65; // 6500 for 10Hz
+
+    // Prepare first configuration.
+    if (!dma.Prepare( conf0 )) {
+        error("Doh!");
+    }
+    
+    // Begin (enable DMA and counter). Note, don't enable
+    // DBLBUF_ENA as we are using DMA double buffering.
+    LPC_DAC->DACCTRL |= (3UL << 2);
+    
+    while (1) { 
+        // There's not a lot to do as DMA and interrupts are
+        // now handling the buffer transfers. So we'll just
+        // flash led1 to show the Mbed is alive and kicking.
+        if (life_counter++ > 1000000) {
+            led1 = !led1; // Show some sort of life.
+            life_counter = 0;
+        }
+    } 
+}
+
+// Configuration callback on TC
+void TC0_callback(void) {
+    
+    // Just show sending buffer0 complete.
+    led3 = !led3; 
+        
+    // Get configuration pointer.
+    MODDMA_Config *config = dma.getConfig();
+    
+    // Finish the DMA cycle by shutting down the channel.
+    dma.Disable( (MODDMA::CHANNELS)config->channelNum() );
+   
+    // Swap to buffer1
+    dma.Prepare( conf1 );
+
+    // Clear DMA IRQ flags.
+    if (dma.irqType() == MODDMA::TcIrq) dma.clearTcIrq(); 
+}
+
+// Configuration callback on Error
+void ERR0_callback(void) {
+    error("Oh no! My Mbed EXPLODED! :( Only kidding, go find the problem");
+}
+
+// Configuration callback on TC
+void TC1_callback(void) {
+    
+    // Just show sending buffer1 complete.
+    led4 = !led4; 
+        
+    // Get configuration pointer.
+    MODDMA_Config *config = dma.getConfig();
+    
+    // Finish the DMA cycle by shutting down the channel.
+    dma.Disable( (MODDMA::CHANNELS)config->channelNum() );
+    
+    // Swap to buffer0
+    dma.Prepare( conf0 );
+    
+    // Clear DMA IRQ flags.
+    if (dma.irqType() == MODDMA::TcIrq) dma.clearTcIrq(); 
+}
+
+// Configuration callback on Error
+void ERR1_callback(void) {
+    error("Oh no! My Mbed EXPLODED! :( Only kidding, go find the problem");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MODDMA/iomacros.h	Wed Dec 05 07:56:09 2012 +0000
@@ -0,0 +1,418 @@
+/*
+    Copyright (c) 2011 Andy Kirkham
+ 
+    Permission is hereby granted, free of charge, to any person obtaining a copy
+    of this software and associated documentation files (the "Software"), to deal
+    in the Software without restriction, including without limitation the rights
+    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+    copies of the Software, and to permit persons to whom the Software is
+    furnished to do so, subject to the following conditions:
+ 
+    The above copyright notice and this permission notice shall be included in
+    all copies or substantial portions of the Software.
+ 
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+    THE SOFTWARE.
+*/
+
+#ifndef IOMACROS_H
+#define IOMACROS_H
+
+#ifndef __LPC17xx_H__
+#include "LPC17xx.h"
+#endif
+
+#define PIN_PULLUP      0UL
+#define PIN_REPEAT      1UL
+#define PIN_NONE        2UL
+#define PIN_PULLDOWN    3UL
+
+/* p5 is P0.9 */
+#define p5_SEL_MASK     ~(3UL << 18)
+#define p5_SET_MASK     (1UL << 9)
+#define p5_CLR_MASK     ~(p5_SET_MASK)
+#define p5_AS_OUTPUT    LPC_PINCON->PINSEL0&=p5_SEL_MASK;LPC_GPIO0->FIODIR|=p5_SET_MASK
+#define p5_AS_INPUT     LPC_GPIO0->FIOMASK &= p5_CLR_MASK; 
+#define p5_SET          LPC_GPIO0->FIOSET = p5_SET_MASK
+#define p5_CLR          LPC_GPIO0->FIOCLR = p5_SET_MASK
+#define p5_IS_SET       (bool)(LPC_GPIO0->FIOPIN & p5_SET_MASK)
+#define p5_IS_CLR       !(p5_IS_SET)
+#define p5_MODE(x)      LPC_PINCON->PINMODE0&=p5_SEL_MASK;LPC_PINCON->PINMODE0|=((x&0x3)<<18)
+
+/* p6 is P0.8 */
+#define p6_SEL_MASK     ~(3UL << 16)
+#define p6_SET_MASK     (1UL <<  8)
+#define p6_CLR_MASK     ~(p6_SET_MASK)
+#define p6_AS_OUTPUT    LPC_PINCON->PINSEL0&=p6_SEL_MASK;LPC_GPIO0->FIODIR|=p6-SET_MASK
+#define p6_AS_INPUT     LPC_GPIO0->FIOMASK &= p6_CLR_MASK; 
+#define p6_SET          LPC_GPIO0->FIOSET = p6_SET_MASK
+#define p6_CLR          LPC_GPIO0->FIOCLR = p6_SET_MASK
+#define p6_IS_SET       (bool)(LPC_GPIO0->FIOPIN & p6_SET_MASK)
+#define p6_IS_CLR       !(p6_IS_SET)
+#define p6_MODE(x)      LPC_PINCON->PINMODE0&=p6_SEL_MASK;LPC_PINCON->PINMODE0|=((x&0x3)<<16)    
+
+/* p7 is P0.7 */
+#define p7_SEL_MASK     ~(3UL << 14)
+#define p7_SET_MASK     (1UL <<  7)
+#define p7_CLR_MASK     ~(p7_SET_MASK)
+#define p7_AS_OUTPUT    LPC_PINCON->PINSEL0&=p7_SEL_MASK;LPC_GPIO0->FIODIR|=p7_SET_MASK
+#define p7_AS_INPUT     LPC_GPIO0->FIOMASK &= p7_CLR_MASK; 
+#define p7_SET          LPC_GPIO0->FIOSET = p7_SET_MASK
+#define p7_CLR          LPC_GPIO0->FIOCLR = p7_SET_MASK
+#define p7_IS_SET       (bool)(LPC_GPIO0->FIOPIN & p7_SET_MASK)
+#define p7_IS_CLR       !(p7_IS_SET)
+#define p7_MODE(x)      LPC_PINCON->PINMODE0&=p7_SEL_MASK;LPC_PINCON->PINMODE0|=((x&0x3)<<14)    
+
+/* 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
+#define p8_CLR          LPC_GPIO0->FIOCLR = p8_SET_MASK
+#define p8_IS_SET       (bool)(LPC_GPIO0->FIOPIN & p8_SET_MASK)
+#define p8_IS_CLR       !(p8_IS_SET)
+#define p8_MODE(x)      LPC_PINCON->PINMODE0&=p8_SEL_MASK;LPC_PINCON->PINMODE0|=((x&0x3)<<12)    
+
+/* p9 is P0.0 */
+#define p9_SEL_MASK     ~(3UL <<  0)
+#define p9_SET_MASK     (1UL <<  0)
+#define p9_CLR_MASK     ~(p9_SET_MASK)
+#define p9_AS_OUTPUT    LPC_PINCON->PINSEL0&=p9_SEL_MASK;LPC_GPIO0->FIODIR|=p9_SET_MASK
+#define p9_AS_INPUT     LPC_GPIO0->FIOMASK &= p9_CLR_MASK; 
+#define p9_SET          LPC_GPIO0->FIOSET = p9_SET_MASK
+#define p9_CLR          LPC_GPIO0->FIOCLR = p9_SET_MASK
+#define p9_IS_SET       (bool)(LPC_GPIO0->FIOPIN & p9_SET_MASK)
+#define p9_IS_CLR       !(p9_IS_SET)
+#define p9_MODE(x)      LPC_PINCON->PINMODE0&=p9_SEL_MASK;LPC_PINCON->PINMODE0|=((x&0x3)<<0)    
+
+/* p10 is P0.1 */
+#define p10_SEL_MASK    ~(3UL <<  2)
+#define p10_SET_MASK    (1UL <<  1)
+#define p10_CLR_MASK    ~(p10_SET_MASK)
+#define p10_AS_OUTPUT   LPC_PINCON->PINSEL0&=p10_SEL_MASK;LPC_GPIO0->FIODIR|=p10_SET_MASK
+#define p10_AS_INPUT    LPC_GPIO0->FIOMASK &= p10_CLR_MASK; 
+#define p10_SET         LPC_GPIO0->FIOSET = p10_SET_MASK
+#define p10_CLR         LPC_GPIO0->FIOCLR = p10_SET_MASK
+#define p10_IS_SET      (bool)(LPC_GPIO0->FIOPIN & p10_SET_MASK)
+#define p10_IS_CLR      !(p10_IS_SET)
+#define p10_MODE(x)     LPC_PINCON->PINMODE0&=p10_SEL_MASK;LPC_PINCON->PINMODE0|=((x&0x3)<<2)
+
+/* p11 is P0.18 */
+#define p11_SEL_MASK    ~(3UL << 4)
+#define p11_SET_MASK    (1UL <<  18)
+#define p11_CLR_MASK    ~(p11_SET_MASK)
+#define p11_AS_OUTPUT   LPC_PINCON->PINSEL1&=p11_SEL_MASK;LPC_GPIO0->FIODIR|=p11_SET_MASK
+#define p11_AS_INPUT    LPC_GPIO0->FIOMASK &= p11_CLR_MASK; 
+#define p11_SET         LPC_GPIO0->FIOSET = p11_SET_MASK
+#define p11_CLR         LPC_GPIO0->FIOCLR = p11_SET_MASK
+#define p11_IS_SET      (bool)(LPC_GPIO0->FIOPIN & p11_SET_MASK)
+#define p11_IS_CLR      !(p11_IS_SET)
+#define p11_MODE(x)     LPC_PINCON->PINMODE1&=p11_SEL_MASK;LPC_PINCON->PINMODE1|=((x&0x3)<<4)
+
+/* p12 is P0.17 */
+#define p12_SEL_MASK    ~(3UL << 2)
+#define p12_SET_MASK    (1UL << 17)
+#define p12_CLR_MASK    ~(p12_SET_MASK)
+#define p12_AS_OUTPUT   LPC_PINCON->PINSEL1&=p12_SEL_MASK;LPC_GPIO0->FIODIR|=p12_SET_MASK
+#define p12_AS_INPUT    LPC_GPIO0->FIOMASK &= p12_CLR_MASK; 
+#define p12_SET         LPC_GPIO0->FIOSET = p12_SET_MASK
+#define p12_CLR         LPC_GPIO0->FIOCLR = p12_SET_MASK
+#define p12_IS_SET      (bool)(LPC_GPIO0->FIOPIN & p12_SET_MASK)
+#define p12_IS_CLR      !(p12_IS_SET)
+#define p12_MODE(x)     LPC_PINCON->PINMODE1&=p12_SEL_MASK;LPC_PINCON->PINMODE1|=((x&0x3)<<2)
+
+/* p13 is P0.15 */
+#define p13_SEL_MASK    ~(3UL << 30)
+#define p13_SET_MASK    (1UL << 15)
+#define p13_CLR_MASK    ~(p13_SET_MASK)
+#define p13_AS_OUTPUT   LPC_PINCON->PINSEL0&=p13_SEL_MASK;LPC_GPIO0->FIODIR|=p13_SET_MASK
+#define p13_AS_INPUT    LPC_GPIO0->FIOMASK &= p13_CLR_MASK; 
+#define p13_SET         LPC_GPIO0->FIOSET = p13_SET_MASK
+#define p13_CLR         LPC_GPIO0->FIOCLR = p13_SET_MASK
+#define p13_IS_SET      (bool)(LPC_GPIO0->FIOPIN & p13_SET_MASK)
+#define p13_IS_CLR      !(p13_IS_SET)
+#define p13_MODE(x)     LPC_PINCON->PINMODE0&=p13_SEL_MASK;LPC_PINCON->PINMODE0|=((x&0x3)<<30)
+
+/* p14 is P0.16 */
+#define p14_SEL_MASK    ~(3UL << 0)
+#define p14_SET_MASK    (1UL << 16)
+#define p14_CLR_MASK    ~(p14_SET_MASK)
+#define p14_AS_OUTPUT   LPC_PINCON->PINSEL1&=p14_SEL_MASK;LPC_GPIO0->FIODIR|=p14_SET_MASK
+#define p14_AS_INPUT    LPC_GPIO0->FIOMASK &= p14_CLR_MASK; 
+#define p14_SET         LPC_GPIO0->FIOSET = p14_SET_MASK
+#define p14_CLR         LPC_GPIO0->FIOCLR = p14_SET_MASK
+#define p14_IS_SET      (bool)(LPC_GPIO0->FIOPIN & p14_SET_MASK)
+#define p14_IS_CLR      !(p14_IS_SET)
+#define p14_MODE(x)     LPC_PINCON->PINMODE1&=p14_SEL_MASK;LPC_PINCON->PINMODE1|=((x&0x3)<<0)
+
+/* p15 is P0.23 */
+#define p15_SEL_MASK    ~(3UL << 14)
+#define p15_SET_MASK    (1UL << 23)
+#define p15_CLR_MASK    ~(p15_SET_MASK)
+#define p15_AS_OUTPUT   LPC_PINCON->PINSEL1&=p15_SEL_MASK;LPC_GPIO0->FIODIR|=p15_SET_MASK
+#define p15_AS_INPUT    LPC_GPIO0->FIOMASK &= p15_CLR_MASK; 
+#define p15_SET         LPC_GPIO0->FIOSET = p15_SET_MASK
+#define p15_CLR         LPC_GPIO0->FIOCLR = p15_SET_MASK
+#define p15_IS_SET      (bool)(LPC_GPIO0->FIOPIN & p15_SET_MASK)
+#define p15_IS_CLR      !(p15_IS_SET)
+#define p15_MODE(x)     LPC_PINCON->PINMODE1&=p15_SEL_MASK;LPC_PINCON->PINMODE1|=((x&0x3)<<14)
+
+/* p16 is P0.24 */
+#define p16_SEL_MASK    ~(3UL << 16)
+#define p16_SET_MASK    (1UL <<  24)
+#define p16_CLR_MASK    ~(p16_SET_MASK)
+#define p16_AS_OUTPUT   LPC_PINCON->PINSEL1&=p16_SEL_MASK;LPC_GPIO0->FIODIR|=p16_SET_MASK
+#define p16_AS_INPUT    LPC_GPIO0->FIOMASK &= p16_CLR_MASK; 
+#define p16_SET         LPC_GPIO0->FIOSET = p16_SET_MASK
+#define p16_CLR         LPC_GPIO0->FIOCLR = p16_SET_MASK
+#define p16_IS_SET      (bool)(LPC_GPIO0->FIOPIN & p16_SET_MASK)
+#define p16_IS_CLR      !(p16_IS_SET)
+#define p16_MODE(x)     LPC_PINCON->PINMODE1&=p16_SEL_MASK;LPC_PINCON->PINMODE1|=((x&0x3)<<16)
+
+/* p17 is P0.25 */
+#define p17_SEL_MASK    ~(3UL <<  18)
+#define p17_SET_MASK    (1UL <<  25)
+#define p17_CLR_MASK    ~(p17_SET_MASK)
+#define p17_AS_OUTPUT   LPC_PINCON->PINSEL1&=p17_SEL_MASK;LPC_GPIO0->FIODIR|=p17_SET_MASK
+#define p17_AS_INPUT    LPC_GPIO0->FIOMASK &= p17_CLR_MASK; 
+#define p17_SET         LPC_GPIO0->FIOSET = p17_SET_MASK
+#define p17_CLR         LPC_GPIO0->FIOCLR = p17_SET_MASK
+#define p17_IS_SET      (bool)(LPC_GPIO0->FIOPIN & p17_SET_MASK)
+#define p17_IS_CLR      !(p17_IS_SET)
+#define p17_MODE(x)     LPC_PINCON->PINMODE1&=p17_SEL_MASK;LPC_PINCON->PINMODE1|=((x&0x3)<<18)
+
+/* p18 is P0.26 */
+#define p18_SEL_MASK    ~(3UL << 20)
+#define p18_SET_MASK    (1UL << 26)
+#define p18_CLR_MASK    ~(p18_SET_MASK)
+#define p18_AS_OUTPUT   LPC_PINCON->PINSEL1&=p18_SEL_MASK;LPC_GPIO0->FIODIR|=p18_SET_MASK
+#define p18_AS_INPUT    LPC_GPIO0->FIOMASK &= p18_CLR_MASK; 
+#define p18_SET         LPC_GPIO0->FIOSET = p18_SET_MASK
+#define p18_CLR         LPC_GPIO0->FIOCLR = p18_SET_MASK
+#define p18_IS_SET      (bool)(LPC_GPIO0->FIOPIN & p18_SET_MASK)
+#define p18_IS_CLR      !(p18_IS_SET)
+#define p18_MODE(x)     LPC_PINCON->PINMODE1&=p18_SEL_MASK;LPC_PINCON->PINMODE1|=((x&0x3)<<20)
+
+/* p19 is P1.30 */
+#define p19_SEL_MASK    ~(3UL << 28)
+#define p19_SET_MASK    (1UL << 30)
+#define p19_AS_OUTPUT   LPC_PINCON->PINSEL3&=p19_SEL_MASK;LPC_GPIO1->FIODIR|=p19_SET_MASK
+#define p19_AS_INPUT    LPC_GPIO1->FIOMASK &= p19_CLR_MASK; 
+#define p19_SET         LPC_GPIO1->FIOSET = p19_SET_MASK
+#define p19_CLR         LPC_GPIO1->FIOCLR = p19_SET_MASK
+#define p19_IS_SET      (bool)(LPC_GPIO1->FIOPIN & p19_SET_MASK)
+#define p19_IS_CLR      !(p19_IS_SET)
+#define p19_MODE(x)     LPC_PINCON->PINMODE3&=p19_SEL_MASK;LPC_PINCON->PINMODE3|=((x&0x3)<<28)
+
+/* p20 is P1.31 */
+#define p20_SEL_MASK    ~(3UL << 30)
+#define p20_SET_MASK    (1UL << 31)
+#define p20_CLR_MASK    ~(p20_SET_MASK)
+#define p20_AS_OUTPUT   LPC_PINCON->PINSEL3&=p20_SEL_MASK;LPC_GPIO1->FIODIR|=p20_SET_MASK
+#define p20_AS_INPUT    LPC_GPIO1->FIOMASK &= p20_CLR_MASK; 
+#define p20_SET         LPC_GPIO1->FIOSET = p20_SET_MASK
+#define p20_CLR         LPC_GPIO1->FIOCLR = p20_SET_MASK
+#define p20_IS_SET      (bool)(LPC_GPIO1->FIOPIN & p20_SET_MASK)
+#define p20_IS_CLR      !(p20_IS_SET)
+#define p20_MODE(x)     LPC_PINCON->PINMODE3&=p20_SEL_MASK;LPC_PINCON->PINMODE3|=((x&0x3)<<30)
+
+/* p21 is P2.5 */
+#define p21_SEL_MASK    ~(3UL << 10)
+#define p21_SET_MASK    (1UL << 5)
+#define p21_CLR_MASK    ~(p21_SET_MASK)
+#define p21_AS_OUTPUT   LPC_PINCON->PINSEL4&=p21_SEL_MASK;LPC_GPIO2->FIODIR|=p21_SET_MASK
+#define p21_AS_INPUT    LPC_GPIO2->FIOMASK &= p21_CLR_MASK; 
+#define p21_SET         LPC_GPIO2->FIOSET = p21_SET_MASK
+#define p21_CLR         LPC_GPIO2->FIOCLR = p21_SET_MASK
+#define p21_IS_SET      (bool)(LPC_GPIO2->FIOPIN & p21_SET_MASK)
+#define p21_IS_CLR      !(p21_IS_SET)
+#define p21_TOGGLE      p21_IS_SET?p21_CLR:p21_SET
+#define p21_MODE(x)     LPC_PINCON->PINMODE4&=p21_SEL_MASK;LPC_PINCON->PINMODE4|=((x&0x3)<<10)
+
+/* p22 is P2.4 */
+#define p22_SEL_MASK    ~(3UL << 8)
+#define p22_SET_MASK    (1UL << 4)
+#define p22_CLR_MASK    ~(p22_SET_MASK)
+#define p22_AS_OUTPUT   LPC_PINCON->PINSEL4&=p22_SEL_MASK;LPC_GPIO2->FIODIR|=p22_SET_MASK
+#define p22_AS_INPUT    LPC_GPIO2->FIOMASK &= p22_CLR_MASK; 
+#define p22_SET         LPC_GPIO2->FIOSET = p22_SET_MASK
+#define p22_CLR         LPC_GPIO2->FIOCLR = p22_SET_MASK
+#define p22_IS_SET      (bool)(LPC_GPIO2->FIOPIN & p22_SET_MASK)
+#define p22_IS_CLR      !(p22_IS_SET)
+#define p22_TOGGLE      p22_IS_SET?p22_CLR:p22_SET
+#define p22_MODE(x)     LPC_PINCON->PINMODE4&=p22_SEL_MASK;LPC_PINCON->PINMODE4|=((x&0x3)<<8)
+
+/* p23 is P2.3 */
+#define p23_SEL_MASK    ~(3UL << 6)
+#define p23_SET_MASK    (1UL << 3)
+#define p23_CLR_MASK    ~(p23_SET_MASK)
+#define p23_AS_OUTPUT   LPC_PINCON->PINSEL4&=p23_SEL_MASK;LPC_GPIO2->FIODIR|=p23_SET_MASK
+#define p23_AS_INPUT    LPC_GPIO2->FIOMASK &= p23_CLR_MASK; 
+#define p23_SET         LPC_GPIO2->FIOSET = p23_SET_MASK
+#define p23_CLR         LPC_GPIO2->FIOCLR = p23_SET_MASK
+#define p23_IS_SET      (bool)(LPC_GPIO2->FIOPIN & p23_SET_MASK)
+#define p23_IS_CLR      !(p23_IS_SET)
+#define p23_TOGGLE      p23_IS_SET?p23_CLR:p23_SET
+#define p23_MODE(x)     LPC_PINCON->PINMODE4&=p23_SEL_MASK;LPC_PINCON->PINMODE4|=((x&0x3)<<6)
+
+/* p24 is P2.2 */
+#define p24_SEL_MASK    ~(3UL << 4)
+#define p24_SET_MASK    (1UL << 2)
+#define p24_CLR_MASK    ~(p24_SET_MASK)
+#define p24_AS_OUTPUT   LPC_PINCON->PINSEL4&=p24_SEL_MASK;LPC_GPIO2->FIODIR|=p24_SET_MASK
+#define p24_AS_INPUT    LPC_GPIO2->FIOMASK &= p24_CLR_MASK; 
+#define p24_SET         LPC_GPIO2->FIOSET = p24_SET_MASK
+#define p24_CLR         LPC_GPIO2->FIOCLR = p24_SET_MASK
+#define p24_IS_SET      (bool)(LPC_GPIO2->FIOPIN & p24_SET_MASK)
+#define p24_IS_CLR      !(p24_IS_SET)
+#define p24_TOGGLE      p24_IS_SET?p24_CLR:p24_SET
+#define p24_MODE(x)     LPC_PINCON->PINMODE4&=p24_SEL_MASK;LPC_PINCON->PINMODE4|=((x&0x3)<<4)
+
+/* p25 is P2.1 */
+#define p25_SEL_MASK    ~(3UL << 2)
+#define p25_SET_MASK    (1UL << 1)
+#define p25_CLR_MASK    ~(p25_SET_MASK)
+#define p25_AS_OUTPUT   LPC_PINCON->PINSEL4&=p25_SEL_MASK;LPC_GPIO2->FIODIR|=p25_SET_MASK
+#define p25_AS_INPUT    LPC_GPIO2->FIOMASK &= p25_CLR_MASK; 
+#define p25_SET         LPC_GPIO2->FIOSET = p25_SET_MASK
+#define p25_CLR         LPC_GPIO2->FIOCLR = p25_SET_MASK
+#define p25_IS_SET      (bool)(LPC_GPIO2->FIOPIN & p25_SET_MASK)
+#define p25_IS_CLR      !(p25_IS_SET)
+#define p25_MODE(x)     LPC_PINCON->PINMODE4&=p25_SEL_MASK;LPC_PINCON->PINMODE4|=((x&0x3)<<2)
+
+/* p26 is P2.0 */
+#define p26_SEL_MASK    ~(3UL << 0)
+#define p26_SET_MASK    (1UL << 0)
+#define p26_CLR_MASK    ~(p26_SET_MASK)
+#define p26_AS_OUTPUT   LPC_PINCON->PINSEL4&=p26_SEL_MASK;LPC_GPIO2->FIODIR|=p26_SET_MASK
+#define p26_AS_INPUT    LPC_GPIO2->FIOMASK &= p26_CLR_MASK; 
+#define p26_SET         LPC_GPIO2->FIOSET = p26_SET_MASK
+#define p26_CLR         LPC_GPIO2->FIOCLR = p26_SET_MASK
+#define p26_IS_SET      (bool)(LPC_GPIO2->FIOPIN & p26_SET_MASK)
+#define p26_IS_CLR      !(p26_IS_SET)
+#define p26_MODE(x)     LPC_PINCON->PINMODE4&=p26_SEL_MASK;LPC_PINCON->PINMODE4|=((x&0x3)<<0)
+
+/* p27 is P0.11 */
+#define p27_SEL_MASK    ~(3UL << 22)
+#define p27_SET_MASK    (1UL << 11)
+#define p27_CLR_MASK    ~(p27_SET_MASK)
+#define p27_AS_OUTPUT   LPC_PINCON->PINSEL0&=p27_SEL_MASK;LPC_GPIO0->FIODIR|=p27_SET_MASK
+#define p27_AS_INPUT    LPC_GPIO0->FIOMASK &= p27_CLR_MASK; 
+#define p27_SET         LPC_GPIO0->FIOSET = p27_SET_MASK
+#define p27_CLR         LPC_GPIO0->FIOCLR = p27_SET_MASK
+#define p27_IS_SET      (bool)(LPC_GPIO0->FIOPIN & p27_SET_MASK)
+#define p27_IS_CLR      !(p27_IS_SET)
+#define p27_MODE(x)     LPC_PINCON->PINMODE0&=p27_SEL_MASK;LPC_PINCON->PINMODE0|=((x&0x3)<<22)
+
+/* p28 is P0.10 */
+#define p28_SEL_MASK    ~(3UL << 20)
+#define p28_SET_MASK    (1UL <<  10)
+#define p28_CLR_MASK    ~(p28_SET_MASK)
+#define p28_AS_OUTPUT   LPC_PINCON->PINSEL0&=p28_SEL_MASK;LPC_GPIO0->FIODIR|=p28_SET_MASK
+#define p28_AS_INPUT    LPC_GPIO0->FIOMASK &= p28_CLR_MASK; 
+#define p28_SET         LPC_GPIO0->FIOSET = p28_SET_MASK
+#define p28_CLR         LPC_GPIO0->FIOCLR = p28_SET_MASK
+#define p28_IS_SET      (bool)(LPC_GPIO0->FIOPIN & p28_SET_MASK)
+#define p28_IS_CLR      !(p28_IS_SET)
+#define p28_MODE(x)     LPC_PINCON->PINMODE0&=p28_SEL_MASK;LPC_PINCON->PINMODE0|=((x&0x3)<<20)
+
+/* p29 is P0.5 */
+#define p29_SEL_MASK    ~(3UL << 10)
+#define p29_SET_MASK    (1UL << 5)
+#define p29_CLR_MASK    ~(p29_SET_MASK)
+#define p29_AS_OUTPUT   LPC_PINCON->PINSEL0&=p29_SEL_MASK;LPC_GPIO0->FIODIR|=p29_SET_MASK
+#define p29_AS_INPUT    LPC_GPIO0->FIOMASK &= p29_CLR_MASK; 
+#define p29_SET         LPC_GPIO0->FIOSET = p29_SET_MASK
+#define p29_CLR         LPC_GPIO0->FIOCLR = p29_SET_MASK
+#define p29_IS_SET      (bool)(LPC_GPIO0->FIOPIN & p29_SET_MASK)
+#define p29_IS_CLR      !(p29_IS_SET)
+#define p29_TOGGLE      p29_IS_SET?p29_CLR:p29_SET
+#define p29_MODE(x)     LPC_PINCON->PINMODE0&=p29_SEL_MASK;LPC_PINCON->PINMODE0|=((x&0x3)<<10)
+
+/* p30 is P0.4 */
+#define p30_SEL_MASK    ~(3UL << 8)
+#define p30_SET_MASK    (1UL << 4)
+#define p30_CLR_MASK    ~(p30_SET_MASK)
+#define p30_AS_OUTPUT   LPC_PINCON->PINSEL0&=p30_SEL_MASK;LPC_GPIO0->FIODIR|=p30_SET_MASK
+#define p30_AS_INPUT    LPC_GPIO0->FIOMASK &= p30_CLR_MASK; 
+#define p30_SET         LPC_GPIO0->FIOSET = p30_SET_MASK
+#define p30_CLR         LPC_GPIO0->FIOCLR = p30_SET_MASK
+#define p30_IS_SET      (bool)(LPC_GPIO0->FIOPIN & p30_SET_MASK)
+#define p30_IS_CLR      !(p30_IS_SET)
+#define p30_MODE(x)     LPC_PINCON->PINMODE0&=p30_SEL_MASK;LPC_PINCON->PINMODE0|=((x&0x3)<<8)
+
+/* The following definitions are for the four Mbed LEDs.
+    LED1 = P1.18
+    LED2 = P1.20
+    LED3 = P1.21
+    LED4 = P1.23 */
+
+#define P1_18_SEL_MASK  ~(3UL << 4)
+#define P1_18_SET_MASK  (1UL << 18)
+#define P1_18_CLR_MASK  ~(P1_18_SET_MASK)
+#define P1_18_AS_OUTPUT LPC_PINCON->PINSEL3&=P1_18_SEL_MASK;LPC_GPIO1->FIODIR|=P1_18_SET_MASK
+#define P1_18_AS_INPUT  LPC_GPIO1->FIOMASK &= P1_18_CLR_MASK; 
+#define P1_18_SET       LPC_GPIO1->FIOSET = P1_18_SET_MASK
+#define P1_18_CLR       LPC_GPIO1->FIOCLR = P1_18_SET_MASK
+#define P1_18_IS_SET    (bool)(LPC_GPIO1->FIOPIN & P1_18_SET_MASK)
+#define P1_18_IS_CLR    !(P1_18_IS_SET)
+#define LED1_USE        P1_18_AS_OUTPUT;P1_18_AS_INPUT
+#define LED1_ON         P1_18_SET
+#define LED1_OFF        P1_18_CLR
+#define LED1_IS_ON      P1_18_IS_SET
+#define LED1_TOGGLE     P1_18_IS_SET?LED1_OFF:LED1_ON
+
+#define P1_20_SEL_MASK  ~(3UL << 8)
+#define P1_20_SET_MASK  (1UL << 20)
+#define P1_20_CLR_MASK  ~(P1_20_SET_MASK)
+#define P1_20_AS_OUTPUT LPC_PINCON->PINSEL3&=P1_20_SEL_MASK;LPC_GPIO1->FIODIR|=P1_20_SET_MASK
+#define P1_20_AS_INPUT  LPC_GPIO1->FIOMASK &= P1_20_CLR_MASK; 
+#define P1_20_SET       LPC_GPIO1->FIOSET = P1_20_SET_MASK
+#define P1_20_CLR       LPC_GPIO1->FIOCLR = P1_20_SET_MASK
+#define P1_20_IS_SET    (bool)(LPC_GPIO1->FIOPIN & P1_20_SET_MASK)
+#define P1_20_IS_CLR    !(P1_20_IS_SET)    
+#define LED2_USE        P1_20_AS_OUTPUT;P1_20_AS_INPUT
+#define LED2_ON         P1_20_SET
+#define LED2_OFF        P1_20_CLR
+#define LED2_IS_ON      P1_20_IS_SET
+#define LED2_TOGGLE     P1_20_IS_SET?LED2_OFF:LED2_ON
+
+#define P1_21_SEL_MASK  ~(3UL << 10)
+#define P1_21_SET_MASK  (1UL << 21)
+#define P1_21_CLR_MASK  ~(P1_21_SET_MASK)
+#define P1_21_AS_OUTPUT LPC_PINCON->PINSEL3&=P1_21_SEL_MASK;LPC_GPIO1->FIODIR|=P1_21_SET_MASK
+#define P1_21_AS_INPUT  LPC_GPIO1->FIOMASK &= P1_21_CLR_MASK; 
+#define P1_21_SET       LPC_GPIO1->FIOSET = P1_21_SET_MASK
+#define P1_21_CLR       LPC_GPIO1->FIOCLR = P1_21_SET_MASK
+#define P1_21_IS_SET    (bool)(LPC_GPIO1->FIOPIN & P1_21_SET_MASK)
+#define P1_21_IS_CLR    !(P1_21_IS_SET)
+#define LED3_USE        P1_21_AS_OUTPUT;P1_21_AS_INPUT
+#define LED3_ON         P1_21_SET
+#define LED3_OFF        P1_21_CLR
+#define LED3_IS_ON      P1_21_IS_SET
+#define LED3_TOGGLE     P1_21_IS_SET?LED3_OFF:LED3_ON
+
+#define P1_23_SEL_MASK  ~(3UL << 14)
+#define P1_23_SET_MASK  (1UL << 23)
+#define P1_23_CLR_MASK  ~(P1_23_SET_MASK)
+#define P1_23_AS_OUTPUT LPC_PINCON->PINSEL3&=P1_23_SEL_MASK;LPC_GPIO1->FIODIR|=P1_23_SET_MASK
+#define P1_23_AS_INPUT  LPC_GPIO1->FIOMASK &= P1_23_CLR_MASK; 
+#define P1_23_SET       LPC_GPIO1->FIOSET = P1_23_SET_MASK
+#define P1_23_CLR       LPC_GPIO1->FIOCLR = P1_23_SET_MASK
+#define P1_23_IS_SET    (bool)(LPC_GPIO1->FIOPIN & P1_23_SET_MASK)
+#define P1_23_IS_CLR    !(P1_23_IS_SET)    
+#define LED4_USE        P1_23_AS_OUTPUT;P1_23_AS_INPUT
+#define LED4_ON         P1_23_SET
+#define LED4_OFF        P1_23_CLR
+#define LED4_IS_ON      P1_23_IS_SET
+#define LED4_TOGGLE     P1_23_IS_SET?LED4_OFF:LED4_ON
+
+#endif
+
--- a/main.cpp	Fri Nov 09 06:23:54 2012 +0000
+++ b/main.cpp	Wed Dec 05 07:56:09 2012 +0000
@@ -1,8 +1,12 @@
 /*
  * SPI RAM 23LC1024 (Microchip)
  *   1Mbit
+ *   with DMA ( http://mbed.org/users/AjK/code/MODDMA/ )
  */
 #include "mbed.h"
+#include "MODDMA.h"
+
+#define ENABLE_DMA
 
 #define CMD_READ    0x03
 #define CMD_WRITE   0x02
@@ -13,20 +17,96 @@
 Serial pc(USBTX, USBRX);
 
 SPI spi(p11, p12, p13); // mosi, miso, sclk
-DigitalOut cs(p17), hold(p18);
+DigitalOut cs(p14);
+
+MODDMA dma;
+MODDMA_Config *dmacfg0 = NULL, *dmacfg1 = NULL;
+DigitalOut led2(LED2), led3(LED3), led4(LED4);
+volatile int dmaexit;
+
+extern "C" void HardFault_Handler() {
+    register unsigned int _msp __asm("msp");
+    printf("Hard Fault! address: %08x\r\n", *((unsigned int *)(_msp + 24)));
+    exit(-1);
+}  
+
+void tc0_callback () {
+    led2 = 1;
+    
+    MODDMA_Config *config = dma.getConfig();
+    dma.Disable( (MODDMA::CHANNELS)config->channelNum() );
+
+    // Clear DMA IRQ flags.
+    if (dma.irqType() == MODDMA::TcIrq) dma.clearTcIrq();    
+    if (dma.irqType() == MODDMA::ErrIrq) dma.clearErrIrq();    
+}
+
+void tc1_callback () {
+    dmaexit = 1;
+    led3 = 1;
+    
+    MODDMA_Config *config = dma.getConfig();
+    dma.Disable( (MODDMA::CHANNELS)config->channelNum() );
+
+    // Clear DMA IRQ flags.
+    if (dma.irqType() == MODDMA::TcIrq) dma.clearTcIrq();    
+    if (dma.irqType() == MODDMA::ErrIrq) dma.clearErrIrq();    
+}
+
+void err_callback () {
+    dmaexit = 1;
+    led4 = 1;
+    printf("err\r\n");
+}
 
 int ram_write (int addr, char *buf, int len) {
     int i;
+    char dummy[len];
 
     cs = 0;
     spi.write(CMD_WRITE);
     spi.write((addr >> 16) & 0xff);
     spi.write((addr >> 8) & 0xff);
     spi.write(addr & 0xff);
+    
+#ifdef ENABLE_DMA
+    dmacfg0
+     ->channelNum    ( MODDMA::Channel_0 )
+     ->srcMemAddr    ( (uint32_t)buf )
+     ->dstMemAddr    ( MODDMA::SSP0_Tx )
+     ->transferSize  ( len )
+     ->transferType  ( MODDMA::m2p )
+     ->dstConn       ( MODDMA::SSP0_Tx )
+     ->attach_tc     ( &tc0_callback )
+     ->attach_err    ( &err_callback )
+    ; // config end
 
+    dmacfg1
+     ->channelNum    ( MODDMA::Channel_1 )
+     ->srcMemAddr    ( MODDMA::SSP0_Rx )
+     ->dstMemAddr    ( (uint32_t)dummy )
+     ->transferSize  ( len )
+     ->transferType  ( MODDMA::p2m )
+     ->srcConn       ( MODDMA::SSP0_Rx )
+     ->attach_tc     ( &tc1_callback )
+     ->attach_err    ( &err_callback )
+    ; // config end
+    
+    if (dma.Setup( dmacfg0 ) && dma.Setup( dmacfg1 )) {
+        dmaexit = 0;
+        LPC_SSP0->DMACR = (1<<1)|(1<<0); // TX,RXDMAE
+        dma.Enable( dmacfg0 );
+        dma.Enable( dmacfg1 );
+        while (! dmaexit);
+    } else {
+        printf("error\r\n");
+    }
+    LPC_SSP0->DMACR = 0;
+#else
     for (i = 0; i < len; i ++) {
         spi.write(buf[i]);
     }
+#endif
     cs = 1;
     return i;
 }
@@ -40,9 +120,44 @@
     spi.write((addr >> 8) & 0xff);
     spi.write(addr & 0xff);
 
+#ifdef ENABLE_DMA
+    dmacfg0
+     ->channelNum    ( MODDMA::Channel_0 )
+     ->srcMemAddr    ( (uint32_t)buf )
+     ->dstMemAddr    ( MODDMA::SSP0_Tx )
+     ->transferSize  ( len )
+     ->transferType  ( MODDMA::m2p )
+     ->dstConn       ( MODDMA::SSP0_Tx )
+     ->attach_tc     ( &tc0_callback )
+     ->attach_err    ( &err_callback )
+    ; // config end
+
+    dmacfg1
+     ->channelNum    ( MODDMA::Channel_1 )
+     ->srcMemAddr    ( MODDMA::SSP0_Rx )
+     ->dstMemAddr    ( (uint32_t)buf )
+     ->transferSize  ( len )
+     ->transferType  ( MODDMA::p2m )
+     ->srcConn       ( MODDMA::SSP0_Rx )
+     ->attach_tc     ( &tc1_callback )
+     ->attach_err    ( &err_callback )
+    ; // config end
+    
+    if (dma.Setup( dmacfg0 ) && dma.Setup( dmacfg1 )) {
+        dmaexit = 0;
+        LPC_SSP0->DMACR = (1<<1)|(1<<0); // TX,RXDMAE
+        dma.Enable( dmacfg0 );
+        dma.Enable( dmacfg1 );
+        while (! dmaexit);
+    } else {
+        printf("error\r\n");
+    }
+    LPC_SSP0->DMACR = 0;
+#else
     for (i = 0; i < len; i ++) {
         buf[i] = spi.write(0);
     }
+#endif
     cs = 1;
     return i;
 }
@@ -53,11 +168,14 @@
     Timer t;
 
     cs = 1;
-    hold = 1;
+#ifdef ENABLE_DMA
+    dmacfg0 = new MODDMA_Config;
+    dmacfg1 = new MODDMA_Config;
+#endif
     pc.baud(115200);
     spi.frequency(16000000);
     wait_ms(500);
-    
+
     cs = 0;
     spi.write(CMD_RDMR);
     printf("RAM mode: %02x\r\n", spi.write(0));
@@ -72,7 +190,7 @@
     for (i = 0; i < 256; i ++) {
         buf[i] = i;
     }
-    ram_write(6, buf, 256);
+    ram_write(8, buf, 200);
 
     wait(1);
     memset(buf, 0, 256);