diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1377554 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.swp diff --git a/README.md b/README.md index ec52ffc..3d86cf3 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,18 @@ # STM32SD -Enables reading and writing on SD card using SD card slot of the STM32 Board. + +## SD library for Arduino + +With an STM32 board with SD card slot availability, this library enables +reading and writing on SD card using SD card slot of a STM32 board (NUCLEO, DISCOVERY, ...). + +This library follow Arduin API. + +For more information about it, please visit: +http://www.arduino.cc/en/Reference/SD + +## Note + +The library is based on FatFs, a generic FAT file system module for small embedded systems. +[http://elm-chan.org/fsw/ff](http://elm-chan.org/fsw/ff/00index_e.html) + +The FatFs has been ported as Arduino library [here](https://github.com/stm32duino/FatFs). The STM32SD library depends on it. diff --git a/examples/CardInfo/CardInfo.ino b/examples/CardInfo/CardInfo.ino new file mode 100644 index 0000000..ec9936d --- /dev/null +++ b/examples/CardInfo/CardInfo.ino @@ -0,0 +1,86 @@ +/* + SD card test + + This example shows how use the utility libraries on which the' + SD library is based in order to get info about your SD card. + Very useful for testing a card when you're not sure whether its working or not. + + * SD card attached + + */ +// include the SD library: +#include + +Sd2Card card; +SdFatFs fatFs; + +void setup() +{ + bool disp = false; + // Open serial communications and wait for port to open: + Serial.begin(9600); + + while (!Serial); + Serial.print("\nInitializing SD card..."); + while(!card.init(SD_DETECT_PIN)) { + if (!disp) { + Serial.println("initialization failed. Is a card inserted?"); + disp = true; + } + delay(10); + } + + Serial.println("A card is present."); + + // print the type of card + Serial.print("\nCard type: "); + switch (card.type()) { + case SD_CARD_TYPE_SD1: + Serial.println("SD1"); + break; + case SD_CARD_TYPE_SD2: + Serial.println("SD2"); + break; + case SD_CARD_TYPE_SDHC: + Serial.println("SDHC"); + break; + default: + Serial.println("Unknown"); + } + + // Now we will try to open the 'volume'/'partition' - it should be FAT16 or FAT32 + if (!fatFs.init()) { + Serial.println("Could not find FAT16/FAT32 partition.\nMake sure you've formatted the card"); + return; + } + + // print the type and size of the first FAT-type volume + uint64_t volumesize; + Serial.print("\nVolume type is FAT"); + Serial.println(fatFs.fatType(), DEC); + Serial.println(); + + volumesize = fatFs.blocksPerCluster(); // clusters are collections of blocks + volumesize *= fatFs.clusterCount(); // we'll have a lot of clusters + volumesize *= 512; // SD card blocks are always 512 bytes + Serial.print("Volume size (bytes): "); + Serial.println(volumesize); + Serial.print("Volume size (Kbytes): "); + volumesize /= 1024; + Serial.println(volumesize); + Serial.print("Volume size (Mbytes): "); + volumesize /= 1024; + Serial.println(volumesize); + + + Serial.println("\nFiles found on the card (name, date and size in bytes): "); + File root = SD.openRoot(); + + // list all files in the card with date and size + root.ls(LS_R | LS_DATE | LS_SIZE); + Serial.println("###### End of the SD tests ######"); +} + +void loop(void) { + // do nothing +} diff --git a/examples/Datalogger/Datalogger.ino b/examples/Datalogger/Datalogger.ino new file mode 100644 index 0000000..d0e1f2b --- /dev/null +++ b/examples/Datalogger/Datalogger.ino @@ -0,0 +1,66 @@ +/* + SD card datalogger + + This example shows how to log data from three analog sensors + to an SD card using the SD library. + + The circuit: + * analog sensors on analog ins A0, A1, and A2 + * SD card + + */ + +#include + +uint32_t A[] = { A0, A1, A2}; + +void setup() +{ + // Open serial communications and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for Leonardo only + } + + Serial.print("Initializing SD card..."); + // see if the card is present and can be initialized: + while (SD.begin(SD_DETECT_PIN) != TRUE) + { + delay(10); + } + delay(100); + Serial.println("card initialized."); +} + +void loop() +{ + // make a string for assembling the data to log: + String dataString = ""; + + // read three sensors and append to the string: + for (int analogPin = 0; analogPin < 3; analogPin++) { + int sensor = analogRead(A[analogPin]); + dataString += String(sensor); + if (analogPin < 2) { + dataString += ","; + } + } + + // open the file. note that only one file can be open at a time, + // so you have to close this one before opening another. + File dataFile = SD.open("datalog.txt", FILE_WRITE); + + // if the file is available, write to it: + if (dataFile) { + dataFile.seek(dataFile.size()); + dataFile.println(dataString); + dataFile.close(); + // print to the serial port too: + Serial.println(dataString); + } + // if the file isn't open, pop up an error: + else { + Serial.println("error opening datalog.txt"); + } + delay(100); +} diff --git a/examples/DumpFile/DumpFile.ino b/examples/DumpFile/DumpFile.ino new file mode 100644 index 0000000..8353c20 --- /dev/null +++ b/examples/DumpFile/DumpFile.ino @@ -0,0 +1,54 @@ +/* + SD card file dump + + This example shows how to read a file from the SD card using the + SD library and send it over the serial port. + + The circuit: + * SD card attached + + This example code is in the public domain. + + */ + +#include + +void setup() +{ + // Open serial communications and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for Leonardo only + } + + + Serial.print("Initializing SD card..."); + // see if the card is present and can be initialized: + while (SD.begin(SD_DETECT_PIN) != TRUE) + { + delay(10); + } + delay(100); + Serial.println("card initialized."); + + // open the file. note that only one file can be open at a time, + // so you have to close this one before opening another. + File dataFile = SD.open("datalog.txt"); + + // if the file is available, write to it: + if (dataFile) { + while (dataFile.available()) { + Serial.write(dataFile.read()); + } + dataFile.close(); + } + // if the file isn't open, pop up an error: + else { + Serial.println("error opening datalog.txt"); + } + Serial.println("###### End of the SD tests ######"); +} + +void loop() +{ +} diff --git a/examples/Files/Files.ino b/examples/Files/Files.ino new file mode 100644 index 0000000..5858eea --- /dev/null +++ b/examples/Files/Files.ino @@ -0,0 +1,68 @@ +/* + SD card basic file example + + This example shows how to create and destroy an SD card file + The circuit: + * SD card attached + + This example code is in the public domain. + + */ +#include + +File myFile; + +void setup() +{ + // Open serial communications and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for Leonardo only + } + + + Serial.print("Initializing SD card..."); + + while (SD.begin(SD_DETECT_PIN) != TRUE) + { + delay(10); + } + Serial.println("initialization done."); + + if (SD.exists("example.txt")) { + Serial.println("example.txt exists."); + } + else { + Serial.println("example.txt doesn't exist."); + } + + // open a new file and immediately close it: + Serial.println("Creating example.txt..."); + myFile = SD.open("example.txt", FILE_WRITE); + myFile.close(); + + // Check to see if the file exists: + if (SD.exists("example.txt")) { + Serial.println("example.txt exists."); + } + else { + Serial.println("example.txt doesn't exist."); + } + + // delete the file: + Serial.println("Removing example.txt..."); + SD.remove("example.txt"); + + if (SD.exists("example.txt")) { + Serial.println("example.txt exists."); + } + else { + Serial.println("example.txt doesn't exist."); + } + Serial.println("###### End of the SD tests ######"); +} + +void loop() +{ + // nothing happens after setup finishes. +} diff --git a/examples/Full/Full.ino b/examples/Full/Full.ino new file mode 100644 index 0000000..3a864d3 --- /dev/null +++ b/examples/Full/Full.ino @@ -0,0 +1,237 @@ +#include + +#define COUNTOF(__BUFFER__) (sizeof(__BUFFER__) / sizeof(*(__BUFFER__))) +#define BUFFERSIZE (COUNTOF(wtext) -1) + +uint32_t file_size = 0, seek_val = FALSE, peek_val = 0; +uint32_t byteswritten, bytesread = 0; +/* File write buffer */ +uint8_t wtext[] = "This is the Arduino SD Test working with FatFs."; +/* File read buffer */ +uint8_t rtext[BUFFERSIZE]; +uint32_t i = 0; +uint8_t isdir = FALSE; +File MyFile; + +void setup() +{ + Serial.begin(9600); + while (!Serial); + + /* Test begin() method */ + while (SD.begin(SD_DETECT_PIN) != TRUE) + { + delay(10); + } + delay(100); + + /* Test mkdir() method */ + Serial.println("Creating 'STM32' directory"); + SD.mkdir("STM32"); + Serial.println("Creating 'ARDUINO' directory"); + SD.mkdir("ARDUINO"); + Serial.println("Creating 'ARDUINO/SD' directory"); + SD.mkdir("ARDUINO/SD"); + + /* Test open() method */ + Serial.println("Opening 'STM32/Toremove.txt' file"); + MyFile = SD.open("STM32/Toremove.txt", FILE_WRITE); + if(MyFile) { + Serial.println("Closing 'STM32/Toremove.txt' file"); + MyFile.close(); + } else { + Serial.println("Error to open 'STM32/Toremove.txt' file"); + } + Serial.println("Opening 'ARDUINO/SD/ARDUINO_SD_TEXT.txt' file"); + MyFile = SD.open("ARDUINO/SD/ARDUINO_SD_TEXT.txt", FILE_WRITE); + if(MyFile) { + /* Test print() method */ + Serial.print("writing \""); + Serial.print((const char*)wtext); + Serial.println("\" into ARDUINO_SD_TEXT.txt file"); + byteswritten = MyFile.print((const char*)wtext); + byteswritten += MyFile.print("\n"); + Serial.print(byteswritten, DEC); + Serial.println(" bytes written."); + Serial.println("Closing 'ARDUINO/SD/ARDUINO_SD_TEXT.txt' file"); + MyFile.close(); + } else { + Serial.println("Error to open 'ARDUINO/SD/ARDUINO_SD_TEXT.txt' file"); + } + + Serial.println("Opening 'ARDUINO/SD/ARDUINO_SD_TEXT.txt' file"); + MyFile = SD.open("ARDUINO/SD/ARDUINO_SD_TEXT.txt"); + if(MyFile) { + bytesread = MyFile.read(rtext, MyFile.size()); + Serial.println("Closing 'ARDUINO/SD/ARDUINO_SD_TEXT.txt' file"); + MyFile.close(); + } else { + Serial.println("Error to open 'ARDUINO/SD/ARDUINO_SD_TEXT.txt' file"); + } + + Serial.println("Opening 'ARDUINO/SD/TEXT.txt' file"); + MyFile = SD.open("ARDUINO/SD/TEXT.txt", FILE_WRITE); + if(MyFile) { + byteswritten = MyFile.print((const char*)rtext); + MyFile.flush(); + Serial.println("Closing 'ARDUINO/SD/TEXT.txt' file"); + MyFile.close(); + } else { + Serial.println("Error to open 'ARDUINO/SD/TEXT.txt' file"); + } + + Serial.println("Opening 'ARDUINO/SD/TEXT.txt' file"); + MyFile = SD.open("ARDUINO/SD/TEXT.txt"); + if(MyFile) { + /* Test size() method */ + file_size = MyFile.size(); + Serial.print("TEXT.txt size: "); + Serial.println(file_size); + + /* Test position and seek method */ + Serial.print("TEXT.txt position value: "); + Serial.println(MyFile.position()); + if(!MyFile.seek(MyFile.size()+1)) { + Serial.println("TEXT.txt seek value over size: OK"); + } else { + Serial.println("TEXT.txt seek value over size: KO"); + } + if(MyFile.seek(MyFile.size())) { + Serial.println("TEXT.txt seek value to size: OK"); + } else { + Serial.println("TEXT.txt seek value to size: KO"); + } + Serial.print("TEXT.txt position value: "); + Serial.println(MyFile.position()); + + if(MyFile.seek(0)) { + Serial.println("TEXT.txt seek value to 0: OK"); + } else { + Serial.println("TEXT.txt seek value to 0: KO"); + } + Serial.print("TEXT.txt position value: "); + Serial.println(MyFile.position()); + + /* Test peek() method */ + Serial.println("TEXT.txt peek (10 times): "); + for(i = 0; i<10; i++) + { + peek_val = MyFile.peek(); + Serial.print(peek_val); + Serial.print(" '"); + Serial.write(peek_val); + Serial.println("'"); + } + i = 0; + + /* Test available() and read() methods */ + Serial.println("TEXT.txt content read byte per byte: "); + while(MyFile.available()) + { + rtext[i] = (uint8_t)MyFile.read(); + Serial.print(rtext[i]); + Serial.print(" '"); + Serial.write(rtext[i]); + Serial.println("'"); + i++; + } + /* Test close method */ + Serial.println("Closing 'ARDUINO/SD/TEXT.txt' file"); + MyFile.close(); + } else { + Serial.println("Error to open 'ARDUINO/SD/TEXT.txt' file"); + } + + /* Test isDirectory() method */ + MyFile = File("STM32"); + if(MyFile) { + Serial.print("Is 'STM32' is a dir: "); + if (MyFile.isDirectory()) + Serial.println("OK"); + else + Serial.println("KO"); + } else { + Serial.println("Error to open 'STM32' dir"); + } + + Serial.println("Opening 'STM32/Toremove.txt' file"); + MyFile = SD.open("STM32/Toremove.txt"); + if(MyFile) { + Serial.print("Is 'STM32/Toremove.txt' is a file: "); + if (MyFile.isDirectory()) + Serial.println("KO"); + else + Serial.println("OK"); + Serial.println("Closing 'STM32/Toremove.txt' file"); + MyFile.close(); + } else { + Serial.println("Error to open 'STM32/Toremove.txt' file"); + } + /* Test exists(), remove() and rmdir() methods */ + Serial.print("Removing 'STM32/Toremove.txt' file..."); + while(SD.exists("STM32/Toremove.txt") == TRUE) + { + SD.remove("STM32/Toremove.txt"); + } + Serial.println("done"); + + Serial.print("Removing 'STM32' dir..."); + while(SD.exists("STM32") == TRUE) + { + SD.rmdir("STM32"); + } + Serial.println("done"); + + /* Test println(), println(data) methods */ + Serial.println("Opening 'ARDUINO/SD/PRINT.txt' file"); + MyFile = SD.open("ARDUINO/SD/PRINT.txt", FILE_WRITE); + if(MyFile) { + String str = String("This is a String object on line 7"); + Serial.print("Printing to 'ARDUINO/SD/PRINT.txt' file..."); + MyFile.println("This should be line 1"); + MyFile.println(); + MyFile.println("This should be line 3"); + MyFile.println("This should be line 4"); + MyFile.println(); + MyFile.println("This should be line 6"); + MyFile.println(str); + Serial.println("done"); + Serial.println("Closing 'ARDUINO/SD/PRINT.txt' file"); + MyFile.close(); + } else { + Serial.println("Error to open 'ARDUINO/SD/PRINT.txt' file"); + } + + /* Test write(buf, len) method */ + Serial.println("Opening 'ARDUINO/SD/WRITE.txt' file"); + MyFile = SD.open("ARDUINO/SD/WRITE.txt", FILE_WRITE); + if(MyFile) { + Serial.print("Writing 'ARDUINO/SD/WRITE.txt' file: "); + byteswritten = MyFile.write(wtext, BUFFERSIZE); + Serial.print(byteswritten); + Serial.println(" bytes written"); + Serial.println("Closing 'ARDUINO/SD/WRITE.txt' file"); + MyFile.close(); + } else { + Serial.println("Error to open 'ARDUINO/SD/WRITE.txt' file"); + } + + /* Test read(buf, len) method */ + Serial.println("Opening 'ARDUINO/SD/WRITE.txt' file"); + MyFile = SD.open("ARDUINO/SD/WRITE.txt"); + if(MyFile) { + Serial.println("Reading 'ARDUINO/SD/WRITE.txt' file:"); + bytesread = MyFile.read(rtext, MyFile.size()); + Serial.println((const char*)rtext); + Serial.println("Closing 'ARDUINO/SD/WRITE.txt' file"); + MyFile.close(); + } else { + Serial.println("Error to open 'ARDUINO/SD/WRITE.txt' file"); + } + Serial.println("###### End of the SD tests ######"); +} + +void loop() +{ + // do nothing +} diff --git a/examples/ReadWrite/ReadWrite.ino b/examples/ReadWrite/ReadWrite.ino new file mode 100644 index 0000000..688c40d --- /dev/null +++ b/examples/ReadWrite/ReadWrite.ino @@ -0,0 +1,69 @@ +/* + SD card read/write + + This example shows how to read and write data to and from an SD card file + The circuit: + * SD card attached + + This example code is in the public domain. + + */ + +#include + +File myFile; + +void setup() +{ + // Open serial communications and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for Leonardo only + } + + + Serial.print("Initializing SD card..."); + while (SD.begin(SD_DETECT_PIN) != TRUE) + { + delay(10); + } + Serial.println("initialization done."); + + // open the file. note that only one file can be open at a time, + // so you have to close this one before opening another. + myFile = SD.open("test.txt", FILE_WRITE); + + // if the file opened okay, write to it: + if (myFile) { + Serial.print("Writing to test.txt..."); + myFile.println("testing 1, 2, 3."); + // close the file: + myFile.close(); + Serial.println("done."); + } else { + // if the file didn't open, print an error: + Serial.println("error opening test.txt"); + } + + // re-open the file for reading: + myFile = SD.open("test.txt"); + if (myFile) { + Serial.println("test.txt:"); + + // read from the file until there's nothing else in it: + while (myFile.available()) { + Serial.write(myFile.read()); + } + // close the file: + myFile.close(); + } else { + // if the file didn't open, print an error: + Serial.println("error opening test.txt"); + } + Serial.println("###### End of the SD tests ######"); +} + +void loop() +{ + // nothing happens after setup +} diff --git a/examples/listfiles/listfiles.ino b/examples/listfiles/listfiles.ino new file mode 100644 index 0000000..9dedef2 --- /dev/null +++ b/examples/listfiles/listfiles.ino @@ -0,0 +1,76 @@ +/* + Listfiles + + This example shows how print out the files in a + directory on a SD card + + The circuit: + * SD card attached + + This example code is in the public domain. + + */ +#include + +File root; + +void setup() +{ + // Open serial communications and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for Serial port to connect. Needed for Leonardo only + } + + Serial.print("Initializing SD card..."); + while (SD.begin(SD_DETECT_PIN) != TRUE) + { + delay(10); + } + Serial.println("initialization done."); + + root = SD.open("/"); + if(root) + printDirectory(root, 0); + else + Serial.println("Could not open root"); + delay(2000); + Serial.println(); + Serial.println("Rewinding, and repeating below:" ); + Serial.println(); + delay(2000); + root.rewindDirectory(); + printDirectory(root, 0); + root.close(); + Serial.println("###### End of the SD tests ######"); +} + +void loop() +{ + // nothing happens after setup finishes. +} + +void printDirectory(File dir, int numTabs) { + while(true) { + File entry = dir.openNextFile(); + if (! entry) { + // no more files + break; + } + for (uint8_t i=0; i for STMicroelectronics + + This library provides four key benefits: + + * Including `STM32SD.h` automatically creates a global + `SD` object which can be interacted with in a similar + manner to other standard global objects like `Serial` and `Ethernet`. + + * Boilerplate initialisation code is contained in one method named + `begin` and no further objects need to be created in order to access + the SD card. + + * Calls to `open` can supply a full path name including parent + directories which simplifies interacting with files in subdirectories. + + * Utility methods are provided to determine whether a file exists + and to create a directory heirarchy. + + */ + +/* + + Implementation Notes + + In order to handle multi-directory path traversal, functionality that + requires this ability is implemented as callback functions. + + Individual methods call the `walkPath` function which performs the actual + directory traversal (swapping between two different directory/file handles + along the way) and at each level calls the supplied callback function. + + Some types of functionality will take an action at each level (e.g. exists + or make directory) which others will only take an action at the bottom + level (e.g. open). + + */ + +extern "C" { + #include + #include + #include + #include "stm32_def.h" +} +#include "assert.h" +#include "STM32SD.h" +SDClass SD; + +/** + * @brief Link SD, register the file system object to the FatFs mode and configure + * relatives SD IOs except SD Detect Pin + * @param None + * @retval TRUE or FALSE + */ +uint8_t SDClass::begin() +{ + /*##-1- Initializes SD IOs #############################################*/ + if (_card.init()) { + return _fatFs.init(); + } + else + { + return FALSE; + } +} + +/** + * @brief Link SD, register the file system object to the FatFs mode and configure + * relatives SD IOs including SD Detect Pin + * @param None + * @retval TRUE or FALSE + */ +uint8_t SDClass::begin(uint8_t cspin) +{ + /*##-1- Initializes SD IOs #############################################*/ + if (_card.init(cspin)) { + return _fatFs.init(); + } + else + { + return FALSE; + } +} + +/** + * @brief Check if a file or folder exist on the SD disk + * @param filename: File name + * @retval TRUE or FALSE + */ +uint8_t SDClass::exists(const char *filepath) +{ + FILINFO fno; + + if(f_stat(filepath, &fno) != FR_OK) + { + return FALSE; + } + else + { + return TRUE; + } +} + +/** + * @brief Create directory on the SD disk + * @param filename: File name + * @retval TRUE or FALSE + */ +uint8_t SDClass::mkdir(const char *filepath) +{ + if(f_mkdir(filepath) != FR_OK) + { + return FALSE; + } + else + { + return TRUE; + } +} + +/** + * @brief Remove directory on the SD disk + * @param filename: File name + * @retval TRUE or FALSE + */ +uint8_t SDClass::rmdir(const char *filepath) +{ + if(f_unlink(filepath) != FR_OK) + { + return FALSE; + } + else + { + return TRUE; + } +} + +/** + * @brief Open a file on the SD disk, if not existing it's created + * @param filename: File name + * @retval File object referring to the opened file + */ +File SDClass::open(const char *filepath) +{ + File file = File(filepath); + + if(f_open(&file._fil, filepath, FA_READ) != FR_OK) + { + f_opendir(&file._dir, filepath); + } + return file; +} + +/** + * @brief Open a file on the SD disk, if not existing it's created + * @param filename: File name + * @param mode: the mode in which to open the file + * @retval File object referring to the opened file + */ +File SDClass::open(const char *filepath, uint8_t mode) +{ + File file = File(filepath); + + if((mode == FILE_WRITE) && (SD.exists(filepath) != TRUE)) + { + mode = mode | FA_CREATE_ALWAYS; + } + + if(f_open(&file._fil, filepath, mode) != FR_OK) + { + f_opendir(&file._dir, filepath); + } + return file; +} + +/** + * @brief Remove a file on the SD disk + * @param filename: File name + * @retval TRUE or FALSE + */ +uint8_t SDClass::remove(const char *filepath) +{ + if(f_unlink(filepath) != FR_OK) + { + return FALSE; + } + else + { + return TRUE; + } +} + +File SDClass::openRoot(void) +{ + File file = File(_fatFs.getRoot()); + + if(f_opendir(&file._dir, _fatFs.getRoot()) != FR_OK) + { + file._dir.fs = 0; + } + return file; +} + +File::File() +{ + _name = NULL; + _fil.fs = 0; + _dir.fs = 0; +} + +File::File(const char* name) +{ + _name = (char*)malloc(strlen(name) +1); + assert(_name != NULL ); + sprintf(_name, "%s", name); + _fil.fs = 0; + _dir.fs = 0; +} + +/** List directory contents to Serial. + * + * \param[in] flags The inclusive OR of + * + * LS_DATE - %Print file modification date + * + * LS_SIZE - %Print file size. + * + * LS_R - Recursive list of subdirectories. + * + * \param[in] indent Amount of space before file name. Used for recursive + * list to indicate subdirectory level. + */ +void File::ls(uint8_t flags, uint8_t indent) { + FRESULT res = FR_OK; + FILINFO fno; + char *fn; + +#if _USE_LFN + static char lfn[_MAX_LFN]; + fno.lfname = lfn; + fno.lfsize = sizeof(lfn); +#endif + + while(1) + { + res = f_readdir(&_dir, &fno); + if(res != FR_OK || fno.fname[0] == 0) + { + break; + } + if(fno.fname[0] == '.') + { + continue; + } +#if _USE_LFN + fn = *fno.lfname ? fno.lfname : fno.fname; +#else + fn = fno.fname; +#endif + //print any indent spaces + for (int8_t i = 0; i < indent; i++) Serial.print(' '); + Serial.print(fn); + + if((fno.fattrib & AM_DIR) == 0) + { + // print modify date/time if requested + if (flags & LS_DATE) { + Serial.print(' '); + printFatDate(fno.fdate); + Serial.print(' '); + printFatTime(fno.ftime); + } + // print size if requested + if (flags & LS_SIZE) { + Serial.print(' '); + Serial.print(fno.fsize); + } + Serial.println(); + } + else + { + // list subdirectory content if requested + if (flags & LS_R) + { + char *fullPath; + fullPath = (char*)malloc(strlen(_name) + 1 + strlen(fn) +1); + if (fullPath != NULL) { + sprintf(fullPath, "%s/%s", _name, fn); + File filtmp = SD.open(fullPath); + + if (filtmp._name != NULL) { + Serial.println(); + filtmp.ls(flags, indent+2); + filtmp.close(); + } else { + Serial.println(fn); + Serial.print("Error to open dir: "); + Serial.println(fn); + } + free(fullPath); + } else { + Serial.println(); + Serial.print("Error to allocate memory!"); + } + } + } + } +} +//------------------------------------------------------------------------------ +/** %Print a directory date field to Serial. + * + * Format is yyyy-mm-dd. + * + * \param[in] fatDate The date field from a directory entry. + */ +void File::printFatDate(uint16_t fatDate) { + Serial.print(FAT_YEAR(fatDate)); + Serial.print('-'); + printTwoDigits(FAT_MONTH(fatDate)); + Serial.print('-'); + printTwoDigits(FAT_DAY(fatDate)); +} +//------------------------------------------------------------------------------ +/** %Print a directory time field to Serial. + * + * Format is hh:mm:ss. + * + * \param[in] fatTime The time field from a directory entry. + */ +void File::printFatTime(uint16_t fatTime) { + printTwoDigits(FAT_HOUR(fatTime)); + Serial.print(':'); + printTwoDigits(FAT_MINUTE(fatTime)); + Serial.print(':'); + printTwoDigits(FAT_SECOND(fatTime)); +} +//------------------------------------------------------------------------------ +/** %Print a value as two digits to Serial. + * + * \param[in] v Value to be printed, 0 <= \a v <= 99 + */ +void File::printTwoDigits(uint8_t v) { + char str[3]; + str[0] = '0' + v/10; + str[1] = '0' + v % 10; + str[2] = 0; + Serial.print(str); +} + +/** + * @brief Read byte from the file + * @retval Byte read + */ +int File::read() +{ + uint8_t byteread; + int8_t data; + f_read(&_fil, (void *)&data, 1, (UINT *)&byteread); + return data; +} + +/** + * @brief Read an amount of data from the file + * @param buf: an array to store the read data from the file + * @param len: the number of elements to read + * @retval Number of bytes read + */ +int File::read(void* buf, size_t len) +{ + uint8_t bytesread; + + f_read(&_fil, buf, len, (UINT *)&bytesread); + return bytesread; + +} + +/** + * @brief Close a file on the SD disk + * @param None + * @retval None + */ +void File::close() +{ + if(_name) + { + if(_fil.fs != 0) { + /* Flush the file before close */ + f_sync(&_fil); + + /* Close the file */ + f_close(&_fil); + } + + if(_dir.fs != 0) { + f_closedir(&_dir); + } + + free(_name); + } +} + + +/** + * @brief Ensures that any bytes written to the file are physically saved to the SD card + * @param None + * @retval None + */ +void File::flush() +{ + f_sync(&_fil); +} + +/** + * @brief Read a byte from the file without advancing to the next one + * @param None + * @retval read byte + */ +int File::peek() +{ + int data; + data = read(); + seek(position() -1); + return data; +} + +/** + * @brief Get the current position within the file + * @param None + * @retval position within file + */ +uint32_t File::position() +{ + uint32_t filepos = 0; + filepos = f_tell(&_fil); + return filepos; +} + +/** + * @brief Seek to a new position in the file + * @param pos: The position to which to seek + * @retval TRUE or FALSE + */ +uint8_t File::seek(uint32_t pos) +{ + if(pos > size()) + { + return FALSE; + } + else + { + if(f_lseek(&_fil, pos) != FR_OK) + { + return FALSE; + } + else + { + return TRUE; + } + } +} + +/** + * @brief Get the size of the file + * @param None + * @retval file's size + */ +uint32_t File::size() +{ + uint32_t file_size = 0; + + file_size = f_size(&_fil); + return(file_size); +} + +File::operator bool() { + return ((_name == NULL) || ((_fil.fs == 0) && (_dir.fs == 0))) ? FALSE : TRUE; +} +/** + * @brief Write data to the file + * @param data: Data to write to the file + * @retval Number of data written (1) + */ +size_t File::write(uint8_t data) +{ + return write(&data, 1); +} + +/** + * @brief Write an array of data to the file + * @param buf: an array of characters or bytes to write to the file + * @param len: the number of elements in buf + * @retval Number of data written + */ +size_t File::write(const char *buf, size_t size) +{ + size_t byteswritten; + f_write(&_fil, (const void *)buf, size, (UINT *)&byteswritten); + return byteswritten; +} + +size_t File::write(const uint8_t *buf, size_t size) +{ + return write((const char *)buf, size); +} + +/** + * @brief Print data to the file + * @param data: Data to write to the file + * @retval Number of data written (1) + */ +size_t File::print(const char* data) +{ + return write(data, strlen(data)); +} + +/** + * @brief Print data to the file + * @retval Number of data written (1) + */ +size_t File::println() +{ + return write("\r\n", 2); +} + +/** + * @brief Print data to the file + * @param data: Data to write to the file + * @retval Number of data written (1) + */ +size_t File::println(const char* data) +{ + size_t bytewritten = write(data, strlen(data)); + bytewritten += println(); + return bytewritten; +} + +/** + * @brief Print data to the file + * @param data: Data of type String to write to the file + * @retval Number of data written (1) + */ +size_t File::println(String& data) +{ + return println(data.c_str()); +} + +/** + * @brief Check if there are any bytes available for reading from the file + * @retval Number of bytes available + */ +int File::available() +{ + uint32_t n = size() - position(); + return n > 0x7FFF ? 0x7FFF : n; +} + + +char* File::name() +{ + char *name = strrchr(_name, '/'); + if (name && name[0] == '/') + name++; + return name; +} + +/** + * @brief Check if the file is directory or normal file + * @retval TRUE if directory else FALSE + */ +uint8_t File::isDirectory() +{ + FILINFO fno; + assert(_name != NULL ); + if (_dir.fs != 0) + return TRUE; + else if (_fil.fs != 0) + return FALSE; + // if not init get info + if (f_stat(_name, &fno) == FR_OK) + { + if(fno.fattrib & AM_DIR) + { + return TRUE; + } + else + { + return FALSE; + } + } +} + +File File::openNextFile(uint8_t mode) +{ + FRESULT res = FR_OK; + FILINFO fno; + char *fn; + char *fullPath = NULL; + size_t name_len= strlen(_name); + size_t len = name_len; +#if _USE_LFN + static char lfn[_MAX_LFN]; + fno.lfname = lfn; + fno.lfsize = sizeof(lfn); +#endif + while(1) + { + res = f_readdir(&_dir, &fno); + if(res != FR_OK || fno.fname[0] == 0) + { + return File(); + } + if(fno.fname[0] == '.') + { + continue; + } +#if _USE_LFN + fn = *fno.lfname ? fno.lfname : fno.fname; +#else + fn = fno.fname; +#endif + len += strlen(fn) +2; + fullPath = (char*)malloc(len); + if (fullPath != NULL) { + // Avoid twice '/' + if ((name_len > 0) && (_name[name_len-1] == '/')) + { + sprintf(fullPath, "%s%s", _name, fn); + } else { + sprintf(fullPath, "%s/%s", _name, fn); + } + File filtmp = SD.open(fullPath, mode); + free(fullPath); + return filtmp; + } else { + return File(); + } + } +} + +void File::rewindDirectory(void) +{ + if(isDirectory()) + { + if(_dir.fs != 0) { + f_closedir(&_dir); + } + f_opendir(&_dir, _name); + } +} + diff --git a/src/STM32SD.h b/src/STM32SD.h new file mode 100644 index 0000000..5960b0e --- /dev/null +++ b/src/STM32SD.h @@ -0,0 +1,102 @@ +/* + + SD - a slightly more friendly wrapper for sdfatlib + + This library aims to expose a subset of SD card functionality + in the form of a higher level "wrapper" object. + + License: GNU General Public License V3 + (Because sdfatlib is licensed with this.) + + (C) Copyright 2010 SparkFun Electronics + + Modified by Frederic Pillon for STMicroelectronics + + */ + +#ifndef __SD_H__ +#define __SD_H__ + +#include + +#include "Sd2Card.h" +#include "SdFatFs.h" + +// flags for ls() +/** ls() flag to print modify date */ +uint8_t const LS_DATE = 1; +/** ls() flag to print file size */ +uint8_t const LS_SIZE = 2; +/** ls() flag for recursive list of subdirectories */ +uint8_t const LS_R = 4; + +class File { +public: + File(void); + File(const char* name); + virtual size_t write(uint8_t); + virtual size_t write(const uint8_t *buf, size_t size); + virtual size_t write(const char *buf, size_t size); + + virtual int read(); + virtual int peek(); + virtual int available(); + virtual void flush(); + int read(void* buf, size_t len); + uint8_t seek(uint32_t pos); + uint32_t position(); + uint32_t size(); + void close(); + operator bool(); + + char* name(void); + char* fullname(void) {return _name;}; + uint8_t isDirectory(); + File openNextFile(uint8_t mode = FILE_READ); + void rewindDirectory(void); + + virtual size_t print(const char* data); + virtual size_t println(); + virtual size_t println(const char* data); + virtual size_t println(String& data); + + // Print to Serial line + void ls(uint8_t flags, uint8_t indent = 0); + static void printFatDate(uint16_t fatDate); + static void printFatTime(uint16_t fatTime); + static void printTwoDigits(uint8_t v); + + + char *_name = NULL; //file or dir name + FIL _fil = {}; // init all fields to 0 + DIR _dir = {}; // init all fields to 0 + +}; + +class SDClass { + +public: + + /* Initialize the SD peripheral */ + uint8_t begin(); + uint8_t begin(uint8_t cspin); + static File open(const char *filepath, uint8_t mode); + static File open(const char *filepath); + static uint8_t exists(const char *filepath); + static uint8_t mkdir(const char *filepath); + static uint8_t remove(const char *filepath); + static uint8_t rmdir(const char *filepath); + + File openRoot(void); + + friend class File; + +private: + Sd2Card _card; + SdFatFs _fatFs; + +}; + +extern SDClass SD; + +#endif diff --git a/src/Sd2Card.cpp b/src/Sd2Card.cpp new file mode 100644 index 0000000..be323b4 --- /dev/null +++ b/src/Sd2Card.cpp @@ -0,0 +1,100 @@ +/** + ****************************************************************************** + * @file Sd2Card.cpp + * @author Frederic Pillon for STMicroelectronics + * @date 2017 + * @brief + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2017 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +#include +#include "Sd2Card.h" + +uint8_t Sd2Card::init(void) { + if (BSP_SD_Init() == MSD_OK) { + BSP_SD_GetCardInfo(&_SdCardInfo); + return TRUE; + } else { + return FALSE; + } +} + +uint8_t Sd2Card::init(uint8_t cspin) { + if (BSP_SD_CSInit() == MSD_OK) { + BSP_SD_GetCardInfo(&_SdCardInfo); + return TRUE; + } else { + return FALSE; + } +} + +uint8_t Sd2Card::type(void) const { + uint8_t cardType = SD_CARD_TYPE_UKN; +#if defined (STM32F4xx) || defined(STM32F7xx) || defined(STM32L4xx) + switch (_SdCardInfo.CardType) { + case CARD_SDSC: + switch (_SdCardInfo.CardVersion) { + case CARD_V1_X: + cardType = SD_CARD_TYPE_SD1; + break; + case CARD_V2_X: + cardType = SD_CARD_TYPE_SD2; + break; + default: + cardType = SD_CARD_TYPE_UKN; + } + break; + case CARD_SDHC_SDXC: + cardType = SD_CARD_TYPE_SDHC; + break; + case CARD_SECURED: + cardType = SD_CARD_TYPE_SECURED; + break; + default: + cardType = SD_CARD_TYPE_UKN; + } +#else /* (STM32F1xx) || defined(STM32F2xx) || defined(STM32L1xx) */ + switch (_SdCardInfo.CardType) { + case STD_CAPACITY_SD_CARD_V1_1: + cardType = SD_CARD_TYPE_SD1; + break; + case STD_CAPACITY_SD_CARD_V2_0: + cardType = SD_CARD_TYPE_SD2; + break; + case HIGH_CAPACITY_SD_CARD: + cardType = SD_CARD_TYPE_SDHC; + break; + default: + cardType = SD_CARD_TYPE_UKN; + } +#endif + return cardType; +} + diff --git a/src/Sd2Card.h b/src/Sd2Card.h new file mode 100644 index 0000000..4c1116b --- /dev/null +++ b/src/Sd2Card.h @@ -0,0 +1,69 @@ +/** + ****************************************************************************** + * @file Sd2Card.h + * @author Frederic Pillon for STMicroelectronics + * @date 2017 + * @brief + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2017 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +#ifndef Sd2Card_h +#define Sd2Card_h + +#include "bsp_sd.h" + +#define FALSE ((uint8_t)0x00) +#define TRUE ((uint8_t)0x01) + +// card types to match Arduino definition +#define SD_CARD_TYPE_UKN 0 +/** Standard capacity V1 SD card */ +#define SD_CARD_TYPE_SD1 1 +/** Standard capacity V2 SD card */ +#define SD_CARD_TYPE_SD2 2 +/** High Capacity SD card */ +#define SD_CARD_TYPE_SDHC 3 +/** High Capacity SD card */ +#define SD_CARD_TYPE_SECURED 4 + +class Sd2Card { + public: + + uint8_t init(void); + uint8_t init(uint8_t cspin); + + /** Return the card type: SD V1, SD V2 or SDHC */ + uint8_t type(void) const; + +private: + SD_CardInfo _SdCardInfo; + +}; +#endif // sd2Card_h diff --git a/src/SdFatFs.cpp b/src/SdFatFs.cpp new file mode 100644 index 0000000..b2bf3bc --- /dev/null +++ b/src/SdFatFs.cpp @@ -0,0 +1,68 @@ +/** + ****************************************************************************** + * @file SdFatFs.cpp + * @author Frederic Pillon for STMicroelectronics + * @date 2017 + * @brief + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2017 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +#include +#include "SdFatFs.h" + +uint8_t SdFatFs::init(void) { + + /*##-1- Link the SD disk I/O driver ########################################*/ + if(FATFS_LinkDriver(&SD_Driver, _SDPath) == 0) + { + /*##-2- Register the file system object to the FatFs module ##############*/ + if(f_mount(&_SDFatFs, (TCHAR const*)_SDPath, 1) == FR_OK) + { + /* FatFs Initialization done */ + return TRUE; + } + } + return FALSE; +} + +uint8_t SdFatFs::fatType(void) +{ + switch (_SDFatFs.fs_type) + { + case FS_FAT12: + return 12; + case FS_FAT16: + return 16; + case FS_FAT32: + return 32; + default: + return 0; + } +} diff --git a/src/SdFatFs.h b/src/SdFatFs.h new file mode 100644 index 0000000..016ebb0 --- /dev/null +++ b/src/SdFatFs.h @@ -0,0 +1,94 @@ +/** + ****************************************************************************** + * @file SdFatFs.h + * @author Frederic Pillon for STMicroelectronics + * @date 2017 + * @brief + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2017 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +#ifndef SdFatFs_h +#define SdFatFs_h + +#include "Sd2Card.h" + +/* FatFs includes component */ +#include "FatFs.h" + +/* To match Arduino definition*/ +#define FILE_WRITE FA_WRITE +#define FILE_READ FA_READ + +/** year part of FAT directory date field */ +static inline uint16_t FAT_YEAR(uint16_t fatDate) { + return 1980 + (fatDate >> 9); +} +/** month part of FAT directory date field */ +static inline uint8_t FAT_MONTH(uint16_t fatDate) { + return (fatDate >> 5) & 0XF; +} +/** day part of FAT directory date field */ +static inline uint8_t FAT_DAY(uint16_t fatDate) { + return fatDate & 0X1F; +} + +/** hour part of FAT directory time field */ +static inline uint8_t FAT_HOUR(uint16_t fatTime) { + return fatTime >> 11; +} +/** minute part of FAT directory time field */ +static inline uint8_t FAT_MINUTE(uint16_t fatTime) { + return(fatTime >> 5) & 0X3F; +} +/** second part of FAT directory time field */ +static inline uint8_t FAT_SECOND(uint16_t fatTime) { + return 2*(fatTime & 0X1F); +} + +class SdFatFs { + public: + + uint8_t init(void); + + /** Return the FatFs type: 12, 16, 32 (0: unknown)*/ + uint8_t fatType(void); + + // inline functions that return volume info + /** \return The volume's cluster size in blocks. */ + uint8_t blocksPerCluster(void) const {return _SDFatFs.csize;} + /** \return The total number of clusters in the volume. */ + uint32_t clusterCount(void) const {return (_SDFatFs.n_fatent -2);} + + char* getRoot(void) { return _SDPath;}; +private: + FATFS _SDFatFs; /* File system object for SD disk logical drive */ + char _SDPath[4]; /* SD disk logical drive path */ +}; +#endif // sdFatFs_h diff --git a/src/bsp_sd.c b/src/bsp_sd.c new file mode 100644 index 0000000..f43adb3 --- /dev/null +++ b/src/bsp_sd.c @@ -0,0 +1,445 @@ + /** + ****************************************************************************** + * @file bsp_sd.c + * @author MCD Application Team + * @version V1.0.0 + * @date 10-June-2016 + * @brief This file includes the uSD card driver mounted on stm32 + * board. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* File Info : ----------------------------------------------------------------- + User NOTES +1. How To use this driver: +-------------------------- + - This driver is used to drive the micro SD external card mounted on a board. + - This driver does not need a specific component driver for the micro SD device + to be included with. + +2. Driver description: +--------------------- + + Initialization steps: + o Initialize the micro SD card using the BSP_SD_Init() function. This + function includes the MSP layer hardware resources initialization and the + SDIO interface configuration to interface with the external micro SD. It + also includes the micro SD initialization sequence. + o To check the SD card presence you can use the function BSP_SD_IsDetected() which + returns the detection status + o If SD presence detection interrupt mode is desired, you must configure the + SD detection interrupt mode by calling the function BSP_SD_ITConfig(). The interrupt + is generated as an external interrupt whenever the micro SD card is + plugged/unplugged in/from the board. The SD detection interrupt + is handled by calling the function BSP_SD_DetectIT() which is called in the IRQ + handler file, the user callback is implemented in the function BSP_SD_DetectCallback(). + o The function BSP_SD_GetCardInfo() is used to get the micro SD card information + which is stored in the structure "HAL_SD_CardInfoTypedef". + + + Micro SD card operations + o The micro SD card can be accessed with read/write block(s) operations once + it is reay for access. The access cand be performed whether using the polling + mode by calling the functions BSP_SD_ReadBlocks()/BSP_SD_WriteBlocks(), or by DMA + transfer using the functions BSP_SD_ReadBlocks_DMA()/BSP_SD_WriteBlocks_DMA() + o The DMA transfer complete is used with interrupt mode. Once the SD transfer + is complete, the SD interrupt is handeled using the function BSP_SD_IRQHandler(), + the DMA Tx/Rx transfer complete are handeled using the functions + BSP_SD_DMA_Tx_IRQHandler()/BSP_SD_DMA_Rx_IRQHandler(). The corresponding user callbacks + are implemented by the user at application level. + o The SD erase block(s) is performed using the function BSP_SD_Erase() with specifying + the number of blocks to erase. + o The SD runtime status is returned when calling the function BSP_SD_GetStatus(). + +------------------------------------------------------------------------------*/ + +/* Includes ------------------------------------------------------------------*/ +#include "bsp_sd.h" + +/* BSP SD Private Variables */ +static SD_HandleTypeDef uSdHandle; +#if defined (STM32F4xx) || defined(STM32F7xx) || defined(STM32L4xx) +#define SD_OK HAL_OK +#define SD_TRANSFER_OK ((uint8_t)0x00) +#define SD_TRANSFER_BUSY ((uint8_t)0x01) +#else /* (STM32F1xx) || defined(STM32F2xx) || defined(STM32L1xx) */ +static SD_CardInfo uSdCardInfo; +#endif + + +/** + * @brief Initializes the SD card device without CS initialization. + * @retval SD status + */ +uint8_t BSP_SD_Init(void) +{ + uint8_t sd_state = MSD_OK; + + /* PLLSAI is dedicated to LCD periph. Do not use it to get 48MHz*/ + + /* uSD device interface configuration */ + uSdHandle.Instance = SD_INSTANCE; + + uSdHandle.Init.ClockEdge = SD_CLK_EDGE; + uSdHandle.Init.ClockBypass = SD_CLK_BYPASS; + uSdHandle.Init.ClockPowerSave = SD_CLK_PWR_SAVE; + uSdHandle.Init.BusWide = SD_BUS_WIDE_1B; + uSdHandle.Init.HardwareFlowControl = SD_HW_FLOW_CTRL; + uSdHandle.Init.ClockDiv = SD_CLK_DIV; + + /* Msp SD initialization */ + BSP_SD_MspInit(&uSdHandle, NULL); + + /* HAL SD initialization */ +#if defined (STM32F4xx) || defined(STM32F7xx) || defined(STM32L4xx) + if(HAL_SD_Init(&uSdHandle) != SD_OK) +#else /* (STM32F1xx) || defined(STM32F2xx) || defined(STM32L1xx) */ + if(HAL_SD_Init(&uSdHandle, &uSdCardInfo) != SD_OK) +#endif + { + sd_state = MSD_ERROR; + } + + /* Configure SD Bus width */ + if(sd_state == MSD_OK) + { + /* Enable wide operation */ + if(HAL_SD_WideBusOperation_Config(&uSdHandle, SD_BUS_WIDE_4B) != SD_OK) + { + sd_state = MSD_ERROR; + } + else + { + sd_state = MSD_OK; + } + } + return sd_state; +} + +/** + * @brief Initializes the SD card device with CS initialization. + * @retval SD status + */ +uint8_t BSP_SD_CSInit(void) +{ + uint8_t sd_state = MSD_OK; + + /* PLLSAI is dedicated to LCD periph. Do not use it to get 48MHz*/ + + /* uSD device interface configuration */ + uSdHandle.Instance = SD_INSTANCE; + + uSdHandle.Init.ClockEdge = SD_CLK_EDGE; + uSdHandle.Init.ClockBypass = SD_CLK_BYPASS; + uSdHandle.Init.ClockPowerSave = SD_CLK_PWR_SAVE; + uSdHandle.Init.BusWide = SD_BUS_WIDE_1B; + uSdHandle.Init.HardwareFlowControl = SD_HW_FLOW_CTRL; + uSdHandle.Init.ClockDiv = SD_CLK_DIV; + + /* Msp SD Detect pin initialization */ + BSP_SD_Detect_MspInit(&uSdHandle, NULL); + if(BSP_SD_IsDetected() != SD_PRESENT) /* Check if SD card is present */ + { + return MSD_ERROR_SD_NOT_PRESENT; + } + + /* Msp SD initialization */ + BSP_SD_MspInit(&uSdHandle, NULL); + + /* HAL SD initialization */ +#if defined (STM32F4xx) || defined(STM32F7xx) || defined(STM32L4xx) + if(HAL_SD_Init(&uSdHandle) != SD_OK) +#else /* (STM32F1xx) || defined(STM32F2xx) || defined(STM32L1xx) */ + if(HAL_SD_Init(&uSdHandle, &uSdCardInfo) != SD_OK) +#endif + { + sd_state = MSD_ERROR; + } + + /* Configure SD Bus width */ + if(sd_state == MSD_OK) + { + /* Enable wide operation */ + if(HAL_SD_WideBusOperation_Config(&uSdHandle, SD_BUS_WIDE_4B) != SD_OK) + { + sd_state = MSD_ERROR; + } + else + { + sd_state = MSD_OK; + } + } + return sd_state; +} + +/** + * @brief DeInitializes the SD card device. + * @retval SD status + */ +uint8_t BSP_SD_DeInit(void) +{ + uint8_t sd_state = MSD_OK; + + uSdHandle.Instance = SD_INSTANCE; + + /* HAL SD deinitialization */ + if(HAL_SD_DeInit(&uSdHandle) != HAL_OK) + { + sd_state = MSD_ERROR; + } + + /* Msp SD deinitialization */ + uSdHandle.Instance = SD_INSTANCE; + BSP_SD_MspDeInit(&uSdHandle, NULL); + + return sd_state; +} + +/** + * @brief Configures Interrupt mode for SD detection pin. + * @retval Returns 0 + */ +uint8_t BSP_SD_ITConfig(void) +{ + GPIO_InitTypeDef gpio_init_structure; + + /* Configure Interrupt mode for SD detection pin */ + gpio_init_structure.Pin = SD_DETECT_PIN; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_FAST; + gpio_init_structure.Mode = GPIO_MODE_IT_RISING_FALLING; + HAL_GPIO_Init(SD_DETECT_GPIO_PORT, &gpio_init_structure); + + /* Enable and set SD detect EXTI Interrupt to the lowest priority */ + HAL_NVIC_SetPriority((IRQn_Type)(SD_DETECT_EXTI_IRQn), 0x0F, 0x00); + HAL_NVIC_EnableIRQ((IRQn_Type)(SD_DETECT_EXTI_IRQn)); + + return MSD_OK; +} + +/** + * @brief Detects if SD card is correctly plugged in the memory slot or not. + * @retval Returns if SD is detected or not + */ +uint8_t BSP_SD_IsDetected(void) +{ + uint8_t status = SD_PRESENT; + + /* Check SD card detect pin */ + if (HAL_GPIO_ReadPin(SD_DETECT_GPIO_PORT, SD_DETECT_PIN) == GPIO_PIN_SET) + { + status = SD_NOT_PRESENT; + } + + return status; +} + +/** + * @brief Reads block(s) from a specified address in an SD card, in polling mode. + * @param pData: Pointer to the buffer that will contain the data to transmit + * @param ReadAddr: Address from where data is to be read + * @param BlockSize: SD card data block size, that should be 512 + * @param NumOfBlocks: Number of SD blocks to read + * @retval SD status + */ +uint8_t BSP_SD_ReadBlocks(uint32_t *pData, uint64_t ReadAddr, uint32_t BlockSize, uint32_t NumOfBlocks) +{ + if(HAL_SD_ReadBlocks(&uSdHandle, pData, ReadAddr, BlockSize, NumOfBlocks) != SD_OK) + { + return MSD_ERROR; + } + else + { + return MSD_OK; + } +} + +/** + * @brief Writes block(s) to a specified address in an SD card, in polling mode. + * @param pData: Pointer to the buffer that will contain the data to transmit + * @param WriteAddr: Address from where data is to be written + * @param BlockSize: SD card data block size, that should be 512 + * @param NumOfBlocks: Number of SD blocks to write + * @retval SD status + */ +uint8_t BSP_SD_WriteBlocks(uint32_t *pData, uint64_t WriteAddr, uint32_t BlockSize, uint32_t NumOfBlocks) +{ + if(HAL_SD_WriteBlocks(&uSdHandle, pData, WriteAddr, BlockSize, NumOfBlocks) != SD_OK) + { + return MSD_ERROR; + } + else + { + return MSD_OK; + } +} + +/** + * @brief Erases the specified memory area of the given SD card. + * @param StartAddr: Start byte address + * @param EndAddr: End byte address + * @retval SD status + */ +uint8_t BSP_SD_Erase(uint64_t StartAddr, uint64_t EndAddr) +{ + if(HAL_SD_Erase(&uSdHandle, StartAddr, EndAddr) != SD_OK) + { + return MSD_ERROR; + } + else + { + return MSD_OK; + } +} + +/** + * @brief Initializes the SD MSP. + * @param hsd: SD handle + * @param Params : pointer on additional configuration parameters, can be NULL. + */ +__weak void BSP_SD_MspInit(SD_HandleTypeDef *hsd, void *Params) +{ + GPIO_InitTypeDef gpio_init_structure; + + /* Enable SDIO clock */ + SD_CLK_ENABLE(); + + /* Enable GPIOs clock */ + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOD_CLK_ENABLE(); + + /* Common GPIO configuration */ + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + gpio_init_structure.Alternate = SD_AF; + + /* GPIOC configuration */ + gpio_init_structure.Pin = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12; + + HAL_GPIO_Init(GPIOC, &gpio_init_structure); + + /* GPIOD configuration */ + gpio_init_structure.Pin = GPIO_PIN_2; + HAL_GPIO_Init(GPIOD, &gpio_init_structure); + +} + +/** + * @brief Initializes the SD Detect pin MSP. + * @param hsd: SD handle + * @param Params : pointer on additional configuration parameters, can be NULL. + */ +__weak void BSP_SD_Detect_MspInit(SD_HandleTypeDef *hsd, void *Params) +{ + GPIO_InitTypeDef gpio_init_structure; + + SD_DETECT_GPIO_CLK_ENABLE(); + + /* GPIO configuration in input for uSD_Detect signal */ + gpio_init_structure.Pin = SD_DETECT_PIN; + gpio_init_structure.Mode = GPIO_MODE_INPUT; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + HAL_GPIO_Init(SD_DETECT_GPIO_PORT, &gpio_init_structure); +} + +/** + * @brief DeInitializes the SD MSP. + * @param hsd: SD handle + * @param Params : pointer on additional configuration parameters, can be NULL. + */ +__weak void BSP_SD_MspDeInit(SD_HandleTypeDef *hsd, void *Params) +{ + /* Disable NVIC for SDIO interrupts */ + HAL_NVIC_DisableIRQ(SDIO_IRQn); + + /* DeInit GPIO pins can be done in the application + (by surcharging this __weak function) */ + + /* Disable SDIO clock */ + __HAL_RCC_SDIO_CLK_DISABLE(); + + /* GPOI pins clock and DMA cloks can be shut down in the applic + by surcgarging this __weak function */ +} + +#if defined (STM32F4xx) || defined(STM32F7xx) || defined(STM32L4xx) +/** + * @brief Gets the current SD card data status. + * @retval Data transfer state. + * This value can be one of the following values: + * @arg SD_TRANSFER_OK: No data transfer is acting + * @arg SD_TRANSFER_BUSY: Data transfer is acting + */ +uint8_t BSP_SD_GetCardState(void) +{ + return((HAL_SD_GetCardState(&uSdHandle) == HAL_SD_CARD_TRANSFER ) ? SD_TRANSFER_OK : SD_TRANSFER_BUSY); +} +#else /* (STM32F1xx) || defined(STM32F2xx) || defined(STM32L1xx) */ +/** + * @brief Gets the current SD card data status. + * @retval Data transfer state. + * This value can be one of the following values: + * @arg SD_TRANSFER_OK: No data transfer is acting + * @arg SD_TRANSFER_BUSY: Data transfer is acting + * @arg SD_TRANSFER_ERROR: Data transfer error + */ +HAL_SD_TransferStateTypedef BSP_SD_GetStatus(void) +{ + return(HAL_SD_GetStatus(&uSdHandle)); +} +#endif + +/** + * @brief Get SD information about specific SD card. + * @param CardInfo: Pointer to HAL_SD_CardInfoTypedef structure + */ +void BSP_SD_GetCardInfo(HAL_SD_CardInfoTypeDef *CardInfo) +{ + /* Get SD card Information */ + HAL_SD_Get_CardInfo(&uSdHandle, CardInfo); +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/bsp_sd.h b/src/bsp_sd.h new file mode 100644 index 0000000..d20e607 --- /dev/null +++ b/src/bsp_sd.h @@ -0,0 +1,97 @@ +/** + ****************************************************************************** + * @file sd_conf.h + * @author fpiSTM + * @date 2017 + * @brief This file contains the common defines and functions prototypes for + * the bdp_sd.c driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __BSP_SD_H +#define __BSP_SD_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "sd_conf.h" + +/*SD Card information structure */ +#if defined (STM32F4xx) || defined(STM32F7xx) || defined(STM32L4xx) +#define HAL_SD_CardInfoTypedef HAL_SD_CardInfoTypeDef +#define BSP_SD_CardInfo HAL_SD_CardInfoTypeDef +#define HAL_SD_WideBusOperation_Config HAL_SD_ConfigWideBusOperation +#define HAL_SD_Get_CardInfo HAL_SD_GetCardInfo +#endif + +#define SD_CardInfo HAL_SD_CardInfoTypedef + +/*SD status structure definition */ +#define MSD_OK ((uint8_t)0x00) +#define MSD_ERROR ((uint8_t)0x01) +#define MSD_ERROR_SD_NOT_PRESENT ((uint8_t)0x02) + +/* SD Exported Constants */ +#define SD_PRESENT ((uint8_t)0x01) +#define SD_NOT_PRESENT ((uint8_t)0x00) + +/* SD Exported Functions */ +uint8_t BSP_SD_Init(void); +uint8_t BSP_SD_CSInit(void); +uint8_t BSP_SD_DeInit(void); +uint8_t BSP_SD_ITConfig(void); + +uint8_t BSP_SD_ReadBlocks(uint32_t *pData, uint64_t ReadAddr, uint32_t BlockSize, uint32_t NumOfBlocks); +uint8_t BSP_SD_WriteBlocks(uint32_t *pData, uint64_t WriteAddr, uint32_t BlockSize, uint32_t NumOfBlocks); +uint8_t BSP_SD_Erase(uint64_t StartAddr, uint64_t EndAddr); +#if defined (STM32F4xx) || defined(STM32F7xx) || defined(STM32L4xx) +uint8_t BSP_SD_GetCardState(void); +#else /* (STM32F1xx) || defined(STM32F2xx) || defined(STM32L1xx) */ +HAL_SD_TransferStateTypedef BSP_SD_GetStatus(void); +#endif +void BSP_SD_GetCardInfo(HAL_SD_CardInfoTypedef *CardInfo); +uint8_t BSP_SD_IsDetected(void); + +/* These __weak function can be surcharged by application code in case the current settings (e.g. DMA stream) + need to be changed for specific needs */ +void BSP_SD_MspInit(SD_HandleTypeDef *hsd, void *Params); +void BSP_SD_Detect_MspInit(SD_HandleTypeDef *hsd, void *Params); +void BSP_SD_MspDeInit(SD_HandleTypeDef *hsd, void *Params); + +#ifdef __cplusplus +} +#endif + +#endif /* __BSP_SD_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/