Hi,
I am building a prototype that uses an uSD card to log data with Mbed OS 6.6. The user will need to be able to remove the SD card and re-insert it without physically resetting the device.
Based on this example for testing i came up with the code posted below.
Basically it mounts/unmounts every 10 seconds. Works fine until i remove/reinsert the SD card. However after doing so, it throws a hard fault next time it tries to mount even if the card is already reinserted at that time. Interestingly the erase() works even after reinserting, but only until the code tries to mount the FS.
I am kinda lost here and need help how to get it working properly. I am also wondering if this might be a bug? I mean it is the nature of SD cards that we can insert/remove them. So i would expect no probems with fs.mount() if i already made fs.unmount() before the removal.
#include “mbed.h”
#include
#include <errno.h>
#include
#include <stdio.h>
#include “SDBlockDevice.h”
// Maximum number of elements in buffer
#define BUFFER_MAX_LEN 10
#define FORCE_REFORMAT false
// This will take the system’s default block device
SDBlockDevice *blockdevice =
new SDBlockDevice(MBED_CONF_SD_SPI_MOSI, MBED_CONF_SD_SPI_MISO,
MBED_CONF_SD_SPI_CLK, MBED_CONF_SD_SPI_CS);
// Instead of the default block device, you can define your own block device.
// For example: HeapBlockDevice with size of 2048 bytes, read size 1, write size
// 1 and erase size 512. #include “HeapBlockDevice.h” BlockDevice *blockdevice = new
// HeapBlockDevice(2048, 1, 1, 512);
#include "FATFileSystem.h"
FATFileSystem filesystem("fs");
// Set up the button to trigger an erase
InterruptIn irq(BUTTON1);
DigitalOut rLED(LED_RED, LED_OFF);
int err = 0;
bool toggle = 0;
FILE *f;
void flipToggle() {
toggle = !toggle;
rLED = !rLED;
}
void erase() {
printf("Initializing the block device... ");
fflush(stdout);
int err = blockdevice->init();
printf("%s\n", (err ? "Fail :(" : "OK"));
if (err) {
error("error: %s (%d)\n", strerror(-err), err);
}
printf("Erasing the block device... ");
fflush(stdout);
err = blockdevice->erase(0, blockdevice->size());
printf("%s\n", (err ? "Fail :(" : "OK"));
if (err) {
error("error: %s (%d)\n", strerror(-err), err);
}
printf("Deinitializing the block device... ");
fflush(stdout);
err = blockdevice->deinit();
printf("%s\n", (err ? "Fail :(" : "OK"));
if (err) {
error("error: %s (%d)\n", strerror(-err), err);
}
}
void mountFS() {
printf("Mounting the filesystem... ");
fflush(stdout);
err = filesystem.mount(blockdevice);
printf("%s\n", (err ? "Fail :(" : "OK"));
if (err || FORCE_REFORMAT) {
// Reformat if we can't mount the filesystem
printf("formatting... ");
fflush(stdout);
err = filesystem.reformat(blockdevice);
printf("%s\n", (err ? "Fail :(" : "OK"));
if (err) {
error("error: %s (%d)\n", strerror(-err), err);
}
}
}
void openFile() {
printf("Opening \"/fs/numbers.txt\"... ");
fflush(stdout);
f = fopen("/fs/numbers.txt", "r+");
printf("%s\n", (!f ? "Fail :(" : "OK"));
if (!f) {
// Create the numbers file if it doesn't exist
printf("No file found, creating a new file... ");
fflush(stdout);
f = fopen("/fs/numbers.txt", "w+");
printf("%s\n", (!f ? "Fail :(" : "OK"));
if (!f) {
error("error: %s (%d)\n", strerror(errno), -errno);
}
for (int i = 0; i < 10; i++) {
printf("\rWriting numbers (%d/%d)... ", i, 10);
fflush(stdout);
err = fprintf(f, " %d\n", i);
if (err < 0) {
printf("Fail :(\n");
error("error: %s (%d)\n", strerror(errno), -errno);
}
}
printf("\rWriting numbers (%d/%d)... OK\n", 10, 10);
printf("Seeking file... ");
fflush(stdout);
err = fseek(f, 0, SEEK_SET);
printf("%s\n", (err < 0 ? "Fail :(" : "OK"));
if (err < 0) {
error("error: %s (%d)\n", strerror(errno), -errno);
}
}
}
void incrementNumbers() {
for (int i = 0; i < 10; i++) {
printf("\rIncrementing numbers (%d/%d)... ", i, 10);
fflush(stdout);
// Get current stream position
long pos = ftell(f);
// Parse out the number and increment
char buf[BUFFER_MAX_LEN];
if (!fgets(buf, BUFFER_MAX_LEN, f)) {
error("error: %s (%d)\n", strerror(errno), -errno);
}
char *endptr;
int32_t number = strtol(buf, &endptr, 10);
if ((errno == ERANGE) || // The number is too small/large
(endptr == buf) || // No character was read
(*endptr && *endptr != '\n') // The whole input was not converted
) {
continue;
}
number += 1;
// Seek to beginning of number
fseek(f, pos, SEEK_SET);
// Store number
fprintf(f, " %d\n", number);
// Flush between write and read on same file
fflush(f);
}
printf("\rIncrementing numbers (%d/%d)... OK\n", 10, 10);
}
void closeFile() {
printf("Closing \"/fs/numbers.txt\"... ");
fflush(stdout);
err = fclose(f);
printf("%s\n", (err < 0 ? "Fail :(" : "OK"));
if (err < 0) {
error("error: %s (%d)\n", strerror(errno), -errno);
}
}
void displayDir() {
printf("Opening the root directory... ");
fflush(stdout);
DIR *d = opendir("/fs/");
printf("%s\n", (!d ? "Fail :(" : "OK"));
if (!d) {
error("error: %s (%d)\n", strerror(errno), -errno);
}
printf("root directory:\n");
while (true) {
struct dirent *e = readdir(d);
if (!e) {
break;
}
printf(" %s\n", e->d_name);
}
printf("Closing the root directory... ");
fflush(stdout);
err = closedir(d);
printf("%s\n", (err < 0 ? "Fail :(" : "OK"));
if (err < 0) {
error("error: %s (%d)\n", strerror(errno), -errno);
}
}
void displayFContent() {
printf("Opening \"/fs/numbers.txt\"... ");
fflush(stdout);
f = fopen("/fs/numbers.txt", "r");
printf("%s\n", (!f ? "Fail :(" : "OK"));
if (!f) {
error("error: %s (%d)\n", strerror(errno), -errno);
}
printf("numbers:\n");
while (!feof(f)) {
int c = fgetc(f);
printf("%c", c);
}
printf("\rClosing \"/fs/numbers.txt\"... ");
fflush(stdout);
err = fclose(f);
printf("%s\n", (err < 0 ? "Fail :(" : "OK"));
if (err < 0) {
error("error: %s (%d)\n", strerror(errno), -errno);
}
}
void unmountFS() {
printf("Unmounting... ");
fflush(stdout);
err = filesystem.unmount();
printf("%s\n", (err < 0 ? "Fail :(" : "OK"));
if (err < 0) {
error("error: %s (%d)\n", strerror(-err), err);
}
}
static auto erase_event = mbed_event_queue()->make_user_allocated_event(erase);
// static auto erase_event = mbed_event_queue() ->
// make_user_allocated_event(flipToggle);
// Entry point for the example
int main() {
printf("--- Mbed OS filesystem example ---\n");
// Setup the erase event on button press, use the event queue
// to avoid running in interrupt context
irq.fall(std::ref(erase_event));
// Try to mount the filesystem
mountFS();
// Open the numbers file
openFile();
// Go through and increment the numbers
incrementNumbers();
// Close the file which also flushes any cached writes
closeFile();
// Display the root directory
displayDir();
// Display the numbers file
displayFContent();
// Tidy up
unmountFS();
printf("Mbed OS filesystem example done!\n");
ThisThread::sleep_for(10000ms);
while (1) {
printf("Toggle state: %d\n", toggle);
mountFS();
unmountFS();
ThisThread::sleep_for(10000ms);
}
}