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
Revision 16:cb10aec6feb1, committed 2011-03-14
- 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
--- 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");
+}
Andy K