531 lines
16 KiB
C
531 lines
16 KiB
C
/******************************************************************************/
|
|
/**
|
|
@file sd_spi.h
|
|
@author Wade Penson
|
|
@date June, 2015
|
|
@brief SD RAW library header.
|
|
@details This library supports MMC, SD1, SD2, and SDHC/SDXC type cards.
|
|
By defining SD_BUFFER, the library also implements a 512 byte buffer
|
|
for reading and writing.
|
|
|
|
@copyright Copyright 2015 Wade Penson
|
|
|
|
@license Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
implied. See the License for the specific language governing
|
|
permissions and limitations under the License.
|
|
|
|
@todo Support for AVR and SAMX AVR without using the Arduino SPI library.
|
|
@todo Support for using Software SPI (bit banging).
|
|
@todo Use CMD6 during initialization to switch card to high speed mode if
|
|
it supports it. This will be helpful for the due since the SPI
|
|
speed can be up to 84MHz.
|
|
@todo Allow setting CS high when card is in busy state for operations
|
|
instead of waiting. However, if an error is thrown for the
|
|
operation, the host will get that error on the next command it
|
|
sends.
|
|
@todo Send_status should be sent after all busy signals
|
|
(look at ch 4.3.7).
|
|
@todo Send stop_transmission if there was an error during
|
|
write continuous (and read continuous??).
|
|
@todo Get the number of well written blocks for sequential writing just in
|
|
case if there was an error.
|
|
@todo Card reads take up to 100ms and writes take up to 500ms. Make
|
|
timeouts reflect this.
|
|
@todo Reduce the number of error codes.
|
|
*/
|
|
/******************************************************************************/
|
|
|
|
#if !defined(SD_SPI_H_)
|
|
#define SD_SPI_H_
|
|
|
|
#if defined(__cplusplus)
|
|
extern "C" {
|
|
#endif
|
|
|
|
#include <string.h>
|
|
#include <stdint.h>
|
|
#include "sd_spi_info.h"
|
|
#include "sd_spi_commands.h"
|
|
|
|
/** Define to enable the block buffer. */
|
|
#define SD_SPI_BUFFER
|
|
|
|
/** State variables used by the SD raw library. */
|
|
typedef struct sd_spi_card {
|
|
/** Digital pin for setting CS high or low. */
|
|
uint8_t chip_select_pin: 8;
|
|
/** The speed of the SPI bus. Use 0 for 25KHz and 1 for 25MHz. */
|
|
uint8_t spi_speed: 3;
|
|
/** Determines if the card is MMC, SD1, SD2, or SDHC/SDXC. */
|
|
uint8_t card_type: 3;
|
|
/** Flag to see if CS has already been set to high or low. */
|
|
uint8_t is_chip_select_high: 1;
|
|
/** True if currently reading continually and false otherwise. */
|
|
uint8_t is_read_write_continuous: 1;
|
|
/** True if currently writing continually and false otherwise. */
|
|
uint8_t is_write_continuous: 1;
|
|
/** If the card is being read or written to continually, this keeps track
|
|
of the block being read or written to. */
|
|
uint32_t continuous_block_address;
|
|
|
|
#if defined(SD_SPI_BUFFER)
|
|
/** Buffer for SD blocks. */
|
|
uint8_t sd_spi_buffer[512];
|
|
/** The address of the block currently being buffered. */
|
|
uint32_t buffered_block_address;
|
|
/** Keeps track of the consistency of the buffer for reading. */
|
|
uint8_t is_buffer_current: 1;
|
|
/** Keeps track if the buffer has been flushed or not. */
|
|
uint8_t is_buffer_written: 1;
|
|
#endif
|
|
} sd_spi_card_t;
|
|
|
|
/**
|
|
@defgroup sd_spi_timeouts SD Timeouts
|
|
@brief Timeouts are used so that the SD does not freeze on
|
|
a task if a failure occurs.
|
|
@{
|
|
*/
|
|
#define SD_INIT_TIMEOUT 5000
|
|
#define SD_WRITE_TIMEOUT 5000
|
|
#define SD_READ_TIMEOUT 5000
|
|
#define SD_ERASE_TIMEOUT 500000
|
|
|
|
/** @} End of group sd_spi_timeouts */
|
|
|
|
/**
|
|
@defgroup sd_spi_card_types SD/MMC Card Types
|
|
@brief Types of cards.
|
|
@{
|
|
*/
|
|
#define SD_CARD_TYPE_UNKNOWN 0
|
|
#define SD_CARD_TYPE_SD1 1
|
|
#define SD_CARD_TYPE_SD2 2
|
|
#define SD_CARD_TYPE_SDHC 3
|
|
#define SD_CARD_TYPE_MMC 4
|
|
|
|
/** @} End of group sd_spi_card_types */
|
|
|
|
/**
|
|
@defgroup sd_spi_error_codes SD Error Codes
|
|
@brief Error codes for the SD library.
|
|
@{
|
|
*/
|
|
#define SD_ERR_OK 0
|
|
|
|
#define SD_ERR_ALREADY_INITIALIZED 1
|
|
#define SD_ERR_NOT_INITIALIZED 2
|
|
#define SD_ERR_UNKNOWN_CARD_TYPE 3
|
|
#define SD_ERR_INIT_TIMEOUT 4
|
|
#define SD_ERR_COMMAND_TIMEOUT 5
|
|
#define SD_ERR_OUTSIDE_VOLTAGE_RANGE 6
|
|
#define SD_ERR_SEND_IF_COND_WRONG_TEST_PATTERN 7
|
|
#define SD_ERR_OCR_REGISTER 8
|
|
#define SD_ERR_SETTING_BLOCK_LENGTH 9
|
|
|
|
#define SD_ERR_ILLEGAL_COMMAND 10
|
|
#define SD_ERR_COMMUNICATION_CRC 11
|
|
#define SD_ERR_ILLEGAL_ADDRESS 12
|
|
#define SD_ERR_ILLEGAL_PARAMETER 13
|
|
#define SD_ERR_CARD_IS_LOCKED 14
|
|
#define SD_ERR_CARD_CONTROLLER 15
|
|
#define SD_ERR_CARD_ECC_FAILURE 16
|
|
#define SD_ERR_ARGUMENT_OUT_OF_RANGE 17
|
|
#define SD_ERR_GENERAL 18
|
|
|
|
#define SD_ERR_WRITE_FAILURE 19
|
|
#define SD_ERR_WRITE_TIMEOUT 20
|
|
#define SD_ERR_WRITE_OUTSIDE_OF_BLOCK 21
|
|
#define SD_ERR_WRITE_DATA_REJECTED 22
|
|
#define SD_ERR_WRITE_DATA_CRC_REJECTED 23
|
|
#define SD_ERR_WRITE_PRE_ERASE 24
|
|
#define SD_ERR_WRITE_PROTECTION_VIOLATION 25
|
|
|
|
#define SD_ERR_READ_FAILURE 26
|
|
#define SD_ERR_READ_TIMEOUT 27
|
|
#define SD_ERR_READ_OUTSIDE_OF_BLOCK 28
|
|
|
|
#define SD_ERR_READ_WRITE_CONTINUOUS 29
|
|
|
|
#define SD_ERR_ERASE_FAILURE 30
|
|
#define SD_ERR_ERASE_TIMEOUT 31
|
|
#define SD_ERR_ERASE_RESET 32
|
|
#define SD_ERR_WRITE_PROTECTION_ERASE_SKIP 33
|
|
#define SD_ERR_ERASE_PARAMETER 34
|
|
#define SD_ERR_ERASE_SEQUENCE 35
|
|
|
|
#define SD_ERR_READ_REGISTER 36
|
|
|
|
/** @} End of group sd_spi_error_codes */
|
|
/* R1 token responses */
|
|
#define SD_IN_IDLE_STATE 0x01
|
|
#define SD_ERASE_RESET 0x02
|
|
#define SD_ILLEGAL_COMMAND 0x04
|
|
#define SD_COMMUNICATION_CRC_ERR 0x08
|
|
#define SD_ERASE_SEQUENCE_ERR 0x10
|
|
#define SD_ADDRESS_ERR 0x20
|
|
#define SD_PARAMETER_ERR 0x40
|
|
|
|
/* R2 token responses */
|
|
#define SD_CARD_IS_LOCKED 0x01
|
|
#define SD_WP_ERASE_SKIP 0x02
|
|
#define SD_GENERAL_ERR 0x04
|
|
#define SD_CC_ERR 0x08
|
|
#define SD_CARD_ECC_FAILURE 0x10
|
|
#define SD_WP_VIOLATION 0x20
|
|
#define SD_ERASE_PARAM 0x40
|
|
#define SD_OUT_OF_RANGE 0x80
|
|
|
|
/* Reading and writing tokens */
|
|
#define SD_TOKEN_START_BLOCK 0xFE
|
|
#define SD_TOKEN_MULTIPLE_WRITE_START_BLOCK 0xFC
|
|
#define SD_TOKEN_MULTIPLE_WRITE_STOP_TRANSFER 0xFD
|
|
#define SD_TOKEN_DATA_ACCEPTED 0x05
|
|
#define SD_TOKEN_DATA_REJECTED_CRC 0x0B
|
|
#define SD_TOKEN_DATA_REJECTED_WRITE_ERR 0x0D
|
|
|
|
/**
|
|
@brief Initializes the card with the given chip select pin.
|
|
@details The card is put into a state where it can be sent read, write, and
|
|
other commands.
|
|
|
|
@param chip_select_pin The digital pin connected to the CS on the card.
|
|
|
|
@return An error code as defined by one of the SD_ERR_* definitions.
|
|
*/
|
|
int8_t
|
|
sd_spi_init(
|
|
uint8_t chip_select_pin
|
|
);
|
|
|
|
/**
|
|
@brief Writes data to a block on the card.
|
|
@details If buffering is enabled, the card will read the block on the card
|
|
into the buffer. The passed in data will then be stored in
|
|
the buffer. The data will be only written out to the card when a
|
|
different block is written to, read is called, write is called,
|
|
erase is called, or sd_spi_flush() is explicitly called.
|
|
If buffering is not enabled, the card will write out the data and
|
|
pad the rest of the block with zeros if number_of_bytes is less
|
|
than 512.
|
|
|
|
@param block_address The address of the block on the card.
|
|
@param[in] data An array of data / an address to the data in
|
|
memory.
|
|
@param number_of_bytes The size of the data in bytes.
|
|
@param byte_offset The byte offset of where to start writing in the
|
|
block.
|
|
|
|
@return An error code as defined by one of the SD_ERR_* definitions.
|
|
*/
|
|
int8_t
|
|
sd_spi_write(
|
|
uint32_t block_address,
|
|
void *data,
|
|
uint16_t number_of_bytes,
|
|
uint16_t byte_offset
|
|
);
|
|
|
|
/**
|
|
@brief Writes a block of data to a block on the card.
|
|
@details When buffering is enabled, this is faster than using sd_spi_write
|
|
since it does not buffer in the block from the card.
|
|
|
|
@param block_address The address of the block on the card.
|
|
@param[in] data An array of data / an address to the data in
|
|
memory.
|
|
|
|
@return An error code as defined by one of the SD_ERR_* definitions.
|
|
*/
|
|
int8_t
|
|
sd_spi_write_block(
|
|
uint32_t block_address,
|
|
void *data
|
|
);
|
|
|
|
/**
|
|
@brief Writes out the data in the buffer to the card if it has not been
|
|
flushed already. If writing continually, this will also advance to
|
|
the next block in the sequence.
|
|
@details This is to be used in conjunction with sd_spi_write or
|
|
sd_spi_continuous_write.
|
|
|
|
@return An error code as defined by one of the SD_ERR_* definitions.
|
|
*/
|
|
int8_t
|
|
sd_spi_flush(
|
|
void
|
|
);
|
|
|
|
/**
|
|
@brief Notifies the card to prepare for sequential writing starting at the
|
|
specified block address.
|
|
@details A sequential write must be stopped by calling
|
|
sd_spi_write_continuous_stop(). When buffering is enabled, use
|
|
sd_spi_write_continuous() in conjunction with sd_spi_write_next().
|
|
If buffering is disabled, use sd_spi_write_continuous() to write out
|
|
the data and it will advance to the next block in the sequence
|
|
automatically.
|
|
|
|
@param start_block_address The address of the first block in the
|
|
sequence.
|
|
@param num_blocks_pre_erase (Optional) The number of block to pre-erase
|
|
to potentially speed up writing. It can be
|
|
set to 0 if the number if the number of
|
|
blocks is unknown or an estimate can be
|
|
given since it does not have to be exact.
|
|
|
|
@return An error code as defined by one of the SD_ERR_* definitions.
|
|
*/
|
|
int8_t
|
|
sd_spi_write_continuous_start(
|
|
uint32_t start_block_address,
|
|
uint32_t num_blocks_pre_erase
|
|
);
|
|
|
|
/**
|
|
@brief Writes data to the current block in the sequence on the card.
|
|
@details If buffering is enabled, the data will be stored in the buffer which
|
|
has been cleared with zeros (current data in the block on the card
|
|
is not pre-buffered). The data will be only written out to the card
|
|
when sd_spi_write_continuous_next() or sd_spi_flush() is explicitly
|
|
called. If the buffering is not enabled, the card will write out the
|
|
data and advance to the next block in the sequence. If the number of
|
|
bytes given is less than 512, the rest of the block will be padded
|
|
with zeros.
|
|
|
|
@param[in] data An array of data / an address to the data in
|
|
memory.
|
|
@param number_of_bytes The size of the data in bytes.
|
|
@param byte_offset The byte offset of where to start writing in the
|
|
block.
|
|
|
|
@return An error code as defined by one of the SD_ERR_* definitions.
|
|
*/
|
|
int8_t
|
|
sd_spi_write_continuous(
|
|
void *data,
|
|
uint16_t number_of_bytes,
|
|
uint16_t byte_offset
|
|
);
|
|
|
|
/**
|
|
@brief Used only when buffering is enabled to write out the data in the
|
|
buffer to the card for continuous writing and advancing to the
|
|
next block in the sequence.
|
|
@details If buffering is not enabled, only use sd_spi_write_continuous().
|
|
|
|
@return An error code as defined by one of the SD_ERR_* definitions.
|
|
*/
|
|
int8_t
|
|
sd_spi_write_continuous_next(
|
|
void
|
|
);
|
|
|
|
/**
|
|
@brief Notifies the card to stop sequential writing and flushes the buffer
|
|
to the card if buffering is enabled.
|
|
@details This may take some time since it waits for the card to complete the
|
|
write.
|
|
|
|
@return An error code as defined by one of the SD_ERR_* definitions.
|
|
*/
|
|
int8_t
|
|
sd_spi_write_continuous_stop(
|
|
void
|
|
);
|
|
|
|
/**
|
|
@brief Reads data from a block on the card.
|
|
@details If buffering is enabled, this will write in the block to the buffer.
|
|
Otherwise, the device will have to read in the data from the card
|
|
on every call (it has to read a 512 byte block only the relevant
|
|
data will be kept).
|
|
|
|
@param block_address The address of the block on the card.
|
|
@param[out] data_buffer A location in memory to write the data to.
|
|
@param number_of_bytes The number of bytes to read.
|
|
@param byte_offset The byte offset of where to start reading in the
|
|
block.
|
|
|
|
@return An error code as defined by one of the SD_ERR_* definitions.
|
|
*/
|
|
int8_t
|
|
sd_spi_read(
|
|
uint32_t block_address,
|
|
void *data_buffer,
|
|
uint16_t number_of_bytes,
|
|
uint16_t byte_offset
|
|
);
|
|
|
|
/**
|
|
@brief Notifies the card to prepare for sequential reading starting at the
|
|
specified block address.
|
|
@details A sequential read must be stopped by calling
|
|
sd_spi_read_continuous_stop(). When buffering is enabled, use
|
|
sd_spi_read_continuous() in conjunction with sd_spi_read_next().
|
|
If buffering is disabled, use sd_spi_read_block() to read in data
|
|
and advance to the next block in the sequence.
|
|
|
|
@param start_block_address The address of the first block in the
|
|
sequence.
|
|
|
|
@return An error code as defined by one of the SD_ERR_* definitions.
|
|
*/
|
|
int8_t
|
|
sd_spi_read_continuous_start(
|
|
uint32_t start_block_address
|
|
);
|
|
|
|
/**
|
|
@brief Reads in data from the current block in the sequence on the card.
|
|
@details If buffering is enabled, the block will be stored in the buffer.
|
|
To advance to the next block, sd_spi_read_continuous_next() must
|
|
be explicitly called. If the buffering is not enabled, the card will
|
|
read in the data and advance to the next block in the sequence.
|
|
|
|
@param[out] data_buffer A location in memory to write the data to.
|
|
@param number_of_bytes The number of bytes to read.
|
|
@param byte_offset The byte offset of where to start reading in the
|
|
block.
|
|
|
|
@return An error code as defined by one of the SD_ERR_* definitions.
|
|
*/
|
|
int8_t
|
|
sd_spi_read_continuous(
|
|
void *data_buffer,
|
|
uint16_t number_of_bytes,
|
|
uint16_t byte_offset
|
|
);
|
|
|
|
/**
|
|
@brief Used only when buffering is enabled to advancing to the
|
|
next block in the sequence.
|
|
@details If buffering is not enabled, only use sd_spi_read_continuous().
|
|
|
|
@return An error code as defined by one of the SD_ERR_* definitions.
|
|
*/
|
|
int8_t
|
|
sd_spi_read_continuous_next(
|
|
void
|
|
);
|
|
|
|
/**
|
|
@brief Notifies the card to stop sequential reading.
|
|
|
|
@return An error code as defined by one of the SD_ERR_* definitions.
|
|
*/
|
|
int8_t
|
|
sd_spi_read_continuous_stop(
|
|
void
|
|
);
|
|
|
|
/**
|
|
@brief Erases all the blocks on the card.
|
|
@details All of the bits will be set with the default value of 0 or 1
|
|
HC depending on the card.
|
|
|
|
@return An error code as defined by one of the SD_ERR_* definitions.
|
|
*/
|
|
int8_t
|
|
sd_spi_erase_all(
|
|
void
|
|
);
|
|
|
|
/**
|
|
@brief Erases the given sequence of blocks on the card.
|
|
@details All of the bits will be set with the default value of 0 or 1
|
|
depending on the card.
|
|
|
|
@param start_block_address The address of the first block in the
|
|
sequence.
|
|
@param end_block_address The address of the last block in the
|
|
sequence.
|
|
|
|
@return An error code as defined by one of the SD_ERR_* definitions.
|
|
*/
|
|
int8_t
|
|
sd_spi_erase_blocks(
|
|
uint32_t start_block_address,
|
|
uint32_t end_block_address
|
|
);
|
|
|
|
/**
|
|
@brief Gets the number of blocks the card has. Blocks are 512 bytes.
|
|
|
|
@return An error code as defined by one of the SD_ERR_* definitions.
|
|
*/
|
|
uint32_t
|
|
sd_spi_card_size(
|
|
void
|
|
);
|
|
|
|
/**
|
|
@brief Gets the type of the card. 1 = SD1, 2 = SD2, 3 = SDHC, and 4 = MMC.
|
|
|
|
@return An error code as defined by one of the SD_ERR_* definitions.
|
|
*/
|
|
uint8_t
|
|
sd_spi_card_type(
|
|
void
|
|
);
|
|
|
|
/**
|
|
@brief Reads the Card Identification (CID) register on the card.
|
|
@details Information is stored in the sd_spi_cid_t structure. The details of
|
|
the structure can be found in sd_spi_info.h.
|
|
|
|
@return An error code as defined by one of the SD_ERR_* definitions.
|
|
*/
|
|
int8_t
|
|
sd_spi_read_cid_register(
|
|
sd_spi_cid_t *cid
|
|
);
|
|
|
|
/**
|
|
@brief Reads the Card Specific Data (CSD) register on the card.
|
|
@details Information is stored in the sd_spi_csd_t structure. The details of
|
|
the structure can be found in sd_spi_info.h.
|
|
|
|
@return An error code as defined by one of the SD_ERR_* definitions.
|
|
*/
|
|
int8_t
|
|
sd_spi_read_csd_register(
|
|
sd_spi_csd_t *csd
|
|
);
|
|
|
|
/**
|
|
@brief Returns the first error code (if any) found in the R2 response on
|
|
from the card.
|
|
|
|
@return An error code as defined by one of the SD_ERR_* definitions.
|
|
*/
|
|
int8_t
|
|
sd_spi_card_status(
|
|
void
|
|
);
|
|
|
|
/**
|
|
@brief Getter for the address of the block that is currently buffered.
|
|
|
|
@return Current buffered block address.
|
|
*/
|
|
uint32_t
|
|
sd_spi_current_buffered_block(
|
|
void
|
|
);
|
|
|
|
#if defined(__cplusplus)
|
|
}
|
|
#endif
|
|
|
|
#endif /* SD_SPI_H_ */
|