First of all, very nice work. Only scrolled through the code, but it looks good.
Hey, thanks Erik! :)
Shouldn't it be fairly simple to make the CardDetect interrupt optional (if NC is supplied)? Sure then you cannot change cards anymore, but everything else should still work fine.
Not exactly, as trying to create an InterruptIn using NC currently throws a nasty assertion error:
mbed assertation failed: pin != (PinName)NC, file: C:\work\mbed\github\libraries\mbed\targets\hal\TARGET_NXP\TARGET_LPC11UXX\pinmap.c, line 38
The only way around this, that I can see, would be to conditionally create an InterruptIn on the heap, and I try to avoid using the heap if at all possible. If somebody were to patch InterruptIn to gracefully ignore NC's this could work though. In fact, I've been having a lot of trouble with NC's in general since around release 85. Constructors that previously worked just fine with NC's and/or are encouraged to be used with NC's like RawSerial now hang. :/
Possibly then an 'eject' function to manually set the lib back to unitialized?
Very possible, but you would have to use FatFs' f_mount() function to reset the file system object (which is owned by FATFileSystem). I might add a method to FATFileSystem for this and submit a pull request later. I've submit a pull request over at GitHub for this, more details below.
A few of your numbers in code could be replaced by defines/enums. (For example your 500ms wait). Can make it a bit clearer.
Clarity is actually why I don't use defines for these numbers, I hate having to go look for them to see what their values are. Much better to use the actual number and comment on what's going on, in my opinion anyway. That is, unless such value is a tuning value that's used in many places throughout the code, in which case I would make that a private constant. Defines are just so... C... ;)
Pull ups on MISO might be quite irritating, especially on standard shields which don't have them. Just checked seeedstudio SD shield, doesn't have them (and even has buffers in between, so you can't add them without soldering them directly on it). Same story for some of the recent TFTs with SD card holder, also no pull ups, and buffers. Maybe internal pull ups can be activated for those without buffer, but to make it official lib (which would be nice, since it looks alot better), it should also work without pull ups.
I hear you, but unfortunately the pullups are considered SD/MMC spec according to ChaN's SD/MMC writeup. Strictly speaking, only the DO pullup is required for correct operation. Without it, the card will continually fail the following busy check:
inline bool SDFileSystem::waitReady(int timeout)
{
//Wait for the specified timeout for the card to become ready
for (int i = 0; i < timeout; i++) {
if (m_SPI.write(0xFF) == 0xFF)
return true;
wait_ms(1);
}
//We timed out
return false;
}
According to ChaN's SD/MMC writeup, if the card is busy it will drive DO low as soon as it's selected, and release it when it's ready. It would have been fortunate if the card actually drove the pin high when ready, but that does not seem to be the case. I'm convinced that the busy check is the reason my library works at high clock frequencies where others fail, and ideally these breakout boards should be adhering to spec and proving pullups. The internal pullups would be perfect for this (especially to support shields), but that would require some patching to the mbed library. I'm not sure how the level shifters complicate this, since my Adafruit breakout board has one and I just added a 100kΩ pullup to 3.3V at the mbed pin. Although if the level shifter was connected to 5V I suppose DO could backfeed the 3.3V rail through the resistor... In this case, you would need to pull up to 5V.
Finally something I wonder about, getting any troubles with the FATFileSystem buffer? I got the USBFileSystem lib, which writes to a shared medium with both FATFileSystem and USBMSD. It is made sure that they can't write at the same time. However still I ran in some situations into issues where FATFileSystem 'caches' directory sectors. Which it didn't re-read. And I don't see something in your code which tells it to reset itself (also not aware of possibilities to do it). I might try later if I can reproduce it with your lib if you haven't already taken that into account and I just haven't seen it.
I believe I solved it by setting FS_TINY in the FAT config file to 1.
Unfortunately, I don't think FatFs exposes it's buffers for public tampering... There's an f_sync() function that can be used to flush any write caches (FATFileSystem makes sure this calls disk_sync()), but nothing that I can see for dealing with the read cache. Explicitly unmounting the filesystem might fix this, see below for more details. At any rate, this would be a FATFileSystem limitation, and not an SDFileSystem limitation.
Bold suggestion here: scrap the existing SDFileSystem library, and re-write it to handle things like card removal and errors properly. I've spent all morning trying to come up with a way of making it handle card removal and reinsertion, and I've had no success. I even tried calling sd.disk_initialize() twice several seconds after reinserting the card as suggested here, with no success. I should point out that I removed and reinserted the card before accessing it, so file pointers are not the issue here. I can't imagine a use case outside of general hobbying in which expecting an SD card to be present from power up to power down with no chance of it being removed would be desirable. Equally as bad is the fact that it currently spits out errors using debug(...) rather than error(...), making it useless on a production device, or even a platform that doesn't support stdio messages. I don't mean to sound overly critical, but I feel like this library is of beta quality at best compared to other official libraries like USBDevice, mbed-rtos, and let's not forget the excellent mbed library.