Demo using DMA to play recorded audio samples to the DAC (p18) on the mbed LPC1768 using the MODDMA library for the LPC1768.

Dependencies:   mbed MODDMA

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /*
00002  * Demonstrates sending a flash buffer to the LPC1768 DAC using DMA
00003  * from recorded audio data samples setup in flash memory
00004  * Connect a speaker with a driver to Mbed pin 18. Main flashes LED1.
00005  * LED3 and LED4 indicate which DMA (double) buffer is in use.
00006  * https://os.mbed.com/users/4180_1/notebook/using-flash-to-play-audio-clips/
00007  * has additional info on using flash to store audio clips
00008  */
00009 #include "mbed.h"
00010 //DMA library - based on DMA->DAC example4.h library code
00011 #include "MODDMA.h"
00012 //Cylon audio sample file in flash in special 32-bit format for DMA->DAC use
00013 #include "DMADAC_cylonbyc.h"
00014 //see https://os.mbed.com/users/4180_1/notebook/using-flash-to-play-audio-clips/
00015 
00016 DigitalOut led1(LED1);
00017 DigitalOut led3(LED3);
00018 DigitalOut led4(LED4);
00019 
00020 AnalogOut signal(p18);
00021 
00022 MODDMA dma;
00023 MODDMA_Config *conf0, *conf1;
00024 int DMA_size = 4095; //max DMA transfer size
00025 int DMA_start_index = 0; //next starting address
00026 int NUM_Remaining=0; //number of audio samples remaining to play
00027 
00028 void TC0_callback(void);
00029 void TC1_callback(void);
00030 void ERR0_callback(void);
00031 void ERR1_callback(void);
00032 
00033 int main()
00034 {
00035     volatile int life_counter = 0;
00036 
00037     // Prepare the GPDMA system for buffer0.
00038     conf0 = new MODDMA_Config;
00039     conf0
00040     ->channelNum    ( MODDMA::Channel_0 )
00041     ->srcMemAddr    ( (uint32_t) &sound_data)
00042     ->dstMemAddr    ( MODDMA::DAC )
00043     ->transferSize  ( DMA_size )
00044     ->transferType  ( MODDMA::m2p )
00045     ->dstConn       ( MODDMA::DAC )
00046     ->attach_tc     ( &TC0_callback )
00047     ->attach_err    ( &ERR0_callback )
00048     ; // config end
00049     // Prepare the GPDMA system for buffer1.
00050     conf1 = new MODDMA_Config;
00051     conf1
00052     ->channelNum    ( MODDMA::Channel_1 )
00053     ->srcMemAddr    ( (uint32_t) &sound_data[DMA_size] )
00054     ->dstMemAddr    ( MODDMA::DAC )
00055     ->transferSize  ( DMA_size )
00056     ->transferType  ( MODDMA::m2p )
00057     ->dstConn       ( MODDMA::DAC )
00058     ->attach_tc     ( &TC1_callback )
00059     ->attach_err    ( &ERR1_callback )
00060     ; // config end
00061 
00062     // Calculating the transfer frequency:
00063     // By default, the Mbed library sets the PCLK_DAC clock value
00064     // to 24MHz. One complete sinewave cycle in each buffer is 360
00065     // points long. So, for a 1Hz wave we would need to transfer 360
00066     // values per second. That would be 24000000/360 which is approx
00067     // 66,666. But that's no good! The count val is only 16bits in size
00068     // so bare this in mind. If you need to go slower you will need to
00069     // alter PCLK_DAC from CCLK/4 to CCLK/8.
00070     LPC_DAC->DACCNTVAL = 2400; //around 11Khz audio sample rate
00071 
00072     // Prepare first configuration.
00073     if (!dma.Prepare( conf0 )) {
00074         error("Doh!");
00075     }
00076 
00077     // Begin (enable DMA and counter). Note, don't enable
00078     // DBLBUF_ENA as we are using DMA double buffering.
00079     LPC_DAC->DACCTRL |= (3UL << 2);
00080 
00081     while (1) {
00082         // There's not a lot to do as DMA and interrupts are
00083         // now handling the buffer transfers. So we'll just
00084         // flash led1 to show the Mbed is alive and kicking.
00085         if (life_counter++ > 1000000) {
00086             led1 = !led1; // Show some sort of life.
00087             life_counter = 0;
00088         }
00089     }
00090 }
00091 
00092 // Configuration callback on TC
00093 void TC0_callback(void)
00094 {
00095 
00096     // Just show sending buffer0 complete.
00097     led3 = !led3;
00098 
00099     // Get configuration pointer.
00100     MODDMA_Config *config = dma.getConfig();
00101 
00102     // Finish the DMA cycle by shutting down the channel.
00103     dma.Disable( (MODDMA::CHANNELS)config->channelNum() );
00104     //Setup for next DMA chunk of audio data
00105     DMA_start_index = DMA_start_index + DMA_size;
00106     conf1->srcMemAddr    ( (uint32_t) &sound_data[DMA_start_index]);
00107     conf1->transferSize(DMA_size);
00108     NUM_Remaining = NUM_ELEMENTS - DMA_start_index;
00109     //Check for end of data and restart if needed
00110     if (NUM_Remaining < DMA_size) {
00111         conf1->transferSize(NUM_Remaining);
00112         DMA_start_index = -DMA_size;
00113     }
00114     // re-config end
00115     // Setup next DMA
00116     // Prepare configuration.
00117     if(!dma.Prepare( conf1 )) {
00118         error("Bad DMA setup");
00119         led3=led4=1;
00120     }
00121     // Clear DMA IRQ flags.
00122     if (dma.irqType() == MODDMA::TcIrq) dma.clearTcIrq();
00123 }
00124 
00125 // Configuration callback on TC
00126 void TC1_callback(void)
00127 {
00128 
00129     // Just show sending buffer1 complete.
00130     led4 = !led4;
00131 
00132     // Get configuration pointer.
00133     MODDMA_Config *config = dma.getConfig();
00134 
00135     // Finish the DMA cycle by shutting down the channel.
00136     dma.Disable( (MODDMA::CHANNELS)config->channelNum() );
00137         //Setup for next DMA chunk of audio data
00138     DMA_start_index = DMA_start_index + DMA_size;
00139     conf0->srcMemAddr    ( (uint32_t) &sound_data[DMA_start_index]);
00140     conf0->transferSize(DMA_size);
00141     NUM_Remaining = NUM_ELEMENTS - DMA_start_index;
00142     //Check for end of data and restart if needed
00143     if (NUM_Remaining < DMA_size) {
00144         conf0->transferSize(NUM_Remaining);
00145         DMA_start_index = -DMA_size;
00146     }
00147     // Swap to buffer0
00148     dma.Prepare( conf0 );
00149 
00150     // Clear DMA IRQ flags.
00151     if (dma.irqType() == MODDMA::TcIrq) dma.clearTcIrq();
00152 }
00153 
00154 // Configuration callback on Error
00155 void ERR0_callback(void)
00156 {
00157     error("DMA 0 error");
00158 }
00159 
00160 // Configuration callback on Error
00161 void ERR1_callback(void)
00162 {
00163     error("DMA 1 error");
00164 }
00165