remove unused files
This commit is contained in:
parent
1e9cb3eeef
commit
df5152579d
File diff suppressed because it is too large
Load Diff
743
src/sdcard.c
743
src/sdcard.c
@ -1,743 +0,0 @@
|
||||
/* sd2iec - SD/MMC to Commodore serial bus interface/controller
|
||||
Copyright (C) 2007-2010 Ingo Korb <ingo@akana.de>
|
||||
|
||||
Inspiration and low-level SD/MMC access based on code from MMC2IEC
|
||||
by Lars Pontoppidan et al., see sdcard.c|h and config.h.
|
||||
|
||||
FAT filesystem access based on code from ChaN and Jim Brain, see ff.c|h.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License only.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
|
||||
sdcard.c: SD/MMC access routines
|
||||
|
||||
Extended, optimized and cleaned version of code from MMC2IEC,
|
||||
original copyright header follows:
|
||||
|
||||
//
|
||||
// Title : SD/MMC Card driver
|
||||
// Author : Lars Pontoppidan, Aske Olsson, Pascal Dufour,
|
||||
// Date : Jan. 2006
|
||||
// Version : 0.42
|
||||
// Target MCU : Atmel AVR Series
|
||||
//
|
||||
// CREDITS:
|
||||
// This module is developed as part of a project at the technical univerisity of
|
||||
// Denmark, DTU.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// This SD card driver implements the fundamental communication with a SD card.
|
||||
// The driver is confirmed working on 8 MHz and 14.7456 MHz AtMega32 and has
|
||||
// been tested successfully with a large number of different SD and MMC cards.
|
||||
//
|
||||
// DISCLAIMER:
|
||||
// The author is in no way responsible for any problems or damage caused by
|
||||
// using this code. Use at your own risk.
|
||||
//
|
||||
// LICENSE:
|
||||
// This code is distributed under the GNU Public License
|
||||
// which can be found at http://www.gnu.org/licenses/gpl.txt
|
||||
//
|
||||
|
||||
The exported functions in this file are weak-aliased to their corresponding
|
||||
versions defined in diskio.h so when this file is the only diskio provider
|
||||
compiled in they will be automatically used by the linker.
|
||||
|
||||
*/
|
||||
|
||||
#include <arm/NXP/LPC17xx/LPC17xx.h>
|
||||
#include <arm/bits.h>
|
||||
#include "config.h"
|
||||
#include "crc.h"
|
||||
#include "diskio.h"
|
||||
#include "spi.h"
|
||||
#include "timer.h"
|
||||
#include "uart.h"
|
||||
#include "sdcard.h"
|
||||
#include "led.h"
|
||||
|
||||
// FIXME: Move, make configurable
|
||||
static void set_sd_led(uint8_t state) {
|
||||
// BITBAND(LPC_GPIO2->FIODIR, 2) = state;
|
||||
}
|
||||
|
||||
// FIXME: Move, add generic C or AVR ASM version
|
||||
static uint32_t swap_word(uint32_t input) {
|
||||
uint32_t result;
|
||||
asm("rev %[result], %[input]" : [result] "=r" (result) : [input] "r" (input));
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_TWINSD
|
||||
# define MAX_CARDS 2
|
||||
#else
|
||||
# define MAX_CARDS 1
|
||||
#endif
|
||||
|
||||
// SD/MMC commands
|
||||
#define GO_IDLE_STATE 0
|
||||
#define SEND_OP_COND 1
|
||||
#define SWITCH_FUNC 6
|
||||
#define SEND_IF_COND 8
|
||||
#define SEND_CSD 9
|
||||
#define SEND_CID 10
|
||||
#define STOP_TRANSMISSION 12
|
||||
#define SEND_STATUS 13
|
||||
#define SET_BLOCKLEN 16
|
||||
#define READ_SINGLE_BLOCK 17
|
||||
#define READ_MULTIPLE_BLOCK 18
|
||||
#define WRITE_BLOCK 24
|
||||
#define WRITE_MULTIPLE_BLOCK 25
|
||||
#define PROGRAM_CSD 27
|
||||
#define SET_WRITE_PROT 28
|
||||
#define CLR_WRITE_PROT 29
|
||||
#define SEND_WRITE_PROT 30
|
||||
#define ERASE_WR_BLK_STAR_ADDR 32
|
||||
#define ERASE_WR_BLK_END_ADDR 33
|
||||
#define ERASE 38
|
||||
#define LOCK_UNLOCK 42
|
||||
#define APP_CMD 55
|
||||
#define GEN_CMD 56
|
||||
#define READ_OCR 58
|
||||
#define CRC_ON_OFF 59
|
||||
|
||||
// SD ACMDs
|
||||
#define SD_STATUS 13
|
||||
#define SD_SEND_NUM_WR_BLOCKS 22
|
||||
#define SD_SET_WR_BLK_ERASE_COUNT 23
|
||||
#define SD_SEND_OP_COND 41
|
||||
#define SD_SET_CLR_CARD_DETECT 42
|
||||
#define SD_SEND_SCR 51
|
||||
|
||||
// R1 status bits
|
||||
#define STATUS_IN_IDLE 1
|
||||
#define STATUS_ERASE_RESET 2
|
||||
#define STATUS_ILLEGAL_COMMAND 4
|
||||
#define STATUS_CRC_ERROR 8
|
||||
#define STATUS_ERASE_SEQ_ERROR 16
|
||||
#define STATUS_ADDRESS_ERROR 32
|
||||
#define STATUS_PARAMETER_ERROR 64
|
||||
|
||||
|
||||
/* Card types - cardtype == 0 is MMC */
|
||||
#define CARD_SD (1<<0)
|
||||
#define CARD_SDHC (1<<1)
|
||||
|
||||
static uint8_t cardtype[MAX_CARDS];
|
||||
|
||||
/**
|
||||
* getbits - read value from bit buffer
|
||||
* @buffer: pointer to the data buffer
|
||||
* @start : index of the first bit in the value
|
||||
* @bits : number of bits in the value
|
||||
*
|
||||
* This function returns a value from the memory region passed as
|
||||
* buffer, starting with bit "start" and "bits" bit long. The buffer
|
||||
* is assumed to be MSB first, passing 0 for start will read starting
|
||||
* from the highest-value bit of the first byte of the buffer.
|
||||
*/
|
||||
static uint32_t getbits(void *buffer, uint16_t start, int8_t bits) {
|
||||
uint8_t *buf = buffer;
|
||||
uint32_t result = 0;
|
||||
|
||||
if ((start % 8) != 0) {
|
||||
/* Unaligned start */
|
||||
result += buf[start / 8] & (0xff >> (start % 8));
|
||||
bits -= 8 - (start % 8);
|
||||
start += 8 - (start % 8);
|
||||
}
|
||||
while (bits >= 8) {
|
||||
result = (result << 8) + buf[start / 8];
|
||||
start += 8;
|
||||
bits -= 8;
|
||||
}
|
||||
if (bits > 0) {
|
||||
result = result << bits;
|
||||
result = result + (buf[start / 8] >> (8-bits));
|
||||
} else if (bits < 0) {
|
||||
/* Fraction of a single byte */
|
||||
result = result >> -bits;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* wait_for_response - waits for a response from the SD card
|
||||
* @expected: expected data byte (0 for anything != 0)
|
||||
*
|
||||
* This function waits until reading from the SD card returns the
|
||||
* byte in expected or until reading returns a non-zero byte if
|
||||
* expected is 0. Returns false if the expected response wasn't
|
||||
* received within 500ms or true if it was.
|
||||
*/
|
||||
static uint8_t wait_for_response(uint8_t expected) {
|
||||
tick_t timeout = getticks() + HZ/2;
|
||||
|
||||
while (time_before(getticks(), timeout)) {
|
||||
uint8_t byte = spi_rx_byte(SPI_SD);
|
||||
|
||||
if (expected == 0 && byte != 0)
|
||||
return 1;
|
||||
|
||||
if (expected != 0 && byte == expected)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void deselectCard(uint8_t card) {
|
||||
// Send 8 clock cycles
|
||||
set_sd_led(0);
|
||||
spi_rx_byte(SPI_SD);
|
||||
}
|
||||
|
||||
/**
|
||||
* sendCommand - send a command to the SD card
|
||||
* @card : card number to be accessed
|
||||
* @command : command to be sent
|
||||
* @parameter: parameter to be sent
|
||||
* @deselect : Flags if the card should be deselected afterwards
|
||||
*
|
||||
* This function calculates the correct CRC7 for the command and
|
||||
* parameter and transmits all of it to the SD card. If requested
|
||||
* the card will be deselected afterwards.
|
||||
*/
|
||||
static int sendCommand(const uint8_t card,
|
||||
const uint8_t command,
|
||||
const uint32_t parameter,
|
||||
const uint8_t deselect) {
|
||||
union {
|
||||
uint32_t l;
|
||||
uint8_t c[4];
|
||||
} long2char;
|
||||
|
||||
uint8_t i,crc,errorcount;
|
||||
tick_t timeout;
|
||||
|
||||
long2char.l = parameter;
|
||||
crc = crc7update(0 , 0x40+command);
|
||||
crc = crc7update(crc, long2char.c[3]);
|
||||
crc = crc7update(crc, long2char.c[2]);
|
||||
crc = crc7update(crc, long2char.c[1]);
|
||||
crc = crc7update(crc, long2char.c[0]);
|
||||
crc = (crc << 1) | 1;
|
||||
|
||||
errorcount = 0;
|
||||
while (errorcount < CONFIG_SD_AUTO_RETRIES) {
|
||||
// Select card
|
||||
set_sd_led(1);
|
||||
#ifdef CONFIG_TWINSD
|
||||
if (card == 0 && command == GO_IDLE_STATE)
|
||||
/* Force both cards to SPI mode simultaneously */
|
||||
SPI_SS_LOW(1);
|
||||
#endif
|
||||
|
||||
// Transfer command
|
||||
spi_tx_byte(0x40+command, SPI_SD);
|
||||
uint32_t tmp = swap_word(parameter);
|
||||
spi_tx_block(&tmp, 4, SPI_SD);
|
||||
spi_tx_byte(crc, SPI_SD);
|
||||
|
||||
// Wait for a valid response
|
||||
timeout = getticks() + HZ/2;
|
||||
do {
|
||||
i = spi_rx_byte(SPI_SD);
|
||||
} while (i & 0x80 && time_before(getticks(), timeout));
|
||||
|
||||
#ifdef CONFIG_TWINSD
|
||||
if (card == 0 && command == GO_IDLE_STATE)
|
||||
SPI_SS_HIGH(1);
|
||||
#endif
|
||||
|
||||
// Check for CRC error
|
||||
// can't reliably retry unless deselect is allowed
|
||||
if (deselect && (i & STATUS_CRC_ERROR)) {
|
||||
uart_putc('x');
|
||||
deselectCard(card);
|
||||
errorcount++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (deselect) deselectCard(card);
|
||||
break;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
// Extended init sequence for SDHC support
|
||||
static uint8_t extendedInit(const uint8_t card) {
|
||||
uint8_t i;
|
||||
uint32_t answer;
|
||||
|
||||
// Send CMD8: SEND_IF_COND
|
||||
// 0b000110101010 == 2.7-3.6V supply, check pattern 0xAA
|
||||
i = sendCommand(card, SEND_IF_COND, 0b000110101010, 0);
|
||||
if (i > 1) {
|
||||
// Card returned an error, ok (MMC or SD1.x) but not SDHC
|
||||
deselectCard(card);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// No error, continue SDHC initialization
|
||||
spi_rx_block(&answer, 4, SPI_SD);
|
||||
answer = swap_word(answer);
|
||||
deselectCard(card);
|
||||
|
||||
if (((answer >> 8) & 0x0f) != 0b0001) {
|
||||
// Card didn't accept our voltage specification
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Verify echo-back of check pattern
|
||||
if ((answer & 0xff) != 0b10101010) {
|
||||
// Check pattern mismatch, working but not SD2.0 compliant
|
||||
// The specs say we should not use the card, but let's try anyway.
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// SD common initialisation
|
||||
static void sdInit(const uint8_t card) {
|
||||
uint8_t i;
|
||||
uint16_t counter;
|
||||
printf("sdInit\n");
|
||||
counter = 0xffff;
|
||||
do {
|
||||
// Prepare for ACMD, send CMD55: APP_CMD
|
||||
i = sendCommand(card, APP_CMD, 0, 1);
|
||||
if (i > 1) {
|
||||
// Command not accepted, could be MMC
|
||||
return;
|
||||
}
|
||||
|
||||
// Send ACMD41: SD_SEND_OP_COND
|
||||
// 1L<<30 == Host has High Capacity Support
|
||||
i = sendCommand(card, SD_SEND_OP_COND, 1L<<30, 1);
|
||||
// Repeat while card card accepts command but isn't ready
|
||||
} while (i == 1 && --counter > 0);
|
||||
|
||||
// Ignore failures, there is at least one Sandisk MMC card
|
||||
// that accepts CMD55, but not ACMD41.
|
||||
if (i == 0)
|
||||
/* We know that a card is SD if ACMD41 was accepted. */
|
||||
cardtype[card] |= CARD_SD;
|
||||
}
|
||||
|
||||
/* Detect changes of SD card 0 */
|
||||
void sd_changed() {
|
||||
if (SDCARD_DETECT)
|
||||
disk_state = DISK_CHANGED;
|
||||
else
|
||||
disk_state = DISK_REMOVED;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_TWINSD
|
||||
/* Detect changes of SD card 1 */
|
||||
ISR(SD2_CHANGE_VECT) {
|
||||
if (SD2_DETECT)
|
||||
disk_state = DISK_CHANGED;
|
||||
else
|
||||
disk_state = DISK_REMOVED;
|
||||
}
|
||||
#endif
|
||||
|
||||
//
|
||||
// Public functions
|
||||
//
|
||||
void sd_init(void) {
|
||||
/* enable GPIO interrupt on SD detect pin, both edges */
|
||||
NVIC_EnableIRQ(EINT3_IRQn);
|
||||
SD_DT_INT_SETUP();
|
||||
}
|
||||
void disk_init(void) __attribute__ ((weak, alias("sd_init")));
|
||||
|
||||
|
||||
DSTATUS sd_status(BYTE drv) {
|
||||
#ifdef CONFIG_TWINSD
|
||||
if (drv != 0) {
|
||||
if (SD2_DETECT) {
|
||||
if (SD2_PIN & SD2_WP) {
|
||||
return STA_PROTECT;
|
||||
} else {
|
||||
return RES_OK;
|
||||
}
|
||||
} else {
|
||||
return STA_NOINIT|STA_NODISK;
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
if (SDCARD_DETECT)
|
||||
if (SDCARD_WP)
|
||||
return STA_PROTECT;
|
||||
else
|
||||
return RES_OK;
|
||||
else
|
||||
return STA_NOINIT|STA_NODISK;
|
||||
}
|
||||
DSTATUS disk_status(BYTE drv) __attribute__ ((weak, alias("sd_status")));
|
||||
|
||||
|
||||
/**
|
||||
* sd_initialize - initialize SD card
|
||||
* @drv : drive
|
||||
*
|
||||
* This function tries to initialize the selected SD card.
|
||||
*/
|
||||
DSTATUS sd_initialize(BYTE drv) {
|
||||
uint8_t i;
|
||||
uint16_t counter;
|
||||
uint32_t answer;
|
||||
printf("sd_initialize\n");
|
||||
if (drv >= MAX_CARDS)
|
||||
return STA_NOINIT|STA_NODISK;
|
||||
/* Don't bother initializing a card that isn't there */
|
||||
if (sd_status(drv) & STA_NODISK)
|
||||
return sd_status(drv);
|
||||
/* JLB: Should be in sd_init, but some uIEC versions have
|
||||
* IEC lines tied to SPI, so I moved it here to resolve the
|
||||
* conflict.
|
||||
*/
|
||||
spi_init(SPI_SPEED_SLOW, SPI_SD);
|
||||
disk_state = DISK_ERROR;
|
||||
|
||||
cardtype[drv] = 0;
|
||||
|
||||
set_sd_led(0);
|
||||
|
||||
// Send 8000 clks
|
||||
for (counter=0; counter<1000; counter++) {
|
||||
spi_tx_byte(0xff, SPI_SD);
|
||||
}
|
||||
|
||||
// Reset card
|
||||
i = sendCommand(drv, GO_IDLE_STATE, 0, 1);
|
||||
if (i != 1) {
|
||||
return STA_NOINIT | STA_NODISK;
|
||||
}
|
||||
|
||||
if (!extendedInit(drv)) {
|
||||
return STA_NOINIT | STA_NODISK;
|
||||
}
|
||||
|
||||
sdInit(drv);
|
||||
|
||||
counter = 0xffff;
|
||||
// According to the spec READ_OCR should work at this point
|
||||
// without retries. One of my Sandisk-cards thinks otherwise.
|
||||
do {
|
||||
// Send CMD58: READ_OCR
|
||||
i = sendCommand(drv, READ_OCR, 0, 0);
|
||||
if (i > 1)
|
||||
deselectCard(drv);
|
||||
} while (i > 1 && counter-- > 0);
|
||||
|
||||
if (counter > 0) {
|
||||
spi_rx_block(&answer, 4, SPI_SD);
|
||||
answer = swap_word(answer);
|
||||
|
||||
// See if the card likes our supply voltage
|
||||
if (!(answer & SD_SUPPLY_VOLTAGE)) {
|
||||
// The code isn't set up to completely ignore the card,
|
||||
// but at least report it as nonworking
|
||||
deselectCard(drv);
|
||||
return STA_NOINIT | STA_NODISK;
|
||||
}
|
||||
|
||||
// See what card we've got
|
||||
if (answer & 0x40000000) {
|
||||
cardtype[drv] |= CARD_SDHC;
|
||||
}
|
||||
}
|
||||
|
||||
// Keep sending CMD1 (SEND_OP_COND) command until zero response
|
||||
counter = 0xffff;
|
||||
do {
|
||||
i = sendCommand(drv, SEND_OP_COND, 1L<<30, 1);
|
||||
counter--;
|
||||
} while (i != 0 && counter > 0);
|
||||
|
||||
if (counter==0) {
|
||||
return STA_NOINIT | STA_NODISK;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SD_DATACRC
|
||||
// Enable CRC checking
|
||||
// The SD spec says that the host "should" send CRC_ON_OFF before ACMD_SEND_OP_COND.
|
||||
// The MMC manual I have says that CRC_ON_OFF isn't allowed before SEND_OP_COND.
|
||||
// Let's just hope that all SD cards work with this order. =(
|
||||
i = sendCommand(drv, CRC_ON_OFF, 1, 1);
|
||||
if (i > 1) {
|
||||
return STA_NOINIT | STA_NODISK;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Send MMC CMD16(SET_BLOCKLEN) to 512 bytes
|
||||
i = sendCommand(drv, SET_BLOCKLEN, 512, 1);
|
||||
if (i != 0) {
|
||||
return STA_NOINIT | STA_NODISK;
|
||||
}
|
||||
|
||||
// Thats it!
|
||||
spi_set_speed(SPI_SPEED_FAST, SPI_SD);
|
||||
disk_state = DISK_OK;
|
||||
return sd_status(drv);
|
||||
}
|
||||
DSTATUS disk_initialize(BYTE drv) __attribute__ ((weak, alias("sd_initialize")));
|
||||
|
||||
|
||||
/**
|
||||
* sd_read - reads sectors from the SD card to buffer
|
||||
* @drv : drive
|
||||
* @buffer: pointer to the buffer
|
||||
* @sector: first sector to be read
|
||||
* @count : number of sectors to be read
|
||||
*
|
||||
* This function reads count sectors from the SD card starting
|
||||
* at sector to buffer. Returns RES_ERROR if an error occured or
|
||||
* RES_OK if successful. Up to SD_AUTO_RETRIES will be made if
|
||||
* the calculated data CRC does not match the one sent by the
|
||||
* card. If there were errors during the command transmission
|
||||
* disk_state will be set to DISK_ERROR and no retries are made.
|
||||
*/
|
||||
DRESULT sd_read(BYTE drv, BYTE *buffer, DWORD sector, BYTE count) {
|
||||
uint8_t sec,res,errorcount;
|
||||
uint16_t crc,recvcrc;
|
||||
if (drv >= MAX_CARDS)
|
||||
return RES_PARERR;
|
||||
//printf("sd_read: sector=%lu, count=%u\n", sector, count);
|
||||
for (sec=0;sec<count;sec++) {
|
||||
errorcount = 0;
|
||||
while (errorcount < CONFIG_SD_AUTO_RETRIES) {
|
||||
if (cardtype[drv] & CARD_SDHC)
|
||||
res = sendCommand(drv, READ_SINGLE_BLOCK, sector+sec, 0);
|
||||
else
|
||||
res = sendCommand(drv, READ_SINGLE_BLOCK, (sector+sec) << 9, 0);
|
||||
|
||||
if (res != 0) {
|
||||
set_sd_led(0);
|
||||
disk_state = DISK_ERROR;
|
||||
return RES_ERROR;
|
||||
}
|
||||
|
||||
// Wait for data token
|
||||
if (!wait_for_response(0xFE)) {
|
||||
set_sd_led(0);
|
||||
disk_state = DISK_ERROR;
|
||||
return RES_ERROR;
|
||||
}
|
||||
|
||||
// Get data
|
||||
crc = 0;
|
||||
|
||||
#ifdef CONFIG_SD_BLOCKTRANSFER
|
||||
/* Transfer data first, calculate CRC afterwards */
|
||||
spi_rx_block(buffer, 512, SPI_SD);
|
||||
|
||||
recvcrc = spi_rx_byte(SPI_SD) << 8 | spi_rx_byte(SPI_SD);
|
||||
#ifdef CONFIG_SD_DATACRC
|
||||
crc = crc_xmodem_block(0, buffer, 512);
|
||||
#endif
|
||||
#else
|
||||
/* Interleave transfer/CRC calculation, AVR-specific */
|
||||
// Initiate data exchange over SPI
|
||||
SPDR = 0xff;
|
||||
uint8_t tmp;
|
||||
|
||||
for (i=0; i<512; i++) {
|
||||
// Wait until data has been received
|
||||
loop_until_bit_is_set(SPSR, SPIF);
|
||||
tmp = SPDR;
|
||||
// Transmit the next byte while we store the current one
|
||||
SPDR = 0xff;
|
||||
|
||||
*(buffer++) = tmp;
|
||||
#ifdef CONFIG_SD_DATACRC
|
||||
crc = _crc_xmodem_update(crc, tmp);
|
||||
#endif
|
||||
}
|
||||
// Wait until the first CRC byte is received
|
||||
loop_until_bit_is_set(SPSR, SPIF);
|
||||
|
||||
// Check CRC
|
||||
recvcrc = (SPDR << 8) + spiTransferByte(0xff);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SD_DATACRC
|
||||
if (recvcrc != crc) {
|
||||
uart_putc('X');
|
||||
deselectCard(drv);
|
||||
errorcount++;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
break;
|
||||
}
|
||||
deselectCard(drv);
|
||||
|
||||
if (errorcount >= CONFIG_SD_AUTO_RETRIES) return RES_ERROR;
|
||||
}
|
||||
|
||||
return RES_OK;
|
||||
}
|
||||
DRESULT disk_read(BYTE drv, BYTE *buffer, DWORD sector, BYTE count) __attribute__ ((weak, alias("sd_read")));
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* sd_write - writes sectors from buffer to the SD card
|
||||
* @drv : drive
|
||||
* @buffer: pointer to the buffer
|
||||
* @sector: first sector to be written
|
||||
* @count : number of sectors to be written
|
||||
*
|
||||
* This function writes count sectors from buffer to the SD card
|
||||
* starting at sector. Returns RES_ERROR if an error occured,
|
||||
* RES_WPRT if the card is currently write-protected or RES_OK
|
||||
* if successful. Up to SD_AUTO_RETRIES will be made if the card
|
||||
* signals a CRC error. If there were errors during the command
|
||||
* transmission disk_state will be set to DISK_ERROR and no retries
|
||||
* are made.
|
||||
*/
|
||||
DRESULT sd_write(BYTE drv, const BYTE *buffer, DWORD sector, BYTE count) {
|
||||
uint8_t res,sec,errorcount,status;
|
||||
uint16_t crc;
|
||||
|
||||
if (drv >= MAX_CARDS)
|
||||
return RES_PARERR;
|
||||
|
||||
#ifdef CONFIG_TWINSD
|
||||
if (drv != 0) {
|
||||
if (SD2_PIN & SD2_WP)
|
||||
return RES_WRPRT;
|
||||
} else
|
||||
#endif
|
||||
|
||||
if (SDCARD_WP) return RES_WRPRT;
|
||||
|
||||
for (sec=0;sec<count;sec++) {
|
||||
errorcount = 0;
|
||||
while (errorcount < CONFIG_SD_AUTO_RETRIES) {
|
||||
writeled(1);
|
||||
if (cardtype[drv] & CARD_SDHC)
|
||||
res = sendCommand(drv, WRITE_BLOCK, sector+sec, 0);
|
||||
else
|
||||
res = sendCommand(drv, WRITE_BLOCK, (sector+sec)<<9, 0);
|
||||
|
||||
if (res != 0) {
|
||||
writeled(0);
|
||||
disk_state = DISK_ERROR;
|
||||
return RES_ERROR;
|
||||
}
|
||||
|
||||
// Send data token
|
||||
spi_tx_byte(0xfe, SPI_SD);
|
||||
|
||||
// Send data
|
||||
spi_tx_block(buffer, 512, SPI_SD);
|
||||
#ifdef CONFIG_SD_DATACRC
|
||||
crc = crc_xmodem_block(0, buffer, 512);
|
||||
#else
|
||||
crc = 0;
|
||||
#endif
|
||||
|
||||
// Send CRC
|
||||
spi_tx_byte(crc >> 8, SPI_SD);
|
||||
spi_tx_byte(crc & 0xff, SPI_SD);
|
||||
|
||||
// Get and check status feedback
|
||||
status = spi_rx_byte(SPI_SD);
|
||||
|
||||
// Retry if neccessary
|
||||
if ((status & 0x0F) != 0x05) {
|
||||
uart_putc('X');
|
||||
deselectCard(drv);
|
||||
errorcount++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Wait for write finish
|
||||
if (!wait_for_response(0)) {
|
||||
writeled(0);
|
||||
disk_state = DISK_ERROR;
|
||||
return RES_ERROR;
|
||||
}
|
||||
break;
|
||||
}
|
||||
deselectCard(drv);
|
||||
|
||||
if (errorcount >= CONFIG_SD_AUTO_RETRIES) {
|
||||
if (!(status & STATUS_CRC_ERROR))
|
||||
disk_state = DISK_ERROR;
|
||||
return RES_ERROR;
|
||||
}
|
||||
}
|
||||
writeled(0);
|
||||
return RES_OK;
|
||||
}
|
||||
DRESULT disk_write(BYTE drv, const BYTE *buffer, DWORD sector, BYTE count) __attribute__ ((weak, alias("sd_write")));
|
||||
|
||||
DRESULT sd_getinfo(BYTE drv, BYTE page, void *buffer) {
|
||||
uint8_t buf[18];
|
||||
uint32_t capacity;
|
||||
|
||||
if (drv >= MAX_CARDS)
|
||||
return RES_NOTRDY;
|
||||
|
||||
if (sd_status(drv) & STA_NODISK)
|
||||
return RES_NOTRDY;
|
||||
|
||||
if (page != 0)
|
||||
return RES_ERROR;
|
||||
|
||||
/* Try to calculate the total number of sectors on the card */
|
||||
/* FIXME: Write a generic data read function and merge with sd_read */
|
||||
if (sendCommand(drv, SEND_CSD, 0, 0) != 0) {
|
||||
deselectCard(drv);
|
||||
return RES_ERROR;
|
||||
}
|
||||
|
||||
/* Wait for data token */
|
||||
if (!wait_for_response(0xfe)) {
|
||||
deselectCard(drv);
|
||||
return RES_ERROR;
|
||||
}
|
||||
|
||||
spi_rx_block(buf, 18, SPI_SD);
|
||||
deselectCard(drv);
|
||||
|
||||
if (cardtype[drv] & CARD_SDHC) {
|
||||
/* Special CSD for SDHC cards */
|
||||
capacity = (1 + getbits(buf,127-69,22)) * 1024;
|
||||
} else {
|
||||
/* Assume that MMC-CSD 1.0/1.1/1.2 and SD-CSD 1.1 are the same... */
|
||||
uint8_t exponent = 2 + getbits(buf, 127-49, 3);
|
||||
capacity = 1 + getbits(buf, 127-73, 12);
|
||||
exponent += getbits(buf, 127-83,4) - 9;
|
||||
while (exponent--) capacity *= 2;
|
||||
}
|
||||
|
||||
diskinfo0_t *di = buffer;
|
||||
di->validbytes = sizeof(diskinfo0_t);
|
||||
di->disktype = DISK_TYPE_SD;
|
||||
di->sectorsize = 2;
|
||||
di->sectorcount = capacity;
|
||||
|
||||
return RES_OK;
|
||||
}
|
||||
DRESULT disk_getinfo(BYTE drv, BYTE page, void *buffer) __attribute__ ((weak, alias("sd_getinfo")));
|
||||
Loading…
x
Reference in New Issue
Block a user