Open
Description
There appears to be an incompatibility between the ArduinoSound.h and RTCZero.h libraries.
When you try to play an audio file after the internal RTC has been initialised, the WAV files won't play. See the rtc.begin()
function call in the code below.
Configuration: MKRZERO and Adafruit MAX98357A I2S audio board.
#include <SD.h> // SD card access library
#include <ArduinoSound.h> // I2S sound interface library
#include <RTCZero.h> // Real Time Clock library
// SETUP Audio playback
// filename of wave file to play
const char filename[] = "MUSIC.WAV";
// variable representing the Wave File
SDWaveFile waveFile;
// SETUP Real Time Clock
/* Create a RTC object */
RTCZero rtc;
/* Change these values to set the current initial time */
const byte seconds = 0;
const byte minutes = 0;
const byte hours = 16;
/* Change these values to set the current initial date */
const byte day = 15;
const byte month = 6;
const byte year = 15;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600); // Start Arduino serial port at 9,600 baud
//SD.begin(); // Open the SD card
delay(500);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
// setup the SD card, depending on your shield of breakout board
// you may need to pass a pin number in begin for SS
Serial.print("Initializing SD card..z.");
if (!SD.begin()) {
Serial.println("initialization failed!");
return;
}
Serial.println("initialization done.");
// create a SDWaveFile
waveFile = SDWaveFile(filename);
// check if the WaveFile is valid
if (!waveFile) {
Serial.println("wave file is invalid!");
while (1); // do nothing
}
// print out some info. about the wave file
Serial.print("Bits per sample = ");
Serial.println(waveFile.bitsPerSample());
long channels = waveFile.channels();
Serial.print("Channels = ");
Serial.println(channels);
long sampleRate = waveFile.sampleRate();
Serial.print("Sample rate = ");
Serial.print(sampleRate);
Serial.println(" Hz");
long duration = waveFile.duration();
Serial.print("Duration = ");
Serial.print(duration);
Serial.println(" seconds");
// adjust the playback volume
AudioOutI2S.volume(100);
// check if the I2S output can play the wave file
if (!AudioOutI2S.canPlay(waveFile)) {
Serial.println("unable to play wave file using I2S!");
while (1); // do nothing
}
// IF START PLAYBACK LOCATED HERE IT WORKS
// start playback
Serial.println("starting playback");
AudioOutI2S.play(waveFile);
// Start the RTC
rtc.begin(); // Initialize RTC
// IF START PLAYBACK LOCATED HERE, after rtc.begin();, IT DOESN'T
// start playback
//Serial.println("starting playback");
//AudioOutI2S.play(waveFile);
// Set the time
rtc.setHours(hours);
rtc.setMinutes(minutes);
rtc.setSeconds(seconds);
// Set the date
rtc.setDay(day);
rtc.setMonth(month);
rtc.setYear(year);
rtc.setAlarmTime(16, 0, 20);
rtc.enableAlarm(rtc.MATCH_HHMMSS);
rtc.attachInterrupt(alarmMatch);
}
void loop() {
}
void alarmMatch() {
Serial.println("Alarm Match!");
}
Metadata
Metadata
Assignees
Labels
No labels
Activity
white-ar commentedon Aug 24, 2019
Having investigated this, I wonder if it is a clock conflict?
sslupsky commentedon Sep 12, 2019
@white-ar I think you are likely correct regarding the clock conflict. I have not used ArduinoSound but had a quick look. Unfortunately, I cannot locate where the I2C object is actually instantiated so I cannot determine which clock it is using. I2S.h has an external reference but not the actual instantiation with the parameters that indicate which clock is used. Maybe someone more familiar with this library could chime in and tell us where it is instantiated.
white-ar commentedon Sep 12, 2019
@sslupsky thank you, I am glad I am not the only one who has 'reached a dead end' whilst trying to fault find this.
There is a similar problem when trying to call the LowPowerArduino function. I assume it is possible that the issue could also lie in the SD card library <SD.h>
It seems from the Atmel Software Framework (ASF) that it is possible to use different clocks. So, I assume if one of the libraries re configures a clock used by one of the other libraries, this could cause a conflict.
As you say, this problem appears to require the help of someone with greater holistic knowledge of the architecture, and I suspect ASF.
All help greatly appreciated.
sslupsky commentedon Sep 12, 2019
@white-ar I have found issues with the RTC library and the LowPowerLibrary. I recently added support for using the periodic interval interrupts with the RTC and the event system. This allows you to wake up more often than is possible using the RTC alarm interrupts.
There are some defects with the Wire and SERCOM libraries with regard the low power compatibility as well. I proposed some solutions with a PR but they have not been accepted (yet?).
aoriani commentedon Dec 24, 2021
I wonder if someone got some ideas after two years. I am working on a clock that would play sound alarms using the MKR WIFI 1010. The board would freeze when trying to play a file. I took hours to realize that removing any line that touched the RTC, would allow the board to play the sound.
white-ar commentedon Dec 24, 2021
@aoriani Hi Andre, I never managed to get it to work, and gave up on making a battery powered version.
@sandeepmistry : was there a resolution to this issue?
I'm sorry, I can't be of further assistance.
aoriani commentedon Dec 24, 2021
@white-ar thanks a lot for your response. It looks like you were the pioneer on this issue because every Google search hits a post of yours. If I correctly followed your saga, you ended using an external RTC and you could not use the LowerPower lib because it faced a similar problem. Is that a precise account?
Someone mentioned on https://forums.adafruit.com/viewtopic.php?f=25&t=182648 that the possible root cause was the RTC lib enabling protection on a register needed by I2S. So I wonder if the incompatibility is at the hardware level, or is there still hope that it could be solved thru software?
white-ar commentedon Dec 24, 2021
@aoriani My project was an alarm clock that played music. The issue being that unless one puts the Arduino into low power mode (sleep) it draws too much power to be viably from battery power.
The RTC was used to keep time when the Arduino is switched off, or between battery changes, etc.
You may note from the code snippet above, this is standard Arduino example code, with the simple addition of the standard RTCzero library. Put another way - the issue is within the standard libraries. I started investigating the underlying libraries and register architecture, however it soon became clear that I didn't have enough background knowledge to make any meaningful progress in this regards.
My project succeeded in its wider goal, so all was not lost.
If you 'need' to get this working, you could try a pair of Arduinos, using an interrupt to signal between them. i.e. one handles the RTC, then wakes the Zero to play audio. (Note: Also, you'd need to message time and alarm time, etc, between them as well.)
Alternatively you could look at a STM32 dev card or even a RPI ... Each of these other routes will undoubtedly have its issues.
Hope this helps.
Khosos commentedon Jan 21, 2023
Hey everyone. I ran into this issue recently and found a fix that seems to work so far. The issue has to do with clock conflicts as many of you have suspected. When the RTCZero library configures the clock it sets the bit value of DIVSEL in the GLCK GENCTRL register to 1. I2S expects this value to be 0 but doesn't explicitly set its value.
To remedy this all you have to do is add this line in the I2S library within the ( void I2SClass::enableClock(int divider) ) function. GCLK->GENCTRL.bit.DIVSEL = 0;
Below is where that line of code goes.
// use the DFLL as the source
while (GCLK->STATUS.bit.SYNCBUSY);
GCLK->GENCTRL.bit.ID = _clockGenerator;
GCLK->GENCTRL.bit.SRC = src;
GCLK->GENCTRL.bit.IDC = 1;
GCLK->GENCTRL.bit.DIVSEL = 0;
GCLK->GENCTRL.bit.GENEN = 1;