Hello gurus,
My lack of C knowledge is hitting hard today. I could use a nudge in the right direction. ![]()
I'm playing with an Adafruit Music Maker FeatherWing, which includes a nifty VS1053b chip that plays back several different audio formats (and even records which blows my mind!). While Adafruit has a library to read/write to most features of the chip, it's missing a read of the millisecond-accurate playback position supported if playing specific audio types. If I could pull that value, I could make an animated robot gizmo timed to audio and that would super fun.
The positionMsec value I'm trying to pull is a uint32_t value over a range of two "registers" at the address range of 0x1E27 - 0x1E28. The Adafruit library has an included method to read uint16_t values at an address that gets me close to what I need, maybe:
uint16_t Adafruit_VS1053::sciRead(uint8_t addr) {
uint16_t data;
#ifdef SPI_HAS_TRANSACTION
if (useHardwareSPI)
SPI.beginTransaction(VS1053_CONTROL_SPI_SETTING);
#endif
digitalWrite(_cs, LOW);
spiwrite(VS1053_SCI_READ);
spiwrite(addr);
delayMicroseconds(10);
data = spiread();
data <<= 8;
data |= spiread();
digitalWrite(_cs, HIGH);
#ifdef SPI_HAS_TRANSACTION
if (useHardwareSPI)
SPI.endTransaction();
#endif
return data;
}
However, I'm puzzled on getting a uint32_t over two registers. My initial attempt was to read a uint16_t value at 0x1E27 and 0x1E28 separately and printing out the values that way to see what could be done:
// Specifically for use with the Adafruit Feather, the pins are pre-set here!
// include SPI, MP3 and SD libraries
#include <SPI.h>
#include <SD.h>
#include <Adafruit_VS1053.h>
// These are the pins used
#define VS1053_RESET -1 // VS1053 reset pin (not used!)
// Feather ESP8266
#if defined(ESP8266)
#define VS1053_CS 16 // VS1053 chip select pin (output)
#define VS1053_DCS 15 // VS1053 Data/command select pin (output)
#define CARDCS 2 // Card chip select pin
#define VS1053_DREQ 0 // VS1053 Data request, ideally an Interrupt pin
// Feather ESP32
#elif defined(ESP32) && !defined(ARDUINO_ADAFRUIT_FEATHER_ESP32S2)
#define VS1053_CS 32 // VS1053 chip select pin (output)
#define VS1053_DCS 33 // VS1053 Data/command select pin (output)
#define CARDCS 14 // Card chip select pin
#define VS1053_DREQ 15 // VS1053 Data request, ideally an Interrupt pin
// Feather Teensy3
#elif defined(TEENSYDUINO)
#define VS1053_CS 3 // VS1053 chip select pin (output)
#define VS1053_DCS 10 // VS1053 Data/command select pin (output)
#define CARDCS 8 // Card chip select pin
#define VS1053_DREQ 4 // VS1053 Data request, ideally an Interrupt pin
// WICED feather
#elif defined(ARDUINO_STM32_FEATHER)
#define VS1053_CS PC7 // VS1053 chip select pin (output)
#define VS1053_DCS PB4 // VS1053 Data/command select pin (output)
#define CARDCS PC5 // Card chip select pin
#define VS1053_DREQ PA15 // VS1053 Data request, ideally an Interrupt pin
#elif defined(ARDUINO_NRF52832_FEATHER )
#define VS1053_CS 30 // VS1053 chip select pin (output)
#define VS1053_DCS 11 // VS1053 Data/command select pin (output)
#define CARDCS 27 // Card chip select pin
#define VS1053_DREQ 31 // VS1053 Data request, ideally an Interrupt pin
// Feather M4, M0, 328, ESP32S2, nRF52840 or 32u4
#else
#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
// DREQ should be an Int pin *if possible* (not possible on 32u4)
#define VS1053_DREQ 9 // VS1053 Data request, ideally an Interrupt pin
#endif
Adafruit_VS1053_FilePlayer musicPlayer =
Adafruit_VS1053_FilePlayer(VS1053_RESET, VS1053_CS, VS1053_DCS, VS1053_DREQ, CARDCS);
void setup() {
Serial.begin(115200);
// if you're using Bluefruit or LoRa/RFM Feather, disable the radio module
//pinMode(8, INPUT_PULLUP);
// Wait for serial port to be opened, remove this line for 'standalone' operation
while (!Serial) { delay(1); }
delay(500);
Serial.println("\n\nAdafruit VS1053 Feather Test");
if (! musicPlayer.begin()) { // initialise the music player
Serial.println(F("Couldn't find VS1053, do you have the right pins defined?"));
while (1);
}
Serial.println(F("VS1053 found"));
if (!SD.begin(CARDCS)) {
Serial.println(F("SD failed, or not present"));
while (1); // don't do anything more
}
Serial.println("SD OK!");
// Set volume for left, right channels. lower numbers == louder volume!
musicPlayer.setVolume(200,200);
#if defined(__AVR_ATmega32U4__)
// Timer interrupts are not suggested, better to use DREQ interrupt!
// but we don't have them on the 32u4 feather...
musicPlayer.useInterrupt(VS1053_FILEPLAYER_TIMER0_INT); // timer int
#else
// If DREQ is on an interrupt pin we can do background
// audio playing
musicPlayer.useInterrupt(VS1053_FILEPLAYER_PIN_INT); // DREQ int
#endif
Serial.println(F("playing track..."));
musicPlayer.startPlayingFile("/track002.ogg");
}
void loop() {
uint16_t decodeTime;
uint16_t playMsec0;
uint16_t playMsec1;
// File is playing in the background
if (musicPlayer.stopped()) {
Serial.println("done playing track");
while (1) {
delay(10); // we're done! do nothing...
}
} else {
decodeTime = musicPlayer.decodeTime();
playMsec0 = musicPlayer.sciRead(0x1E27);
playMsec1 = musicPlayer.sciRead(0x1E28);
Serial.print("decodeTime(): ");
Serial.print(decodeTime);
Serial.print(" playMsec0: ");
Serial.print(playMsec0);
Serial.print(" playMsec1: ");
Serial.print(playMsec1);
Serial.print("\n");
}
delay(100);
}
If I read from those values though while playing back a .ogg file, 0x1E27 always reads as "7721", while 0x1E28 reads as other crazy numbers that change by the second, sometimes (see below). These values are not populated when playing a .mp3 file as expected. I can read other nearby values properly such as 0x1E05 (also not used in the Adafruit library) which is the average playback rate, quickly ramping up to "48001" in the case of my .ogg file.
Output:
Adafruit VS1053 Feather Test
VS1053 found
SD OK!
playing track...
decodeTime(): 0 playMsec0: 7721 playMsec1: 0
decodeTime(): 0 playMsec0: 7721 playMsec1: 0
decodeTime(): 0 playMsec0: 7721 playMsec1: 0
decodeTime(): 0 playMsec0: 7721 playMsec1: 0
decodeTime(): 0 playMsec0: 7721 playMsec1: 0
decodeTime(): 0 playMsec0: 7721 playMsec1: 0
decodeTime(): 0 playMsec0: 7721 playMsec1: 0
decodeTime(): 0 playMsec0: 7721 playMsec1: 0
decodeTime(): 0 playMsec0: 7721 playMsec1: 0
decodeTime(): 1 playMsec0: 7721 playMsec1: 33805
decodeTime(): 1 playMsec0: 7721 playMsec1: 33805
decodeTime(): 1 playMsec0: 7721 playMsec1: 33805
decodeTime(): 1 playMsec0: 7721 playMsec1: 33805
decodeTime(): 1 playMsec0: 7721 playMsec1: 33805
decodeTime(): 1 playMsec0: 7721 playMsec1: 33805
decodeTime(): 1 playMsec0: 7721 playMsec1: 33805
decodeTime(): 1 playMsec0: 7721 playMsec1: 33805
decodeTime(): 1 playMsec0: 7721 playMsec1: 33805
decodeTime(): 2 playMsec0: 7721 playMsec1: 26549
decodeTime(): 2 playMsec0: 7721 playMsec1: 26549
decodeTime(): 2 playMsec0: 7721 playMsec1: 26549
decodeTime(): 2 playMsec0: 7721 playMsec1: 26549
decodeTime(): 2 playMsec0: 7721 playMsec1: 26549
decodeTime(): 2 playMsec0: 7721 playMsec1: 26549
decodeTime(): 2 playMsec0: 7721 playMsec1: 26549
decodeTime(): 2 playMsec0: 7721 playMsec1: 26549
decodeTime(): 3 playMsec0: 7721 playMsec1: 27018
decodeTime(): 3 playMsec0: 7721 playMsec1: 27018
decodeTime(): 3 playMsec0: 7721 playMsec1: 27018
decodeTime(): 3 playMsec0: 7721 playMsec1: 27018
decodeTime(): 3 playMsec0: 7721 playMsec1: 27018
decodeTime(): 3 playMsec0: 7721 playMsec1: 27018
decodeTime(): 3 playMsec0: 7721 playMsec1: 27018
decodeTime(): 3 playMsec0: 7721 playMsec1: 27018
decodeTime(): 4 playMsec0: 7721 playMsec1: 27689
decodeTime(): 4 playMsec0: 7721 playMsec1: 27689
decodeTime(): 4 playMsec0: 7721 playMsec1: 27689
decodeTime(): 4 playMsec0: 7721 playMsec1: 27689
decodeTime(): 4 playMsec0: 7721 playMsec1: 27689
decodeTime(): 4 playMsec0: 7721 playMsec1: 27689
decodeTime(): 4 playMsec0: 7721 playMsec1: 27689
decodeTime(): 4 playMsec0: 7721 playMsec1: 27689
decodeTime(): 4 playMsec0: 7721 playMsec1: 27689
decodeTime(): 5 playMsec0: 7721 playMsec1: 27689
decodeTime(): 5 playMsec0: 7721 playMsec1: 27689
decodeTime(): 5 playMsec0: 7721 playMsec1: 27689
decodeTime(): 5 playMsec0: 7721 playMsec1: 27689
decodeTime(): 5 playMsec0: 7721 playMsec1: 27689
decodeTime(): 5 playMsec0: 7721 playMsec1: 27689
decodeTime(): 5 playMsec0: 7721 playMsec1: 27689
decodeTime(): 5 playMsec0: 7721 playMsec1: 27689
decodeTime(): 5 playMsec0: 7721 playMsec1: 27689
decodeTime(): 6 playMsec0: 7721 playMsec1: 27689
decodeTime(): 6 playMsec0: 7721 playMsec1: 27689
decodeTime(): 6 playMsec0: 7721 playMsec1: 27689
decodeTime(): 6 playMsec0: 7721 playMsec1: 27689
decodeTime(): 6 playMsec0: 7721 playMsec1: 27689
decodeTime(): 6 playMsec0: 7721 playMsec1: 27689
decodeTime(): 6 playMsec0: 7721 playMsec1: 27689
decodeTime(): 6 playMsec0: 7721 playMsec1: 27689
decodeTime(): 7 playMsec0: 7721 playMsec1: 27689
decodeTime(): 7 playMsec0: 7721 playMsec1: 27689
done playing track
Perhaps reading two values like that separately is not the way to go. Would you have an idea on how to get that uint32_t value over a range registers 0x1E27 to 0x1E28? Once I get this going, I'll be sure to post a crude demo video as thanks.
Thanks for taking a look in advance! ![]()