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

Committer:
4180_1
Date:
Wed Feb 20 15:07:22 2019 +0000
Revision:
1:a61a49613606
Parent:
0:e4f991474a45
ver 0.1

Who changed what in which revision?

UserRevisionLine numberNew contents of line
4180_1 1:a61a49613606 1 /*
4180_1 1:a61a49613606 2 * Demonstrates sending a flash buffer to the LPC1768 DAC using DMA
4180_1 1:a61a49613606 3 * from recorded audio data samples setup in flash memory
4180_1 1:a61a49613606 4 * Connect a speaker with a driver to Mbed pin 18. Main flashes LED1.
4180_1 1:a61a49613606 5 * LED3 and LED4 indicate which DMA (double) buffer is in use.
4180_1 1:a61a49613606 6 * https://os.mbed.com/users/4180_1/notebook/using-flash-to-play-audio-clips/
4180_1 1:a61a49613606 7 * has additional info on using flash to store audio clips
4180_1 1:a61a49613606 8 */
4180_1 0:e4f991474a45 9 #include "mbed.h"
4180_1 1:a61a49613606 10 //DMA library - based on DMA->DAC example4.h library code
4180_1 1:a61a49613606 11 #include "MODDMA.h"
4180_1 1:a61a49613606 12 //Cylon audio sample file in flash in special 32-bit format for DMA->DAC use
4180_1 1:a61a49613606 13 #include "DMADAC_cylonbyc.h"
4180_1 0:e4f991474a45 14 //see https://os.mbed.com/users/4180_1/notebook/using-flash-to-play-audio-clips/
4180_1 1:a61a49613606 15
4180_1 1:a61a49613606 16 DigitalOut led1(LED1);
4180_1 1:a61a49613606 17 DigitalOut led3(LED3);
4180_1 1:a61a49613606 18 DigitalOut led4(LED4);
4180_1 1:a61a49613606 19
4180_1 1:a61a49613606 20 AnalogOut signal(p18);
4180_1 1:a61a49613606 21
4180_1 1:a61a49613606 22 MODDMA dma;
4180_1 1:a61a49613606 23 MODDMA_Config *conf0, *conf1;
4180_1 1:a61a49613606 24 int DMA_size = 4095; //max DMA transfer size
4180_1 1:a61a49613606 25 int DMA_start_index = 0; //next starting address
4180_1 1:a61a49613606 26 int NUM_Remaining=0; //number of audio samples remaining to play
4180_1 1:a61a49613606 27
4180_1 1:a61a49613606 28 void TC0_callback(void);
4180_1 1:a61a49613606 29 void TC1_callback(void);
4180_1 1:a61a49613606 30 void ERR0_callback(void);
4180_1 1:a61a49613606 31 void ERR1_callback(void);
4180_1 1:a61a49613606 32
4180_1 1:a61a49613606 33 int main()
4180_1 1:a61a49613606 34 {
4180_1 1:a61a49613606 35 volatile int life_counter = 0;
4180_1 0:e4f991474a45 36
4180_1 1:a61a49613606 37 // Prepare the GPDMA system for buffer0.
4180_1 1:a61a49613606 38 conf0 = new MODDMA_Config;
4180_1 1:a61a49613606 39 conf0
4180_1 1:a61a49613606 40 ->channelNum ( MODDMA::Channel_0 )
4180_1 1:a61a49613606 41 ->srcMemAddr ( (uint32_t) &sound_data)
4180_1 1:a61a49613606 42 ->dstMemAddr ( MODDMA::DAC )
4180_1 1:a61a49613606 43 ->transferSize ( DMA_size )
4180_1 1:a61a49613606 44 ->transferType ( MODDMA::m2p )
4180_1 1:a61a49613606 45 ->dstConn ( MODDMA::DAC )
4180_1 1:a61a49613606 46 ->attach_tc ( &TC0_callback )
4180_1 1:a61a49613606 47 ->attach_err ( &ERR0_callback )
4180_1 1:a61a49613606 48 ; // config end
4180_1 1:a61a49613606 49 // Prepare the GPDMA system for buffer1.
4180_1 1:a61a49613606 50 conf1 = new MODDMA_Config;
4180_1 1:a61a49613606 51 conf1
4180_1 1:a61a49613606 52 ->channelNum ( MODDMA::Channel_1 )
4180_1 1:a61a49613606 53 ->srcMemAddr ( (uint32_t) &sound_data[DMA_size] )
4180_1 1:a61a49613606 54 ->dstMemAddr ( MODDMA::DAC )
4180_1 1:a61a49613606 55 ->transferSize ( DMA_size )
4180_1 1:a61a49613606 56 ->transferType ( MODDMA::m2p )
4180_1 1:a61a49613606 57 ->dstConn ( MODDMA::DAC )
4180_1 1:a61a49613606 58 ->attach_tc ( &TC1_callback )
4180_1 1:a61a49613606 59 ->attach_err ( &ERR1_callback )
4180_1 1:a61a49613606 60 ; // config end
4180_1 0:e4f991474a45 61
4180_1 1:a61a49613606 62 // Calculating the transfer frequency:
4180_1 1:a61a49613606 63 // By default, the Mbed library sets the PCLK_DAC clock value
4180_1 1:a61a49613606 64 // to 24MHz. One complete sinewave cycle in each buffer is 360
4180_1 1:a61a49613606 65 // points long. So, for a 1Hz wave we would need to transfer 360
4180_1 1:a61a49613606 66 // values per second. That would be 24000000/360 which is approx
4180_1 1:a61a49613606 67 // 66,666. But that's no good! The count val is only 16bits in size
4180_1 1:a61a49613606 68 // so bare this in mind. If you need to go slower you will need to
4180_1 1:a61a49613606 69 // alter PCLK_DAC from CCLK/4 to CCLK/8.
4180_1 1:a61a49613606 70 LPC_DAC->DACCNTVAL = 2400; //around 11Khz audio sample rate
4180_1 1:a61a49613606 71
4180_1 1:a61a49613606 72 // Prepare first configuration.
4180_1 1:a61a49613606 73 if (!dma.Prepare( conf0 )) {
4180_1 1:a61a49613606 74 error("Doh!");
4180_1 1:a61a49613606 75 }
4180_1 1:a61a49613606 76
4180_1 1:a61a49613606 77 // Begin (enable DMA and counter). Note, don't enable
4180_1 1:a61a49613606 78 // DBLBUF_ENA as we are using DMA double buffering.
4180_1 1:a61a49613606 79 LPC_DAC->DACCTRL |= (3UL << 2);
4180_1 1:a61a49613606 80
4180_1 1:a61a49613606 81 while (1) {
4180_1 1:a61a49613606 82 // There's not a lot to do as DMA and interrupts are
4180_1 1:a61a49613606 83 // now handling the buffer transfers. So we'll just
4180_1 1:a61a49613606 84 // flash led1 to show the Mbed is alive and kicking.
4180_1 1:a61a49613606 85 if (life_counter++ > 1000000) {
4180_1 1:a61a49613606 86 led1 = !led1; // Show some sort of life.
4180_1 1:a61a49613606 87 life_counter = 0;
4180_1 1:a61a49613606 88 }
4180_1 0:e4f991474a45 89 }
4180_1 0:e4f991474a45 90 }
4180_1 1:a61a49613606 91
4180_1 1:a61a49613606 92 // Configuration callback on TC
4180_1 1:a61a49613606 93 void TC0_callback(void)
4180_1 1:a61a49613606 94 {
4180_1 1:a61a49613606 95
4180_1 1:a61a49613606 96 // Just show sending buffer0 complete.
4180_1 1:a61a49613606 97 led3 = !led3;
4180_1 1:a61a49613606 98
4180_1 1:a61a49613606 99 // Get configuration pointer.
4180_1 1:a61a49613606 100 MODDMA_Config *config = dma.getConfig();
4180_1 1:a61a49613606 101
4180_1 1:a61a49613606 102 // Finish the DMA cycle by shutting down the channel.
4180_1 1:a61a49613606 103 dma.Disable( (MODDMA::CHANNELS)config->channelNum() );
4180_1 1:a61a49613606 104 //Setup for next DMA chunk of audio data
4180_1 1:a61a49613606 105 DMA_start_index = DMA_start_index + DMA_size;
4180_1 1:a61a49613606 106 conf1->srcMemAddr ( (uint32_t) &sound_data[DMA_start_index]);
4180_1 1:a61a49613606 107 conf1->transferSize(DMA_size);
4180_1 1:a61a49613606 108 NUM_Remaining = NUM_ELEMENTS - DMA_start_index;
4180_1 1:a61a49613606 109 //Check for end of data and restart if needed
4180_1 1:a61a49613606 110 if (NUM_Remaining < DMA_size) {
4180_1 1:a61a49613606 111 conf1->transferSize(NUM_Remaining);
4180_1 1:a61a49613606 112 DMA_start_index = -DMA_size;
4180_1 1:a61a49613606 113 }
4180_1 1:a61a49613606 114 // re-config end
4180_1 1:a61a49613606 115 // Setup next DMA
4180_1 1:a61a49613606 116 // Prepare configuration.
4180_1 1:a61a49613606 117 if(!dma.Prepare( conf1 )) {
4180_1 1:a61a49613606 118 error("Bad DMA setup");
4180_1 1:a61a49613606 119 led3=led4=1;
4180_1 1:a61a49613606 120 }
4180_1 1:a61a49613606 121 // Clear DMA IRQ flags.
4180_1 1:a61a49613606 122 if (dma.irqType() == MODDMA::TcIrq) dma.clearTcIrq();
4180_1 1:a61a49613606 123 }
4180_1 1:a61a49613606 124
4180_1 1:a61a49613606 125 // Configuration callback on TC
4180_1 1:a61a49613606 126 void TC1_callback(void)
4180_1 0:e4f991474a45 127 {
4180_1 1:a61a49613606 128
4180_1 1:a61a49613606 129 // Just show sending buffer1 complete.
4180_1 1:a61a49613606 130 led4 = !led4;
4180_1 1:a61a49613606 131
4180_1 1:a61a49613606 132 // Get configuration pointer.
4180_1 1:a61a49613606 133 MODDMA_Config *config = dma.getConfig();
4180_1 1:a61a49613606 134
4180_1 1:a61a49613606 135 // Finish the DMA cycle by shutting down the channel.
4180_1 1:a61a49613606 136 dma.Disable( (MODDMA::CHANNELS)config->channelNum() );
4180_1 1:a61a49613606 137 //Setup for next DMA chunk of audio data
4180_1 1:a61a49613606 138 DMA_start_index = DMA_start_index + DMA_size;
4180_1 1:a61a49613606 139 conf0->srcMemAddr ( (uint32_t) &sound_data[DMA_start_index]);
4180_1 1:a61a49613606 140 conf0->transferSize(DMA_size);
4180_1 1:a61a49613606 141 NUM_Remaining = NUM_ELEMENTS - DMA_start_index;
4180_1 1:a61a49613606 142 //Check for end of data and restart if needed
4180_1 1:a61a49613606 143 if (NUM_Remaining < DMA_size) {
4180_1 1:a61a49613606 144 conf0->transferSize(NUM_Remaining);
4180_1 1:a61a49613606 145 DMA_start_index = -DMA_size;
4180_1 0:e4f991474a45 146 }
4180_1 1:a61a49613606 147 // Swap to buffer0
4180_1 1:a61a49613606 148 dma.Prepare( conf0 );
4180_1 1:a61a49613606 149
4180_1 1:a61a49613606 150 // Clear DMA IRQ flags.
4180_1 1:a61a49613606 151 if (dma.irqType() == MODDMA::TcIrq) dma.clearTcIrq();
4180_1 0:e4f991474a45 152 }
4180_1 1:a61a49613606 153
4180_1 1:a61a49613606 154 // Configuration callback on Error
4180_1 1:a61a49613606 155 void ERR0_callback(void)
4180_1 1:a61a49613606 156 {
4180_1 1:a61a49613606 157 error("DMA 0 error");
4180_1 1:a61a49613606 158 }
4180_1 1:a61a49613606 159
4180_1 1:a61a49613606 160 // Configuration callback on Error
4180_1 1:a61a49613606 161 void ERR1_callback(void)
4180_1 1:a61a49613606 162 {
4180_1 1:a61a49613606 163 error("DMA 1 error");
4180_1 1:a61a49613606 164 }
4180_1 1:a61a49613606 165