|
- /* 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.
- */
-
- #if defined(__arm__)
- #include "SD_t3.h"
- #ifdef USE_TEENSY3_OPTIMIZED_CODE
-
- uint8_t SDClass::fat_type;
- uint32_t SDClass::fat1_begin_lba;
- uint32_t SDClass::fat2_begin_lba;
- uint32_t SDClass::data_begin_lba;
- uint32_t SDClass::max_cluster;
- uint8_t SDClass::sector2cluster;
- File SDClass::rootDir;
-
- static uint32_t unaligned_read32_align16(const void *p)
- {
- #ifdef KINETISK
- return *(const uint32_t *)p;
- #else
- return *(const uint16_t *)p | (*(const uint16_t *)(p+1) << 16);
- #endif
- }
-
- static uint32_t unaligned_read16_align8(const void *p)
- {
- #ifdef KINETISK
- return *(const uint16_t *)p;
- #else
- return *(const uint8_t *)p | (*(const uint8_t *)(p+1) << 8);
- #endif
- }
-
- #define BPB_BytsPerSec 11 // 2 bytes
- #define BPB_SecPerClus 13 // 1 byte
- #define BPB_NumFATs 16 // 1 byte
- #define BPB_RootEntCnt 17 // 1 byte
- #define BPB_TotSec16 19 // 2 bytes
- #define BPB_FATSz16 22 // 2 bytes
- #define BPB_TotSec32 32 // 4 bytes
- #define BPB_FATSz32 36 // 4 bytes
- #define BPB_RootClus 44 // 4 bytes
-
- bool SDClass::begin(uint8_t csPin)
- {
- uint8_t status;
- uint32_t cond, hcs, ocr;
-
- // set up the SPI hardware
- csreg = PIN_TO_BASEREG(csPin);
- csmask = PIN_TO_BITMASK(csPin);
- pinMode(csPin, OUTPUT);
- DIRECT_WRITE_HIGH(csreg, csmask);
- SPI.begin();
- // send clocks to initialize hardware
- SPI.beginTransaction(SD_SPI_SPEED);
- for (uint8_t i=0; i < 5; i++) SPI.transfer16(0xFFFF);
- // put the card into idle state
- elapsedMillis msec = 0;
- while (1) {
- status = sd_cmd0();
- //Serial.print("cmd0=");
- //Serial.println(status);
- if (status == 1) break;
- SPI.endTransaction();
- if (msec > 250) return false;
- SPI.beginTransaction(SD_SPI_SPEED);
- }
- // detect version 1 vs 2 cards
- cond = sd_cmd8();
- if (cond == 0x80000000) {
- // version 1 card
- card_type = 1;
- hcs = 0;
- } else if (cond == 0x1AA) {
- // version 2 card
- card_type = 2;
- hcs = (1<<30);
- } else {
- SPI.endTransaction();
- return false;
- }
- //Serial.println();
- // wait for the card to be ready
- msec = 0;
- while (1) {
- status = sd_acmd41(hcs);
- //Serial.println();
- if (status == 0) break;
- SPI.endTransaction();
- if (status > 1) return false;
- if (msec > 1500) return false;
- SPI.beginTransaction(SD_SPI_SPEED);
- }
- //Serial.println("card is ready");
- // detect high capacity cards
- if (card_type == 2) {
- ocr = sd_cmd58();
- //Serial.print("ocr =");
- //Serial.println(ocr, HEX);
- if ((ocr >> 30) == 3) card_type = 3;
- }
- SPI.endTransaction();
- //Serial.println("init ok");
- // read the MBR (partition table)
- SDCache s;
- sector_t * mbr = s.read(0);
- //Serial.printf(" mbr sig = %04X\n", mbr->u16[255]);
- if (mbr->u16[255] != 0xAA55) return false;
- uint32_t partition_lba = 0;
- uint32_t index = 446;
- do {
- uint8_t type = mbr->u8[index+4];
- //Serial.printf(" partition %d is type %d\n", (index-446)/16+1, type);
- if (type == 6 || type == 11 || type == 12) {
- partition_lba = unaligned_read32_align16(mbr->u8 + index + 8);
- //Serial.printf(" partition lba = %d\n", partition_lba);
- break;
- }
- index += 16;
- } while (index < 64);
- s.release();
-
- // read the FAT volume ID
- sector_t *vol = s.read(partition_lba);
- if (vol->u16[255] != 0xAA55) return false;
- // BPB_BytsPerSec must be 512 bytes per sector
- if (unaligned_read16_align8(vol->u8 + BPB_BytsPerSec) != 512) return false;
- // BPB_NumFATs must be 2 copies of the file allocation table
- if (vol->u8[BPB_NumFATs] != 2) return false;
- uint32_t reserved_sectors = vol->u16[14/2];
- if (reserved_sectors == 0) return false;
- //Serial.printf(" reserved_sectors = %d\n", reserved_sectors);
- uint32_t sectors_per_cluster = vol->u8[BPB_SecPerClus];
- //Serial.printf(" sectors_per_cluster = %d\n", sectors_per_cluster);
- uint32_t s2c = 31 - __builtin_clz(sectors_per_cluster);
- //Serial.printf(" s2c = %d\n", s2c);
- sector2cluster = s2c;
- uint32_t sectors_per_fat = vol->u16[BPB_FATSz16/2];
- if (sectors_per_fat == 0) sectors_per_fat = vol->u32[BPB_FATSz32/4];
- //Serial.printf(" sectors_per_fat = %d\n", sectors_per_fat);
- uint32_t root_dir_entries = unaligned_read16_align8(vol->u8 + BPB_RootEntCnt);
- //Serial.printf(" root_dir_entries = %d\n", root_dir_entries);
- uint32_t root_dir_sectors = (root_dir_entries + 15) >> 4;
- //Serial.printf(" root_dir_sectors = %d\n", root_dir_sectors);
-
- uint32_t total_sectors = unaligned_read16_align8(vol->u8 + BPB_TotSec16);
- if (total_sectors == 0) total_sectors = vol->u32[BPB_TotSec32/4];
- //Serial.printf(" total_sectors = %d\n", total_sectors);
-
- fat1_begin_lba = partition_lba + reserved_sectors;
- fat2_begin_lba = fat1_begin_lba + sectors_per_fat;
- data_begin_lba = fat2_begin_lba + sectors_per_fat + root_dir_sectors;
-
- uint32_t cluster_count = (total_sectors - reserved_sectors
- - root_dir_sectors - (sectors_per_fat << 1)) >> s2c;
- //Serial.printf(" cluster_count = %d\n", cluster_count);
- max_cluster = cluster_count + 1;
- if (cluster_count < 4085) {
- return false; // FAT12
- } else if (cluster_count < 65525) {
- fat_type = 16;
- rootDir.length = root_dir_entries << 5;
- rootDir.start_cluster = partition_lba + reserved_sectors + sectors_per_fat * 2;
- rootDir.type = FILE_DIR_ROOT16;
- } else {
- fat_type = 32;
- rootDir.length = 0;
- rootDir.start_cluster = vol->u32[BPB_RootClus/4];
- //Serial.printf(" root cluster = %d\n", rootDir.start_cluster);
- rootDir.type = FILE_DIR;
- }
- rootDir.current_cluster = rootDir.start_cluster;
- rootDir.offset = 0;
- s.release();
- //Serial.println(sizeof(fatdir_t));
- return true;
- }
-
- #endif
- #endif
|