Demo using DMA to play recorded audio samples to the DAC (p18) on the mbed LPC1768 using the MODDMA library for the LPC1768.
main.cpp
- Committer:
- 4180_1
- Date:
- 2019-02-20
- Revision:
- 1:a61a49613606
- Parent:
- 0:e4f991474a45
File content as of revision 1:a61a49613606:
/* * Demonstrates sending a flash buffer to the LPC1768 DAC using DMA * from recorded audio data samples setup in flash memory * Connect a speaker with a driver to Mbed pin 18. Main flashes LED1. * LED3 and LED4 indicate which DMA (double) buffer is in use. * https://os.mbed.com/users/4180_1/notebook/using-flash-to-play-audio-clips/ * has additional info on using flash to store audio clips */ #include "mbed.h" //DMA library - based on DMA->DAC example4.h library code #include "MODDMA.h" //Cylon audio sample file in flash in special 32-bit format for DMA->DAC use #include "DMADAC_cylonbyc.h" //see https://os.mbed.com/users/4180_1/notebook/using-flash-to-play-audio-clips/ DigitalOut led1(LED1); DigitalOut led3(LED3); DigitalOut led4(LED4); AnalogOut signal(p18); MODDMA dma; MODDMA_Config *conf0, *conf1; int DMA_size = 4095; //max DMA transfer size int DMA_start_index = 0; //next starting address int NUM_Remaining=0; //number of audio samples remaining to play void TC0_callback(void); void TC1_callback(void); void ERR0_callback(void); void ERR1_callback(void); int main() { volatile int life_counter = 0; // Prepare the GPDMA system for buffer0. conf0 = new MODDMA_Config; conf0 ->channelNum ( MODDMA::Channel_0 ) ->srcMemAddr ( (uint32_t) &sound_data) ->dstMemAddr ( MODDMA::DAC ) ->transferSize ( DMA_size ) ->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) &sound_data[DMA_size] ) ->dstMemAddr ( MODDMA::DAC ) ->transferSize ( DMA_size ) ->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. LPC_DAC->DACCNTVAL = 2400; //around 11Khz audio sample rate // 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() ); //Setup for next DMA chunk of audio data DMA_start_index = DMA_start_index + DMA_size; conf1->srcMemAddr ( (uint32_t) &sound_data[DMA_start_index]); conf1->transferSize(DMA_size); NUM_Remaining = NUM_ELEMENTS - DMA_start_index; //Check for end of data and restart if needed if (NUM_Remaining < DMA_size) { conf1->transferSize(NUM_Remaining); DMA_start_index = -DMA_size; } // re-config end // Setup next DMA // Prepare configuration. if(!dma.Prepare( conf1 )) { error("Bad DMA setup"); led3=led4=1; } // Clear DMA IRQ flags. if (dma.irqType() == MODDMA::TcIrq) dma.clearTcIrq(); } // 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() ); //Setup for next DMA chunk of audio data DMA_start_index = DMA_start_index + DMA_size; conf0->srcMemAddr ( (uint32_t) &sound_data[DMA_start_index]); conf0->transferSize(DMA_size); NUM_Remaining = NUM_ELEMENTS - DMA_start_index; //Check for end of data and restart if needed if (NUM_Remaining < DMA_size) { conf0->transferSize(NUM_Remaining); DMA_start_index = -DMA_size; } // Swap to buffer0 dma.Prepare( conf0 ); // Clear DMA IRQ flags. if (dma.irqType() == MODDMA::TcIrq) dma.clearTcIrq(); } // Configuration callback on Error void ERR0_callback(void) { error("DMA 0 error"); } // Configuration callback on Error void ERR1_callback(void) { error("DMA 1 error"); }