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
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
Generated on Sun Jul 17 2022 05:39:02 by
1.7.2