mirror of https://github.com/ARMmbed/mbed-os.git
bd: Adopted the block device api in the SDBlockDevice
parent
4633d3129d
commit
03a332c5eb
|
|
@ -58,13 +58,13 @@ public:
|
|||
*
|
||||
* @return 0 on success or a negative error code on failure
|
||||
*/
|
||||
virtual bd_error_t init() = 0;
|
||||
virtual bd_error_t init();
|
||||
|
||||
/** Deinitialize a block device
|
||||
*
|
||||
* @return 0 on success or a negative error code on failure
|
||||
*/
|
||||
virtual bd_error_t deinit() = 0;
|
||||
virtual bd_error_t deinit();
|
||||
|
||||
/** Read blocks from a block device
|
||||
*
|
||||
|
|
@ -73,7 +73,7 @@ public:
|
|||
* @param size Size to read in bytes, must be a multiple of read block size
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
virtual bd_error_t read(void *buffer, bd_addr_t addr, bd_size_t size) = 0;
|
||||
virtual bd_error_t read(void *buffer, bd_addr_t addr, bd_size_t size);
|
||||
|
||||
/** Program blocks to a block device
|
||||
*
|
||||
|
|
|
|||
|
|
@ -116,15 +116,16 @@
|
|||
/* If the target has no SPI support then SDCard is not supported */
|
||||
#ifdef DEVICE_SPI
|
||||
|
||||
#include "SDFileSystem.h"
|
||||
#include "SDBlockDevice.h"
|
||||
#include "mbed_debug.h"
|
||||
|
||||
#define SD_COMMAND_TIMEOUT 5000
|
||||
|
||||
#define SD_DBG 0
|
||||
|
||||
SDFileSystem::SDFileSystem(PinName mosi, PinName miso, PinName sclk, PinName cs, const char* name) :
|
||||
FATFileSystem(name), _spi(mosi, miso, sclk), _cs(cs), _is_initialized(0) {
|
||||
SDBlockDevice::SDBlockDevice(PinName mosi, PinName miso, PinName sclk, PinName cs)
|
||||
: _spi(mosi, miso, sclk), _cs(cs), _is_initialized(0)
|
||||
{
|
||||
_cs = 1;
|
||||
|
||||
// Set default to 100kHz for initialisation and 1MHz for data transfer
|
||||
|
|
@ -132,6 +133,13 @@ SDFileSystem::SDFileSystem(PinName mosi, PinName miso, PinName sclk, PinName cs,
|
|||
_transfer_sck = 1000000;
|
||||
}
|
||||
|
||||
SDBlockDevice::~SDBlockDevice()
|
||||
{
|
||||
if (_is_initialized) {
|
||||
deinit();
|
||||
}
|
||||
}
|
||||
|
||||
#define R1_IDLE_STATE (1 << 0)
|
||||
#define R1_ERASE_RESET (1 << 1)
|
||||
#define R1_ILLEGAL_COMMAND (1 << 2)
|
||||
|
|
@ -150,8 +158,9 @@ SDFileSystem::SDFileSystem(PinName mosi, PinName miso, PinName sclk, PinName cs,
|
|||
#define SDCARD_V2 2
|
||||
#define SDCARD_V2HC 3
|
||||
|
||||
int SDFileSystem::initialise_card() {
|
||||
_dbg = SD_DBG;
|
||||
bd_error_t SDBlockDevice::_initialise_card()
|
||||
{
|
||||
_dbg = SD_DBG;
|
||||
// Set to SCK for initialisation, and clock card with cs = 1
|
||||
_spi.lock();
|
||||
_spi.frequency(_init_sck);
|
||||
|
|
@ -164,36 +173,38 @@ int SDFileSystem::initialise_card() {
|
|||
// send CMD0, should return with all zeros except IDLE STATE set (bit 0)
|
||||
if (_cmd(0, 0) != R1_IDLE_STATE) {
|
||||
debug_if(_dbg, "No disk, or could not put SD card in to SPI idle state\n");
|
||||
return SDCARD_FAIL;
|
||||
return BD_ERROR_NO_DEVICE;
|
||||
}
|
||||
|
||||
// send CMD8 to determine whther it is ver 2.x
|
||||
int r = _cmd8();
|
||||
if (r == R1_IDLE_STATE) {
|
||||
return initialise_card_v2();
|
||||
return _initialise_card_v2();
|
||||
} else if (r == (R1_IDLE_STATE | R1_ILLEGAL_COMMAND)) {
|
||||
return initialise_card_v1();
|
||||
return _initialise_card_v1();
|
||||
} else {
|
||||
debug_if(_dbg, "Not in idle state after sending CMD8 (not an SD card?)\n");
|
||||
return SDCARD_FAIL;
|
||||
return BD_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
int SDFileSystem::initialise_card_v1() {
|
||||
bd_error_t SDBlockDevice::_initialise_card_v1()
|
||||
{
|
||||
for (int i = 0; i < SD_COMMAND_TIMEOUT; i++) {
|
||||
_cmd(55, 0);
|
||||
if (_cmd(41, 0) == 0) {
|
||||
cdv = 512;
|
||||
_block_size = 512;
|
||||
debug_if(_dbg, "\n\rInit: SEDCARD_V1\n\r");
|
||||
return SDCARD_V1;
|
||||
return BD_ERROR_OK;
|
||||
}
|
||||
}
|
||||
|
||||
debug_if(_dbg, "Timeout waiting for v1.x card\n");
|
||||
return SDCARD_FAIL;
|
||||
return BD_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
int SDFileSystem::initialise_card_v2() {
|
||||
bd_error_t SDBlockDevice::_initialise_card_v2()
|
||||
{
|
||||
for (int i = 0; i < SD_COMMAND_TIMEOUT; i++) {
|
||||
wait_ms(50);
|
||||
_cmd58();
|
||||
|
|
@ -201,22 +212,24 @@ int SDFileSystem::initialise_card_v2() {
|
|||
if (_cmd(41, 0x40000000) == 0) {
|
||||
_cmd58();
|
||||
debug_if(_dbg, "\n\rInit: SDCARD_V2\n\r");
|
||||
cdv = 1;
|
||||
return SDCARD_V2;
|
||||
_block_size = 1;
|
||||
return BD_ERROR_OK;
|
||||
}
|
||||
}
|
||||
|
||||
debug_if(_dbg, "Timeout waiting for v2.x card\n");
|
||||
return SDCARD_FAIL;
|
||||
return BD_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
int SDFileSystem::disk_initialize() {
|
||||
lock();
|
||||
_is_initialized = initialise_card();
|
||||
if (_is_initialized == 0) {
|
||||
bd_error_t SDBlockDevice::init()
|
||||
{
|
||||
_lock.lock();
|
||||
bd_error_t err = _initialise_card();
|
||||
_is_initialized = (err == BD_ERROR_OK);
|
||||
if (!_is_initialized) {
|
||||
debug_if(_dbg, "Fail to initialize card\n");
|
||||
unlock();
|
||||
return 1;
|
||||
_lock.unlock();
|
||||
return err;
|
||||
}
|
||||
debug_if(_dbg, "init card = %d\n", _is_initialized);
|
||||
_sectors = _sd_sectors();
|
||||
|
|
@ -224,85 +237,119 @@ int SDFileSystem::disk_initialize() {
|
|||
// Set block length to 512 (CMD16)
|
||||
if (_cmd(16, 512) != 0) {
|
||||
debug_if(_dbg, "Set 512-byte block timed out\n");
|
||||
unlock();
|
||||
return 1;
|
||||
_lock.unlock();
|
||||
return BD_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
// Set SCK for data transfer
|
||||
_spi.frequency(_transfer_sck);
|
||||
unlock();
|
||||
_lock.unlock();
|
||||
return BD_ERROR_OK;
|
||||
}
|
||||
|
||||
bd_error_t SDBlockDevice::deinit()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SDFileSystem::disk_write(const uint8_t* buffer, uint32_t block_number, uint32_t count) {
|
||||
lock();
|
||||
if (!_is_initialized) {
|
||||
unlock();
|
||||
return -1;
|
||||
bd_error_t SDBlockDevice::program(const void *b, bd_addr_t addr, bd_size_t size)
|
||||
{
|
||||
if (!is_valid_program(addr, size)) {
|
||||
return BD_ERROR_PARAMETER;
|
||||
}
|
||||
|
||||
for (uint32_t b = block_number; b < block_number + count; b++) {
|
||||
_lock.lock();
|
||||
if (!_is_initialized) {
|
||||
_lock.unlock();
|
||||
return BD_ERROR_NO_INIT;
|
||||
}
|
||||
|
||||
const uint8_t *buffer = static_cast<const uint8_t*>(b);
|
||||
while (size > 0) {
|
||||
bd_addr_t block = addr / 512;
|
||||
// set write address for single block (CMD24)
|
||||
if (_cmd(24, b * cdv) != 0) {
|
||||
unlock();
|
||||
return 1;
|
||||
if (_cmd(24, block * _block_size) != 0) {
|
||||
_lock.unlock();
|
||||
return BD_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
// send the data block
|
||||
_write(buffer, 512);
|
||||
buffer += 512;
|
||||
addr += 512;
|
||||
size -= 512;
|
||||
}
|
||||
|
||||
unlock();
|
||||
_lock.unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SDFileSystem::disk_read(uint8_t* buffer, uint32_t block_number, uint32_t count) {
|
||||
lock();
|
||||
if (!_is_initialized) {
|
||||
unlock();
|
||||
return -1;
|
||||
bd_error_t SDBlockDevice::read(void *b, bd_addr_t addr, bd_size_t size)
|
||||
{
|
||||
if (!is_valid_read(addr, size)) {
|
||||
return BD_ERROR_PARAMETER;
|
||||
}
|
||||
|
||||
for (uint32_t b = block_number; b < block_number + count; b++) {
|
||||
_lock.lock();
|
||||
if (!_is_initialized) {
|
||||
_lock.unlock();
|
||||
return BD_ERROR_PARAMETER;
|
||||
}
|
||||
|
||||
uint8_t *buffer = static_cast<uint8_t *>(b);
|
||||
while (size > 0) {
|
||||
bd_addr_t block = addr / 512;
|
||||
// set read address for single block (CMD17)
|
||||
if (_cmd(17, b * cdv) != 0) {
|
||||
unlock();
|
||||
return 1;
|
||||
if (_cmd(17, block * _block_size) != 0) {
|
||||
_lock.unlock();
|
||||
return BD_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
// receive the data
|
||||
_read(buffer, 512);
|
||||
buffer += 512;
|
||||
addr += 512;
|
||||
size -= 512;
|
||||
}
|
||||
|
||||
unlock();
|
||||
_lock.unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SDFileSystem::disk_status() {
|
||||
lock();
|
||||
// FATFileSystem::disk_status() returns 0 when initialized
|
||||
int ret = _is_initialized ? 0 : 1;
|
||||
unlock();
|
||||
return ret;
|
||||
bd_error_t SDBlockDevice::erase(bd_addr_t addr, bd_size_t size)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SDFileSystem::disk_sync() { return 0; }
|
||||
uint32_t SDFileSystem::disk_sectors() {
|
||||
lock();
|
||||
uint32_t sectors = _sectors;
|
||||
unlock();
|
||||
return sectors;
|
||||
bd_size_t SDBlockDevice::get_read_size()
|
||||
{
|
||||
return 512;
|
||||
}
|
||||
|
||||
void SDFileSystem::debug(bool dbg){
|
||||
bd_size_t SDBlockDevice::get_program_size()
|
||||
{
|
||||
return 512;
|
||||
}
|
||||
|
||||
bd_size_t SDBlockDevice::get_erase_size()
|
||||
{
|
||||
return 512;
|
||||
}
|
||||
|
||||
bd_size_t SDBlockDevice::size()
|
||||
{
|
||||
_lock.lock();
|
||||
bd_size_t sectors = _sectors;
|
||||
_lock.unlock();
|
||||
return 512*sectors;
|
||||
}
|
||||
|
||||
void SDBlockDevice::debug(bool dbg)
|
||||
{
|
||||
_dbg = dbg;
|
||||
}
|
||||
|
||||
|
||||
// PRIVATE FUNCTIONS
|
||||
int SDFileSystem::_cmd(int cmd, int arg) {
|
||||
int SDBlockDevice::_cmd(int cmd, int arg) {
|
||||
_spi.lock();
|
||||
_cs = 0;
|
||||
|
||||
|
|
@ -329,7 +376,7 @@ int SDFileSystem::_cmd(int cmd, int arg) {
|
|||
_spi.unlock();
|
||||
return -1; // timeout
|
||||
}
|
||||
int SDFileSystem::_cmdx(int cmd, int arg) {
|
||||
int SDBlockDevice::_cmdx(int cmd, int arg) {
|
||||
_spi.lock();
|
||||
_cs = 0;
|
||||
|
||||
|
|
@ -357,7 +404,7 @@ int SDFileSystem::_cmdx(int cmd, int arg) {
|
|||
}
|
||||
|
||||
|
||||
int SDFileSystem::_cmd58() {
|
||||
int SDBlockDevice::_cmd58() {
|
||||
_spi.lock();
|
||||
_cs = 0;
|
||||
int arg = 0;
|
||||
|
|
@ -390,7 +437,7 @@ int SDFileSystem::_cmd58() {
|
|||
return -1; // timeout
|
||||
}
|
||||
|
||||
int SDFileSystem::_cmd8() {
|
||||
int SDBlockDevice::_cmd8() {
|
||||
_spi.lock();
|
||||
_cs = 0;
|
||||
|
||||
|
|
@ -422,7 +469,7 @@ int SDFileSystem::_cmd8() {
|
|||
return -1; // timeout
|
||||
}
|
||||
|
||||
int SDFileSystem::_read(uint8_t *buffer, uint32_t length) {
|
||||
int SDBlockDevice::_read(uint8_t *buffer, uint32_t length) {
|
||||
_spi.lock();
|
||||
_cs = 0;
|
||||
|
||||
|
|
@ -442,7 +489,7 @@ int SDFileSystem::_read(uint8_t *buffer, uint32_t length) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int SDFileSystem::_write(const uint8_t*buffer, uint32_t length) {
|
||||
int SDBlockDevice::_write(const uint8_t*buffer, uint32_t length) {
|
||||
_spi.lock();
|
||||
_cs = 0;
|
||||
|
||||
|
|
@ -488,7 +535,7 @@ static uint32_t ext_bits(unsigned char *data, int msb, int lsb) {
|
|||
return bits;
|
||||
}
|
||||
|
||||
uint32_t SDFileSystem::_sd_sectors() {
|
||||
uint32_t SDBlockDevice::_sd_sectors() {
|
||||
uint32_t c_size, c_size_mult, read_bl_len;
|
||||
uint32_t block_len, mult, blocknr, capacity;
|
||||
uint32_t hc_c_size;
|
||||
|
|
@ -515,7 +562,7 @@ uint32_t SDFileSystem::_sd_sectors() {
|
|||
|
||||
switch (csd_structure) {
|
||||
case 0:
|
||||
cdv = 512;
|
||||
_block_size = 512;
|
||||
c_size = ext_bits(csd, 73, 62);
|
||||
c_size_mult = ext_bits(csd, 49, 47);
|
||||
read_bl_len = ext_bits(csd, 83, 80);
|
||||
|
|
@ -525,11 +572,11 @@ uint32_t SDFileSystem::_sd_sectors() {
|
|||
blocknr = (c_size + 1) * mult;
|
||||
capacity = blocknr * block_len;
|
||||
blocks = capacity / 512;
|
||||
debug_if(_dbg, "\n\rSDCard\n\rc_size: %d \n\rcapacity: %ld \n\rsectors: %lld\n\r", c_size, capacity, blocks);
|
||||
debug_if(_dbg, "\n\rSDBlockDevice\n\rc_size: %d \n\rcapacity: %ld \n\rsectors: %lld\n\r", c_size, capacity, blocks);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
cdv = 1;
|
||||
_block_size = 1;
|
||||
hc_c_size = ext_bits(csd, 63, 48);
|
||||
blocks = (hc_c_size+1)*1024;
|
||||
debug_if(_dbg, "\n\rSDHC Card \n\rhc_c_size: %d\n\rcapacity: %lld \n\rsectors: %lld\n\r", hc_c_size, blocks*512, blocks);
|
||||
|
|
@ -0,0 +1,158 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2006-2012 ARM Limited
|
||||
*
|
||||
* 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 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.
|
||||
*/
|
||||
#ifndef MBED_SD_BLOCK_DEVICE_H
|
||||
#define MBED_SD_BLOCK_DEVICE_H
|
||||
|
||||
/* If the target has no SPI support then SDCard is not supported */
|
||||
#ifdef DEVICE_SPI
|
||||
|
||||
#include "BlockDevice.h"
|
||||
#include "mbed.h"
|
||||
|
||||
|
||||
/** Access an SD Card using SPI
|
||||
*
|
||||
* @code
|
||||
* #include "mbed.h"
|
||||
* #include "SDBlockDevice.h"
|
||||
*
|
||||
* SDBlockDevice sd(p5, p6, p7, p12); // mosi, miso, sclk, cs
|
||||
* uint8_t block[512] = "Hello World!\n";
|
||||
*
|
||||
* int main() {
|
||||
* sd.init();
|
||||
* sd.write(block, 0, 512);
|
||||
* sd.read(block, 0, 512);
|
||||
* printf("%s", block);
|
||||
* sd.deinit();
|
||||
* }
|
||||
*/
|
||||
class SDBlockDevice : public BlockDevice {
|
||||
public:
|
||||
/** Lifetime of an SD card
|
||||
*/
|
||||
SDBlockDevice(PinName mosi, PinName miso, PinName sclk, PinName cs);
|
||||
virtual ~SDBlockDevice();
|
||||
|
||||
/** Initialize a block device
|
||||
*
|
||||
* @return 0 on success or a negative error code on failure
|
||||
*/
|
||||
virtual bd_error_t init();
|
||||
|
||||
/** Deinitialize a block device
|
||||
*
|
||||
* @return 0 on success or a negative error code on failure
|
||||
*/
|
||||
virtual bd_error_t deinit();
|
||||
|
||||
/** Read blocks from a block device
|
||||
*
|
||||
* @param buffer Buffer to write blocks to
|
||||
* @param addr Address of block to begin reading from
|
||||
* @param size Size to read in bytes, must be a multiple of read block size
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
virtual bd_error_t read(void *buffer, bd_addr_t addr, bd_size_t size);
|
||||
|
||||
/** Program blocks to a block device
|
||||
*
|
||||
* The blocks must have been erased prior to being programmed
|
||||
*
|
||||
* @param buffer Buffer of data to write to blocks
|
||||
* @param addr Address of block to begin writing to
|
||||
* @param size Size to write in bytes, must be a multiple of program block size
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
virtual bd_error_t program(const void *buffer, bd_addr_t addr, bd_size_t size);
|
||||
|
||||
/** Erase blocks on a block device
|
||||
*
|
||||
* The state of an erased block is undefined until it has been programmed
|
||||
*
|
||||
* @param addr Address of block to begin erasing
|
||||
* @param size Size to erase in bytes, must be a multiple of erase block size
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
virtual bd_error_t erase(bd_addr_t addr, bd_size_t size);
|
||||
|
||||
/** Get the size of a readable block
|
||||
*
|
||||
* @return Size of a readable block in bytes
|
||||
*/
|
||||
virtual bd_size_t get_read_size();
|
||||
|
||||
/** Get the size of a programable block
|
||||
*
|
||||
* @return Size of a programable block in bytes
|
||||
* @note Must be a multiple of the read size
|
||||
*/
|
||||
virtual bd_size_t get_program_size();
|
||||
|
||||
/** Get the size of a eraseable block
|
||||
*
|
||||
* @return Size of a eraseable block in bytes
|
||||
* @note Must be a multiple of the program size
|
||||
*/
|
||||
virtual bd_size_t get_erase_size();
|
||||
|
||||
/** Get the total size of the underlying device
|
||||
*
|
||||
* @return Size of the underlying device in bytes
|
||||
*/
|
||||
virtual bd_size_t size();
|
||||
|
||||
/** Enable or disable debugging
|
||||
*
|
||||
* @param State of debugging
|
||||
*/
|
||||
virtual void debug(bool dbg);
|
||||
|
||||
private:
|
||||
int _cmd(int cmd, int arg);
|
||||
int _cmdx(int cmd, int arg);
|
||||
int _cmd8();
|
||||
int _cmd58();
|
||||
bd_error_t _initialise_card();
|
||||
bd_error_t _initialise_card_v1();
|
||||
bd_error_t _initialise_card_v2();
|
||||
|
||||
int _read(uint8_t * buffer, uint32_t length);
|
||||
int _write(const uint8_t *buffer, uint32_t length);
|
||||
uint32_t _sd_sectors();
|
||||
uint32_t _sectors;
|
||||
|
||||
uint32_t _init_sck;
|
||||
uint32_t _transfer_sck;
|
||||
|
||||
SPI _spi;
|
||||
DigitalOut _cs;
|
||||
unsigned _block_size;
|
||||
bool _is_initialized;
|
||||
bool _dbg;
|
||||
Mutex _lock;
|
||||
};
|
||||
|
||||
|
||||
#endif /* DEVICE_SPI */
|
||||
|
||||
#endif /* MBED_SD_BLOCK_DEVICE_H */
|
||||
|
|
@ -1,98 +0,0 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2006-2012 ARM Limited
|
||||
*
|
||||
* 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 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.
|
||||
*/
|
||||
#ifndef MBED_SDFILESYSTEM_H
|
||||
#define MBED_SDFILESYSTEM_H
|
||||
|
||||
/* If the target has no SPI support then SDCard is not supported */
|
||||
#ifdef DEVICE_SPI
|
||||
|
||||
#include "mbed.h"
|
||||
#include "FATFileSystem.h"
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
|
||||
/** Access the filesystem on an SD Card using SPI
|
||||
*
|
||||
* @code
|
||||
* #include "mbed.h"
|
||||
* #include "SDFileSystem.h"
|
||||
*
|
||||
* SDFileSystem sd(p5, p6, p7, p12, "sd"); // mosi, miso, sclk, cs
|
||||
*
|
||||
* int main() {
|
||||
* FILE *fp = fopen("/sd/myfile.txt", "w");
|
||||
* fprintf(fp, "Hello World!\n");
|
||||
* fclose(fp);
|
||||
* }
|
||||
*/
|
||||
class SDFileSystem : public FATFileSystem {
|
||||
public:
|
||||
|
||||
/** Create the File System for accessing an SD Card using SPI
|
||||
*
|
||||
* @param mosi SPI mosi pin connected to SD Card
|
||||
* @param miso SPI miso pin conencted to SD Card
|
||||
* @param sclk SPI sclk pin connected to SD Card
|
||||
* @param cs DigitalOut pin used as SD Card chip select
|
||||
* @param name The name used to access the virtual filesystem
|
||||
*/
|
||||
SDFileSystem(PinName mosi, PinName miso, PinName sclk, PinName cs, const char* name);
|
||||
virtual int disk_initialize();
|
||||
virtual int disk_status();
|
||||
virtual int disk_read(uint8_t* buffer, uint32_t block_number, uint32_t count);
|
||||
virtual int disk_write(const uint8_t* buffer, uint32_t block_number, uint32_t count);
|
||||
virtual int disk_sync();
|
||||
virtual uint32_t disk_sectors();
|
||||
void debug(bool dbg);
|
||||
|
||||
protected:
|
||||
|
||||
int _cmd(int cmd, int arg);
|
||||
int _cmdx(int cmd, int arg);
|
||||
int _cmd8();
|
||||
int _cmd58();
|
||||
int initialise_card();
|
||||
int initialise_card_v1();
|
||||
int initialise_card_v2();
|
||||
|
||||
int _read(uint8_t * buffer, uint32_t length);
|
||||
int _write(const uint8_t *buffer, uint32_t length);
|
||||
uint32_t _sd_sectors();
|
||||
uint32_t _sectors;
|
||||
|
||||
void set_init_sck(uint32_t sck) { _init_sck = sck; }
|
||||
// Note: The highest SPI clock rate is 20 MHz for MMC and 25 MHz for SD
|
||||
void set_transfer_sck(uint32_t sck) { _transfer_sck = sck; }
|
||||
uint32_t _init_sck;
|
||||
uint32_t _transfer_sck;
|
||||
|
||||
SPI _spi;
|
||||
DigitalOut _cs;
|
||||
int cdv;
|
||||
int _is_initialized;
|
||||
bool _dbg;
|
||||
};
|
||||
|
||||
#endif /* DEVICE_SPI */
|
||||
|
||||
#endif /* MBED_SDFILESYSTEM_H */
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2017 ARM Limited
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#include "mbed.h"
|
||||
#include "greentea-client/test_env.h"
|
||||
#include "unity.h"
|
||||
#include "utest.h"
|
||||
|
||||
#include "SDBlockDevice.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
using namespace utest::v1;
|
||||
|
||||
#ifndef SD_INSTALLED
|
||||
#define SD_INSTALLED false
|
||||
#endif
|
||||
|
||||
#ifndef SD_PINS
|
||||
#if defined(TARGET_K64F)
|
||||
#define SD_PINS PTE3, PTE1, PTE2, PTE4
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !SD_INSTALLED
|
||||
#error [NOT_SUPPORTED] SD card required
|
||||
#endif
|
||||
|
||||
#define BLOCK_SIZE 512
|
||||
uint8_t write_block[BLOCK_SIZE];
|
||||
uint8_t read_block[BLOCK_SIZE];
|
||||
|
||||
// Simple test which read/writes a block
|
||||
void test_read_write() {
|
||||
SDBlockDevice bd(SD_PINS);
|
||||
|
||||
int err = bd.init();
|
||||
TEST_ASSERT_EQUAL(0, err);
|
||||
|
||||
printf("read size: %llu\r\n", bd.get_read_size());
|
||||
printf("program size: %llu\r\n", bd.get_program_size());
|
||||
printf("erase size: %llu\r\n", bd.get_erase_size());
|
||||
|
||||
// Fill with random sequence
|
||||
srand(1);
|
||||
for (int i = 0; i < BLOCK_SIZE; i++) {
|
||||
write_block[i] = 0xff & rand();
|
||||
}
|
||||
|
||||
// Write, sync, and read the block
|
||||
err = bd.write(write_block, 0, BLOCK_SIZE);
|
||||
TEST_ASSERT_EQUAL(0, err);
|
||||
|
||||
err = bd.read(read_block, 0, BLOCK_SIZE);
|
||||
TEST_ASSERT_EQUAL(0, err);
|
||||
|
||||
// Check that the data was unmodified
|
||||
srand(1);
|
||||
for (int i = 0; i < BLOCK_SIZE; i++) {
|
||||
TEST_ASSERT_EQUAL(0xff & rand(), read_block[i]);
|
||||
}
|
||||
|
||||
err = bd.deinit();
|
||||
TEST_ASSERT_EQUAL(0, err);
|
||||
}
|
||||
|
||||
|
||||
// Test setup
|
||||
utest::v1::status_t test_setup(const size_t number_of_cases) {
|
||||
GREENTEA_SETUP(10, "default_auto");
|
||||
return verbose_test_setup_handler(number_of_cases);
|
||||
}
|
||||
|
||||
Case cases[] = {
|
||||
Case("Testing read write of a block", test_read_write),
|
||||
};
|
||||
|
||||
Specification specification(test_setup, cases);
|
||||
|
||||
int main() {
|
||||
return !Harness::run(specification);
|
||||
}
|
||||
Loading…
Reference in New Issue