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

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

Files at this revision

API Documentation at this revision

Comitter:
AjK
Date:
Mon Mar 14 13:51:38 2011 +0000
Parent:
15:e01144bae101
Child:
17:97a16bf2ff43
Commit message:
1.12 See ChangeLoc.c

Changed in this revision

ChangeLog.c Show annotated file Show diff for this revision Revisions of this file
DATALUTS.cpp Show annotated file Show diff for this revision Revisions of this file
MODDMA.h Show annotated file Show diff for this revision Revisions of this file
SETUP.cpp Show annotated file Show diff for this revision Revisions of this file
example3.h Show annotated file Show diff for this revision Revisions of this file
example4.h Show annotated file Show diff for this revision Revisions of this file
--- a/ChangeLog.c	Mon Mar 14 00:14:24 2011 +0000
+++ b/ChangeLog.c	Mon Mar 14 13:51:38 2011 +0000
@@ -1,8 +1,14 @@
 /* $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 teh documentation of example3.h
+    * Fixed a silly typo in the documentation of example3.h
     
 1.10- 13 Mar 2011
 
--- a/DATALUTS.cpp	Mon Mar 14 00:14:24 2011 +0000
+++ b/DATALUTS.cpp	Mon Mar 14 13:51:38 2011 +0000
@@ -123,7 +123,7 @@
         , (uint8_t)word      // ADC
         , (uint8_t)word      // I2S channel 0
         , (uint8_t)word      // I2S channel 1
-        , (uint8_t)byte      // DAC
+        , (uint8_t)word      // DAC 
         , (uint8_t)byte      // UART0 Tx
         , (uint8_t)byte      // UART0 Rx
         , (uint8_t)byte      // UART1 Tx
--- a/MODDMA.h	Mon Mar 14 00:14:24 2011 +0000
+++ b/MODDMA.h	Mon Mar 14 13:51:38 2011 +0000
@@ -312,7 +312,7 @@
         , 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. */
+        , m2g = 5UL     /*!< Psuedo Special case for writing "peripheral GPIO" that's memory mapped. */        
     };   
 
     //! Burst size in Source and Destination definitions */
@@ -376,6 +376,20 @@
     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
--- a/SETUP.cpp	Mon Mar 14 00:14:24 2011 +0000
+++ b/SETUP.cpp	Mon Mar 14 13:51:38 2011 +0000
@@ -60,7 +60,7 @@
                 | CxControl_DI() 
                 | CxControl_I();
             break;
-            
+        
         // Memory to peripheral
         case m2p:
             // Assign physical source
--- a/example3.h	Mon Mar 14 00:14:24 2011 +0000
+++ b/example3.h	Mon Mar 14 13:51:38 2011 +0000
@@ -29,7 +29,7 @@
 bool dmaTransferComplete;
 
 MODDMA dma;
-MODDMA_Config *conf, conf_copy;
+MODDMA_Config *conf;
 
 void TC0_callback(void);
 void ERR0_callback(void);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/example4.h	Mon Mar 14 13:51:38 2011 +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");
+}