|
- /* Optimized SD Library for Teensy 3.X
- * Copyright (c) 2015, Paul Stoffregen, paul@pjrc.com
- *
- * Development of this SD library was funded by PJRC.COM, LLC by sales of
- * Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
- * open source software by purchasing genuine Teensy or other PJRC products.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice, development funding notice, and this permission
- * notice shall be included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
- // This Teensy 3.x optimized version is a work-in-progress.
- //
- // Uncomment this line to use the Teensy version, which completely replaces
- // all of the normal Arduino SD library code. The optimized version is
- // currently read-only. It CAN NOT WRITE ANYTHING TO YOUR SD CARD. However,
- // it is *much* faster for reading more than 1 file at a time, especially for
- // the Teensy Audio Library to play and mix multiple sound files.
- // On Teensy 3.5 & 3.6, this optimization does NOT SUPPORT the built-in SD
- // sockets. It only works with SD cards connected to the SPI pins.
- //
- //#define USE_TEENSY3_OPTIMIZED_CODE
-
- /* Why reinvent the SD library wheel...
- * 1: Allow reading files from within interrupts
- * 2: Cache more than one sector for improved performance
- * 3: General optimization for 32 bit ARM on Teensy 3.x & Teensy-LC
- * 4: Permissive MIT license
- */
-
- #if !defined(__SD_t3_H__) && defined(__arm__) && defined(USE_TEENSY3_OPTIMIZED_CODE)
- #define __SD_t3_H__
- #define __SD_H__
-
- #include <Arduino.h>
- #include <SPI.h>
- #include "utility/ioreg.h"
-
- #define SD_CACHE_SIZE 7 // each cache entry uses 520 bytes of RAM
-
- #define SD_SPI_SPEED SPISettings(25000000, MSBFIRST, SPI_MODE0)
-
- #define FILE_READ 0
- #define FILE_WRITE 1
- #define FILE_DIR 2
- #define FILE_DIR_ROOT16 3
- #define FILE_INVALID 4
-
- class File;
-
- class SDClass
- {
- public:
- static bool begin(uint8_t csPin = SS);
- static File open(const char *path, uint8_t mode = FILE_READ);
- static bool exists(const char *path);
- static bool mkdir(const char *path);
- static bool remove(const char *path);
- static bool rmdir(const char *path);
- private:
- static uint8_t sd_cmd0();
- static uint32_t sd_cmd8();
- static uint8_t sd_acmd41(uint32_t hcs);
- static uint32_t sd_cmd58();
- static bool sd_read(uint32_t addr, void * data);
- static void send_cmd(uint16_t cmd, uint32_t arg);
- static uint8_t recv_r1();
- static uint32_t recv_r3_or_r7();
- static void end_cmd();
- static volatile IO_REG_TYPE * csreg;
- static IO_REG_TYPE csmask;
- static uint8_t card_type; // 1=SDv1, 2=SDv2, 3=SDHC
- static File rootDir;
- static uint32_t fat1_begin_lba;
- static uint32_t fat2_begin_lba;
- static uint32_t data_begin_lba;
- static uint32_t max_cluster;
- static uint8_t sector2cluster;
- static uint8_t fat_type;
- friend class SDCache;
- friend class File;
- typedef struct {
- union {
- struct { // short 8.3 filename info
- char name[11];
- uint8_t attrib;
- uint8_t reserved;
- uint8_t ctime_tenth;
- uint16_t ctime;
- uint16_t cdate;
- uint16_t adate;
- uint16_t cluster_high;
- uint16_t wtime;
- uint16_t wdate;
- uint16_t cluster_low;
- uint32_t size;
- };
- struct { // long filename info
- uint8_t ord;
- uint8_t lname1[10];
- uint8_t lattrib;
- uint8_t type;
- uint8_t cksum;
- uint8_t lname2[12];
- uint16_t lcluster_low;
- uint8_t lname3[4];
- };
- };
- } fatdir_t;
- typedef union {
- uint8_t u8[512];
- uint16_t u16[256];
- uint32_t u32[128];
- fatdir_t dir[16];
- } sector_t;
- };
-
-
- #define ATTR_READ_ONLY 0x01
- #define ATTR_HIDDEN 0x02
- #define ATTR_SYSTEM 0x04
- #define ATTR_VOLUME_ID 0x08
- #define ATTR_DIRECTORY 0x10
- #define ATTR_ARCHIVE 0x20
- #define ATTR_LONG_NAME 0x0F
-
- class File : public Stream
- {
- public:
- File();
- ~File();
- // TODO: copy constructors, needs to be ISR safe
- virtual size_t write(uint8_t b);
- virtual size_t write(const uint8_t *buf, size_t size);
- virtual int read();
- virtual int peek();
- virtual int available();
- virtual void flush();
- int read(void *buf, uint32_t size);
- bool seek(uint32_t pos);
- uint32_t position() {
- if (type <= FILE_WRITE) return offset;
- return 0;
- }
- uint32_t size() {
- if (type <= FILE_WRITE) return length;
- return 0;
- }
- void close();
- operator bool() {
- return (type < FILE_INVALID);
- }
- char * name() {
- return namestr;
- }
- bool isDirectory() {
- return (type == FILE_DIR) || (type == FILE_DIR_ROOT16);
- }
- File openNextFile(uint8_t mode = FILE_READ);
- void rewindDirectory() {
- rewind();
- }
- using Print::write;
- void rewind() {
- offset = 0;
- current_cluster = start_cluster;
- };
- private:
- bool find(const char *filename, File *found);
- void init(SDClass::fatdir_t *dirent);
- bool next_cluster();
- uint32_t offset; // position within file (EOF = length)
- uint32_t length; // total size of file
- uint32_t start_cluster; // first cluster for the file
- uint32_t current_cluster; // position (must agree w/ offset)
- uint32_t dirent_lba; // dir sector for this file
- uint8_t dirent_index; // dir index within sector (0 to 15)
- uint8_t type; // file vs dir
- char namestr[13];
- friend class SDClass;
- static inline uint32_t cluster_number(uint32_t n) {
- return n >> (SDClass::sector2cluster + 9);
- }
- static inline uint32_t cluster_offset(uint32_t n) {
- return n & ((1 << (SDClass::sector2cluster + 9)) - 1);
- }
- static inline uint32_t custer_to_sector(uint32_t n) {
- return (n - 2) * (1 << SDClass::sector2cluster)
- + SDClass::data_begin_lba;
- }
- static inline bool is_new_cluster(uint32_t lba) {
- return (lba & ((1 << SDClass::sector2cluster) - 1)) == 0;
- }
- };
-
- class SDCache
- {
- private:
- // SDCache objects should be created with local scope.
- // read(), get(), alloc() acquire temporary locks on
- // cache buffers, which are automatically released
- // by the destructor when the object goes out of scope.
- // Pointers returned by those functions must NEVER be
- // used after the SDCache object which returned them
- // no longer exists.
- SDCache(void) { item = NULL; }
- ~SDCache(void) { release(); }
- typedef struct cache_struct {
- SDClass::sector_t data;
- uint32_t lba;
- cache_struct * next;
- uint8_t usagecount;
- uint8_t flags;
- } cache_t;
- SDClass::sector_t * read(uint32_t lba, bool is_fat=false);
- bool read(uint32_t lba, void *buffer);
- cache_t * get(uint32_t lba, bool allocate=true);
- void dirty(void);
- void flush(void);
- void release(void);
- cache_t * item;
- static cache_t *cache_list;
- static cache_t cache[SD_CACHE_SIZE];
- static void init(void);
- static void print_cache(void);
- friend class SDClass;
- friend class File;
- };
-
-
- extern SDClass SD;
-
- #endif
|