PaulStoffregen
Well-known member
I've been pretty quiet the last couple days.... better SD caching that's interrupt safe is turning into quite a project!
Just another quick update... I'm still very actively working on this problem.
Over the last several days, I've ended up rewriting the entire SD+SdFat library. Well. most of it so far, but only reading, not writing to the card. Originally I wanted to just patch Bill's code, and I made a pretty good attempt at that last week. But there were just too many complex paths to analyze, especially in the directory parsing, to resolve all the ranges where pointers still depended on cached data. Bill's put a lot of work into reducing the AVR code size, and most of his code is still pretty readable, but it was never designed with a multi-sector, interrupt aware cache in mind, which needs to be notified when the filesystem is and isn't depending on buffers to remain fixed.
Ultimately, I started fresh. Fortunately, I'm pretty familiar with FAT filesystems, from the old MP3 player days when I wrote simpler filesystem code all in 8051 assembly.
This time around, I created a SDCache object, where the static cached sector buffers have usage counts of the number SDCache objects currently requiring them. I'm using the object destructor to manage when the cache can allow a buffer to be released back into the pool to be reused. By writing all the code fresh, I can structure things with these objects and pointers to allow the cache to properly serve multiple concurrent, interrupt-based and main program users.
This morning I got the new code playing the stress test, with 1, 2, 3, 4 all playing and without any chirps or audible artifacts (at least nothing I can hear within the noise floor on these samples using good over-ear headphones). There's still some bugs to work out, like a memory leak that eventually strikes, and quite a bit of the new code still needs to optimization.
Anyway, the good news is an excellent solution is in sight. Well, with the caveat that at least for quite some time, there will be a choice between the original SD library which can read and write, and this new one that's read-only. Eventually I'll add write support, but that's not going to happen this week.
I hope to have code to share in a day or two. This has been a really tough problem, but the end is finally in sight.
Ok, I've committed a pile of new code to github. This is still at a very early stage, but at least in a couple lengthy tests here it was looking really good.
The main thing is the SD library.
https://github.com/PaulStoffregen/SD
You'll need to edit SD_t3.h, line 30. By default, the normal SD library is used. You must uncomment that line to compile the new code.
The new SD code has quite a number of limitations. It can't parse pathnames, so you can only open files in the root directory. It can't write to the card. A few of the SD functions, like openNextFile() aren't implemented yet. I've only tested on 2 cards so far, both FAT32 format, so FAT16 (2GB or less) is utterly untested so far. Remember, this is a complete ground-up rewrite of the SD library. Expect some issues.....
But the larger cache and playing more than 1 file at a time while opening others works! Or at least it has on tests I've been doing here.
You'll also need the latest Audio library from github. It was disabling interrupts, as a not-so-great workaround for the SD library problems. This change removes that, so audio can play during the lengthy open while the library has to parse the huge directory with hundreds of files.
https://github.com/PaulStoffregen/Audio/commit/4c6e76e2b4b0888874fc9b60c843bfb9c4248b8a
The other minor thing, which probably doesn't matter (but I've done all my recent testing with it) is this little patch to kinetis.h:
https://github.com/PaulStoffregen/cores/commit/8cd4703817f4e0d143e4686b101c4f34614040bd
I've been doing all my testing on Arduino 1.6.3. In theory, any copy with Teensyduino 1.22 installed should give the same results. Well, except the old versions only run the compiler with code size optimization, so you probably want one of the newer version with speed optimization (in the Tools > CPU Speed menu).
#include <Audio.h>
#include <Wire.h>
#include <SD.h>
#include <SPI.h>
//////////////////////////////////////////////////////////////////////////
//////////////////////// Audio Setup ///////////////////////////
AudioPlaySdRaw raw4; //channel 4 playback
AudioPlaySdRaw raw3; //channel 4 playback
AudioPlaySdRaw raw2; //channel 4 playback
AudioPlaySdRaw raw1; //channel 4 playback
AudioMixer4 mixer1; //combines up to 4 channels, can play even more if needed by more mixers
AudioOutputI2S i2s; //I2S type playback (opposed to I2C etc)
AudioConnection patchCord1(raw4, 0, mixer1, 3);
AudioConnection patchCord2(raw3, 0, mixer1, 2);
AudioConnection patchCord3(raw2, 0, mixer1, 1);
AudioConnection patchCord4(raw1, 0, mixer1, 0);
AudioConnection patchCord5(mixer1, 0, i2s, 0);
AudioControlSGTL5000 sgtl5000; //audio codec chip
//////////////////////////////////////////////////////////////////////////
const float maxVolume = 0.1;//set speaker volume
const int playbackInterval = 500; //time between files in milliseconds
void setup()
{
AudioMemory(30); //memory usage usually around 6-7, more mixers use more memory
sgtl5000.enable();
mixer1.gain(0, maxVolume); //channel, volume
mixer1.gain(1, maxVolume);
mixer1.gain(2, maxVolume);
mixer1.gain(3, maxVolume);
SPI.setMOSI(7); //move from pin 6 to pin 7
SPI.setSCK(14); //move from pin 13 to pin 14
SD.begin(10); //set SD card cable pin select to pin (#10)
}
void loop()
{
raw1.play("300.RAW");
delay(playbackInterval); //wait to open next file
raw2.play("700.RAW");
delay(playbackInterval); //wait to open next file
raw3.play("600.RAW");
delay(playbackInterval); //wait to open next file
raw4.play("050.RAW");
delay(playbackInterval); //wait to open next file
}
Also it still skips numbers at 500ms or less, which does not work for me. I'm not 100% sure I have the patch installed correct.
It's almost certainly not installed properly.
I know there's a lot of separate pieces to get right. Later this week I'll put together a beta installer. That's the way I can help.
Any idea what would cause the SD updated library not to work with that version?
Otherwise, the audio portion of our product is stuck for now.
Any updates on this?
We are willing to make donations to keep wheels of progress spinning...
The new SD code has quite a number of limitations. It can't parse pathnames, so you can only open files in the root directory. It can't write to the card. A few of the SD functions, like openNextFile() aren't implemented yet.