Feather M0 Express Arduino IDE Setup
We'll upload the code to the Adafruit Feather M0 Express using the Arduino IDE. We'll need to have the Adafruit board profile and libraries installed before uploading the code. If you're new to Arduino, let's first walkthrough the board profile setup using the Adafruit Feather M0 Express guide.
Installing Libraries in Arduino
With the board profile, we can then install the dependencies. We'll use Arduino's built-in Library Manage to install the libraries. Goto Sketch > Include Library and select Manage Libraries. Here, we'll search for the Adafruit VS1053 Library and install the latest version.
Uploading Code
With the Feather board profile and Arduino library installed, download the mp3player.ino file save them to a new folder named “mp3player”. You'll want to place the new folder into arduino's sketches folder (ie. ~/HD/Documents/Arduino/sketches).
Open the mp3player.ino file in the Arduino IDE. Select the Adafruit Feather M0 Express board under the Tools > Board menu. Connect the Feather board to your computer via microUSB cable and select "/dev/cu.modem..." under the Tools > Port menu (Option might be named different using Windows OS).
Upload the code to the Feather using the Upload command, Cmd+U or clicking the arrow icon.
// SPDX-FileCopyrightText: 2017 Carter Nelson for Adafruit Industries // // SPDX-License-Identifier: MIT // // Gordon Cole MP3 Player // #include <SPI.h> #include <SD.h> #include <Adafruit_VS1053.h> // Guide is based on Feather M0 Express // ARDUINO_SAMD_FEATHER_M0 defines only // VS1053 Pins #define VS1053_RESET -1 // VS1053 reset pin (not used!) #define VS1053_CS 6 // VS1053 chip select pin (output) #define VS1053_DCS 10 // VS1053 Data/command select pin (output) #define CARDCS 5 // Card chip select pin #define VS1053_DREQ 9 // VS1053 Data request, ideally an Interrupt pin // Button Pins #define BUTTON_PLAY 13 // PLAY / STOP button #define BUTTON_PAUSE 12 // PAUSE / RESUME button #define BUTTON_NEXT 11 // NEXT button // Status LED #define LED_STATUS 19 // status LED #define BLINK_RATE 500 // blink rate in ms // Volume Control #define KNOB_VOLUME 0 // volume knob #define KNOB_MIN 0 // min ADC value #define KNOB_MAX 1023 // max ADC value #define VOL_MIN 0 // min volume (most loud) #define VOL_MAX 50 // max volume (most quiet) #define VOL_UPDATE 250 // update rate in ms #define VOL_SAMPLES 10 // number of reads for average #define VOL_SAMPLE_RATE 5 // ms delay per sample #define VOL_THRESHOLD 20 // vol must change by this many counts // Maximum number of files (tracks) to load #define TRACKS_MAX 100 // Player behavior #define AUTO_PLAY_NEXT true // true to automatically go to next track unsigned long currentMillis; unsigned long previousBlinkMillis, previousVolMillis; int currentKnob, previousKnob; int volume; int currentTrack, totalTracks; char trackListing[TRACKS_MAX][13] = {' '}; enum mode { PLAYING, PAUSED, STOPPED } currentMode = STOPPED; Adafruit_VS1053_FilePlayer musicPlayer = Adafruit_VS1053_FilePlayer(VS1053_RESET, VS1053_CS, VS1053_DCS, VS1053_DREQ, CARDCS); //----------------------------------------------------------------------------- void setup() { Serial.begin(9600); // Leave commented for standalone operation, uncomment for troubleshooting //while (!Serial) ; // Initialize pins pinMode(BUTTON_PLAY, INPUT_PULLUP); pinMode(BUTTON_PAUSE, INPUT_PULLUP); pinMode(BUTTON_NEXT, INPUT_PULLUP); pinMode(LED_STATUS, OUTPUT); // Initialize status LED previousBlinkMillis = millis(); digitalWrite(LED_STATUS, LOW); Serial.println("\n\nGordon Cole MP3 Player"); // Initialize the music player if (! musicPlayer.begin()) { Serial.println(F("Couldn't find VS1053, do you have the right pins defined?")); while (1) { digitalWrite(LED_STATUS, !digitalRead(LED_STATUS)); delay(100); } } Serial.println(F("VS1053 found")); musicPlayer.softReset(); // Make a tone to indicate VS1053 is working musicPlayer.sineTest(0x44, 500); // Set volume for left, right channels. lower numbers == louder volume! previousVolMillis = millis(); previousKnob = analogRead(KNOB_VOLUME); volume = map(previousKnob, KNOB_MIN, KNOB_MAX, VOL_MIN, VOL_MAX); Serial.print("Volume = "); Serial.println(volume); musicPlayer.setVolume(volume, volume); // Initialize the SD card if (!SD.begin(CARDCS)) { Serial.println(F("SD failed, or not present")); while (1) { digitalWrite(LED_STATUS, !digitalRead(LED_STATUS)); delay(100); } } Serial.println("SD OK!"); // Load list of tracks Serial.println("Track Listing"); Serial.println("============="); totalTracks = 0; loadTracks(SD.open("/"), 0); currentTrack = 0; // Setup interrupts (DREQ) for playback musicPlayer.useInterrupt(VS1053_FILEPLAYER_PIN_INT); } //----------------------------------------------------------------------------- void loop() { // Check and set volume updateVolume(); // Update status LED updateStatusLED(); // Auto play next track if feature enabled if (AUTO_PLAY_NEXT) { if (currentMode==PLAYING && musicPlayer.stopped()) { currentTrack = ++currentTrack < totalTracks ? currentTrack : 0; Serial.print("Next "); Serial.print(currentTrack); Serial.print("="); Serial.println(trackListing[currentTrack]); musicPlayer.startPlayingFile(trackListing[currentTrack]); currentMode = PLAYING; } } // Start / Stop if (!digitalRead(BUTTON_PLAY)) { if (musicPlayer.stopped()) { Serial.print("Start "); Serial.print(currentTrack); Serial.print("="); Serial.println(trackListing[currentTrack]); musicPlayer.startPlayingFile(trackListing[currentTrack]); currentMode = PLAYING; } else { Serial.println("Stopped."); musicPlayer.stopPlaying(); currentMode = STOPPED; } delay(250); } // Pause / Resume if (!digitalRead(BUTTON_PAUSE)) { if (!musicPlayer.stopped()) { if (musicPlayer.paused()) { Serial.println("Resumed"); musicPlayer.pausePlaying(false); currentMode = PLAYING; } else { Serial.println("Paused"); musicPlayer.pausePlaying(true); currentMode = PAUSED; } } delay(250); } // Next if (!digitalRead(BUTTON_NEXT)) { if (!musicPlayer.stopped()) { Serial.println("Stopping current playback."); musicPlayer.stopPlaying(); } currentTrack = ++currentTrack < totalTracks ? currentTrack : 0; Serial.print("Next "); Serial.print(currentTrack); Serial.print("="); Serial.println(trackListing[currentTrack]); musicPlayer.startPlayingFile(trackListing[currentTrack]); currentMode = PLAYING; delay(250); } } //----------------------------------------------------------------------------- void updateVolume() { // Rate limit currentMillis = millis(); if (currentMillis - previousVolMillis < VOL_UPDATE) return; previousVolMillis = currentMillis; // Get an average reading currentKnob = 0; for (int i=0; i<VOL_SAMPLES; i++) { currentKnob += analogRead(KNOB_VOLUME); delay(VOL_SAMPLE_RATE); } currentKnob /= VOL_SAMPLES; // Only update if it's changed if (abs(currentKnob-previousKnob) > VOL_THRESHOLD) { Serial.print("["); Serial.print(currentKnob); Serial.print(","); Serial.print(previousKnob); Serial.print("] "); previousKnob = currentKnob; volume = map(currentKnob, KNOB_MIN, KNOB_MAX, VOL_MIN, VOL_MAX); Serial.print("Volume set to: "); Serial.println(volume); musicPlayer.setVolume(volume, volume); } } //----------------------------------------------------------------------------- void updateStatusLED() { if (musicPlayer.paused()) { // Blink it like a polaroid currentMillis = millis(); if (currentMillis - previousBlinkMillis > BLINK_RATE) { previousBlinkMillis = currentMillis; digitalWrite(LED_STATUS, !digitalRead(LED_STATUS)); } } else if (!musicPlayer.stopped()) { // It's so on again digitalWrite(LED_STATUS, HIGH); } else { // It's so off again digitalWrite(LED_STATUS, LOW); } } //----------------------------------------------------------------------------- void loadTracks(File dir, int level) { while (true) { File entry = dir.openNextFile(); if (!entry) return; if (entry.isDirectory()) { // Recursive call to scan next dir level loadTracks(entry, level + 1); } else { // Only add files in root dir if (level == 0) { // And only if they have good names if (nameCheck(entry.name())) { strncpy(trackListing[totalTracks], entry.name(), 12); Serial.print(totalTracks); Serial.print("="); Serial.println(trackListing[totalTracks]); totalTracks++; } } } entry.close(); // Stop scanning if we hit max if (totalTracks >= TRACKS_MAX) return; } } //----------------------------------------------------------------------------- bool nameCheck(char* name) { int len = strlen(name); // Check length if (len <= 4) return false; // Check extension char* ext = strrchr(name,'.'); if (!( strcmp(ext,".MP3") == 0 || strcmp(ext,".OGG") == 0 )) return false; // Check first character switch(name[0]) { case '_': return false; } return true; }
Text editor powered by tinymce.