/ examples / DMA_fancy_player / DMA_fancy_player.ino
DMA_fancy_player.ino
  1  /* 
  2   *  A fancy DMA MP3 player
  3   *  the PLAY pin will start playback from the beginning of the file
  4   *  the PAUSE pin will pause playback at the current point
  5   *  the RESUME pin will resume playback at the point it was paused
  6   *  a potentiometer is connected to the VOLUME pin to set the playback volume
  7   */
  8   
  9  #include "Adafruit_MP3.h"
 10  #include <SPI.h>
 11  #include <SD.h>
 12  
 13  #include <Adafruit_ZeroDMA.h>
 14  #include "utility/dma.h"
 15  
 16  #define VOLUME_MAX 2047
 17  #define PIN_PAUSE 5
 18  #define PIN_RESUME 6
 19  #define PIN_PLAY 9
 20  #define PIN_VOLUME A3
 21  
 22  const char *filename = "test3.mp3";
 23  const int chipSelect = 10;
 24  
 25  Adafruit_ZeroDMA leftDMA;
 26  Adafruit_ZeroDMA rightDMA;
 27  ZeroDMAstatus    stat; // DMA status codes returned by some functions
 28  File dataFile;
 29  Adafruit_MP3_DMA player;
 30  DmacDescriptor *desc;
 31  
 32  //the output data buffers
 33  int16_t *ping, *pong;
 34  int volume;
 35  
 36  //this gets called when the player wants more data
 37  int getMoreData(uint8_t *writeHere, int thisManyBytes){
 38    int bytesRead = 0;
 39    while(dataFile.available() && bytesRead < thisManyBytes){
 40      *writeHere = dataFile.read();
 41      writeHere++;
 42      bytesRead++;
 43    }
 44    return bytesRead;
 45  }
 46  
 47  
 48  //this will get called when data has been decoded
 49  void decodeCallback(int16_t *data, int len){
 50    for(int i=0; i<len; i++){
 51      int val = map(*data, -32768, 32767, 0, volume);
 52      *data++ = val;
 53    }
 54  }
 55  
 56  void dma_callback(Adafruit_ZeroDMA *dma) {
 57    
 58    digitalWrite(13, HIGH);
 59    //try to fill the next buffer
 60    if(player.fill()){
 61      //stop
 62      leftDMA.abort();
 63      rightDMA.abort();
 64    }
 65    digitalWrite(13, LOW);
 66  }
 67  
 68  void doNothing(Adafruit_ZeroDMA *dma) {
 69    
 70  }
 71  
 72  void initMonoDMA(){
 73    //set up the DMA channels
 74    leftDMA.setTrigger(MP3_DMA_TRIGGER);
 75    leftDMA.setAction(DMA_TRIGGER_ACTON_BEAT);
 76    stat = leftDMA.allocate();
 77  
 78    //ask for the buffers we're going to use
 79    player.getBuffers(&ping, &pong);
 80  
 81    //make the descriptors
 82    desc = leftDMA.addDescriptor(
 83      ping,                    // move data from here
 84      (void *)(&DAC->DATA[0]), // to here (M4)
 85      MP3_OUTBUF_SIZE,
 86      DMA_BEAT_SIZE_HWORD,               // bytes/hword/words
 87      true,                             // increment source addr?
 88      false);
 89    desc->BTCTRL.bit.BLOCKACT = DMA_BLOCK_ACTION_INT;
 90  
 91    desc = leftDMA.addDescriptor(
 92      pong,                    // move data from here
 93      (void *)(&DAC->DATA[0]), // to here (M4)
 94      MP3_OUTBUF_SIZE,
 95      DMA_BEAT_SIZE_HWORD,               // bytes/hword/words
 96      true,                             // increment source addr?
 97      false);                   // increment dest addr?
 98    desc->BTCTRL.bit.BLOCKACT = DMA_BLOCK_ACTION_INT;
 99  
100    //make the descriptor list loop
101    leftDMA.loop(true);
102    leftDMA.setCallback(dma_callback);
103  
104    rightDMA.setTrigger(MP3_DMA_TRIGGER);
105    rightDMA.setAction(DMA_TRIGGER_ACTON_BEAT);
106    stat = rightDMA.allocate();
107  
108    //make the descriptors
109    desc = rightDMA.addDescriptor(
110      ping + 1,                    // move data from here
111      (void *)(&DAC->DATA[1]), // to here (M4)
112      MP3_OUTBUF_SIZE,                      // this many...
113      DMA_BEAT_SIZE_HWORD,               // bytes/hword/words
114      true,                             // increment source addr?
115      false);                           // increment dest addr?
116    desc->BTCTRL.bit.BLOCKACT = DMA_BLOCK_ACTION_INT;
117  
118    desc = rightDMA.addDescriptor(
119      pong + 1,                    // move data from here
120      (void *)(&DAC->DATA[1]), // to here (M4)
121      MP3_OUTBUF_SIZE,                      // this many...
122      DMA_BEAT_SIZE_HWORD,               // bytes/hword/words
123      true,                             // increment source addr?
124      false);                           // increment dest addr?
125    desc->BTCTRL.bit.BLOCKACT = DMA_BLOCK_ACTION_INT;
126  
127    //make the descriptor list loop
128    rightDMA.loop(true);
129    rightDMA.setCallback(doNothing);
130  }
131  
132  void initStereoDMA(){
133      //######### LEFT CHANNEL DMA ##############//
134    
135    //set up the DMA channels
136    leftDMA.setTrigger(MP3_DMA_TRIGGER);
137    leftDMA.setAction(DMA_TRIGGER_ACTON_BEAT);
138    stat = leftDMA.allocate();
139  
140    //ask for the buffers we're going to use
141    player.getBuffers(&ping, &pong);
142  
143    //make the descriptors
144    desc = leftDMA.addDescriptor(
145      ping,                    // move data from here
146      (void *)(&DAC->DATA[0]), // to here (M4)
147      MP3_OUTBUF_SIZE >> 1,                      // this many...
148      DMA_BEAT_SIZE_HWORD,               // bytes/hword/words
149      true,                             // increment source addr?
150      false,
151      DMA_ADDRESS_INCREMENT_STEP_SIZE_2,
152      DMA_STEPSEL_SRC);                           // increment dest addr?
153  
154    desc->BTCTRL.bit.BLOCKACT = DMA_BLOCK_ACTION_INT;
155  
156    desc = leftDMA.addDescriptor(
157      pong,                    // move data from here
158      (void *)(&DAC->DATA[0]), // to here (M4)
159      MP3_OUTBUF_SIZE >> 1,                      // this many...
160      DMA_BEAT_SIZE_HWORD,               // bytes/hword/words
161      true,                             // increment source addr?
162      false,
163      DMA_ADDRESS_INCREMENT_STEP_SIZE_2,
164      DMA_STEPSEL_SRC);                           // increment dest addr?
165      
166    desc->BTCTRL.bit.BLOCKACT = DMA_BLOCK_ACTION_INT;
167  
168    //make the descriptor list loop
169    leftDMA.loop(true);
170    leftDMA.setCallback(dma_callback);
171  
172    //######### RIGHT CHANNEL DMA ##############//
173  
174    rightDMA.setTrigger(MP3_DMA_TRIGGER);
175    rightDMA.setAction(DMA_TRIGGER_ACTON_BEAT);
176    stat = rightDMA.allocate();
177  
178    //make the descriptors
179    desc = rightDMA.addDescriptor(
180      ping + 1,                    // move data from here
181      (void *)(&DAC->DATA[1]), // to here (M4)
182      MP3_OUTBUF_SIZE >> 1,                      // this many...
183      DMA_BEAT_SIZE_HWORD,               // bytes/hword/words
184      true,                             // increment source addr?
185      false,
186      DMA_ADDRESS_INCREMENT_STEP_SIZE_2,
187      DMA_STEPSEL_SRC);                           // increment dest addr?
188    desc->BTCTRL.bit.BLOCKACT = DMA_BLOCK_ACTION_INT;
189  
190    desc = rightDMA.addDescriptor(
191      pong + 1,                    // move data from here
192      (void *)(&DAC->DATA[1]), // to here (M4)
193      MP3_OUTBUF_SIZE >> 1,                      // this many...
194      DMA_BEAT_SIZE_HWORD,               // bytes/hword/words
195      true,                             // increment source addr?
196      false,
197      DMA_ADDRESS_INCREMENT_STEP_SIZE_2,
198      DMA_STEPSEL_SRC);                           // increment dest addr?
199    desc->BTCTRL.bit.BLOCKACT = DMA_BLOCK_ACTION_INT;
200  
201    //make the descriptor list loop
202    rightDMA.loop(true);
203    rightDMA.setCallback(doNothing);
204  }
205  
206  // the setup routine runs once when you press reset:
207  void setup() {
208    pinMode(13, OUTPUT);
209    Serial.begin(9600);
210    while(!Serial);
211  
212    pinMode(PIN_PAUSE, INPUT_PULLUP);
213    pinMode(PIN_RESUME, INPUT_PULLUP);
214    pinMode(PIN_PLAY, INPUT_PULLUP);
215    
216    while (!SD.begin(12000000, chipSelect)) {
217      Serial.println("Card failed, or not present");
218      delay(2000);
219    }
220    Serial.println("card initialized.");
221  
222    dataFile = SD.open(filename);
223    if(!dataFile){
224      Serial.println("could not open file!");
225      while(1);
226    }
227  
228    //set the DAC to the center of the range
229    analogWrite(A0, 2048);
230    analogWrite(A1, 2048);
231  
232    //begin the player
233    player.begin();
234  
235    //this will be how the player asks for data
236    player.setBufferCallback(getMoreData);
237  
238    //this will be how the player asks you to clean the data
239    player.setDecodeCallback(decodeCallback);
240  }
241  
242  void loop() {
243    //read volume control
244    int v = analogRead(PIN_VOLUME);
245    volume = map(v, 0, 1023, 0, VOLUME_MAX);
246  
247    //read pins
248    
249    if(!digitalRead(PIN_PAUSE)){
250      player.pause();
251    }
252    else if(!digitalRead(PIN_RESUME)){
253      player.resume();
254    }
255    else if(!digitalRead(PIN_PLAY)){
256      //this button will restart playback of the file
257      rightDMA.abort();
258      leftDMA.abort();
259  
260      if(dataFile){
261        dataFile.close();
262      }
263      dataFile = SD.open(filename);
264      if(!dataFile){
265        Serial.println("could not open file!");
266        while(1);
267      }
268  
269      player.play(); //this will automatically fill the first buffer and get the channel info
270      
271      if(player.numChannels == 1)
272        initMonoDMA(); //this is a mono file
273      
274      else if(player.numChannels == 2)
275        initStereoDMA(); //this is a stereo file
276      
277      else{
278        Serial.println("only mono and stereo files are supported");
279        while(1);
280      }
281      
282      rightDMA.startJob();
283      leftDMA.startJob();
284    }
285    delay(20);
286  }
287