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
|
* @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
|
/** Deinitialize a block device
|
||||||
*
|
*
|
||||||
* @return 0 on success or a negative error code on failure
|
* @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
|
/** 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
|
* @param size Size to read in bytes, must be a multiple of read block size
|
||||||
* @return 0 on success, negative error code on failure
|
* @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
|
/** Program blocks to a block device
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -116,15 +116,16 @@
|
||||||
/* If the target has no SPI support then SDCard is not supported */
|
/* If the target has no SPI support then SDCard is not supported */
|
||||||
#ifdef DEVICE_SPI
|
#ifdef DEVICE_SPI
|
||||||
|
|
||||||
#include "SDFileSystem.h"
|
#include "SDBlockDevice.h"
|
||||||
#include "mbed_debug.h"
|
#include "mbed_debug.h"
|
||||||
|
|
||||||
#define SD_COMMAND_TIMEOUT 5000
|
#define SD_COMMAND_TIMEOUT 5000
|
||||||
|
|
||||||
#define SD_DBG 0
|
#define SD_DBG 0
|
||||||
|
|
||||||
SDFileSystem::SDFileSystem(PinName mosi, PinName miso, PinName sclk, PinName cs, const char* name) :
|
SDBlockDevice::SDBlockDevice(PinName mosi, PinName miso, PinName sclk, PinName cs)
|
||||||
FATFileSystem(name), _spi(mosi, miso, sclk), _cs(cs), _is_initialized(0) {
|
: _spi(mosi, miso, sclk), _cs(cs), _is_initialized(0)
|
||||||
|
{
|
||||||
_cs = 1;
|
_cs = 1;
|
||||||
|
|
||||||
// Set default to 100kHz for initialisation and 1MHz for data transfer
|
// 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;
|
_transfer_sck = 1000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SDBlockDevice::~SDBlockDevice()
|
||||||
|
{
|
||||||
|
if (_is_initialized) {
|
||||||
|
deinit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#define R1_IDLE_STATE (1 << 0)
|
#define R1_IDLE_STATE (1 << 0)
|
||||||
#define R1_ERASE_RESET (1 << 1)
|
#define R1_ERASE_RESET (1 << 1)
|
||||||
#define R1_ILLEGAL_COMMAND (1 << 2)
|
#define R1_ILLEGAL_COMMAND (1 << 2)
|
||||||
|
|
@ -150,7 +158,8 @@ SDFileSystem::SDFileSystem(PinName mosi, PinName miso, PinName sclk, PinName cs,
|
||||||
#define SDCARD_V2 2
|
#define SDCARD_V2 2
|
||||||
#define SDCARD_V2HC 3
|
#define SDCARD_V2HC 3
|
||||||
|
|
||||||
int SDFileSystem::initialise_card() {
|
bd_error_t SDBlockDevice::_initialise_card()
|
||||||
|
{
|
||||||
_dbg = SD_DBG;
|
_dbg = SD_DBG;
|
||||||
// Set to SCK for initialisation, and clock card with cs = 1
|
// Set to SCK for initialisation, and clock card with cs = 1
|
||||||
_spi.lock();
|
_spi.lock();
|
||||||
|
|
@ -164,36 +173,38 @@ int SDFileSystem::initialise_card() {
|
||||||
// send CMD0, should return with all zeros except IDLE STATE set (bit 0)
|
// send CMD0, should return with all zeros except IDLE STATE set (bit 0)
|
||||||
if (_cmd(0, 0) != R1_IDLE_STATE) {
|
if (_cmd(0, 0) != R1_IDLE_STATE) {
|
||||||
debug_if(_dbg, "No disk, or could not put SD card in to SPI idle state\n");
|
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
|
// send CMD8 to determine whther it is ver 2.x
|
||||||
int r = _cmd8();
|
int r = _cmd8();
|
||||||
if (r == R1_IDLE_STATE) {
|
if (r == R1_IDLE_STATE) {
|
||||||
return initialise_card_v2();
|
return _initialise_card_v2();
|
||||||
} else if (r == (R1_IDLE_STATE | R1_ILLEGAL_COMMAND)) {
|
} else if (r == (R1_IDLE_STATE | R1_ILLEGAL_COMMAND)) {
|
||||||
return initialise_card_v1();
|
return _initialise_card_v1();
|
||||||
} else {
|
} else {
|
||||||
debug_if(_dbg, "Not in idle state after sending CMD8 (not an SD card?)\n");
|
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++) {
|
for (int i = 0; i < SD_COMMAND_TIMEOUT; i++) {
|
||||||
_cmd(55, 0);
|
_cmd(55, 0);
|
||||||
if (_cmd(41, 0) == 0) {
|
if (_cmd(41, 0) == 0) {
|
||||||
cdv = 512;
|
_block_size = 512;
|
||||||
debug_if(_dbg, "\n\rInit: SEDCARD_V1\n\r");
|
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");
|
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++) {
|
for (int i = 0; i < SD_COMMAND_TIMEOUT; i++) {
|
||||||
wait_ms(50);
|
wait_ms(50);
|
||||||
_cmd58();
|
_cmd58();
|
||||||
|
|
@ -201,22 +212,24 @@ int SDFileSystem::initialise_card_v2() {
|
||||||
if (_cmd(41, 0x40000000) == 0) {
|
if (_cmd(41, 0x40000000) == 0) {
|
||||||
_cmd58();
|
_cmd58();
|
||||||
debug_if(_dbg, "\n\rInit: SDCARD_V2\n\r");
|
debug_if(_dbg, "\n\rInit: SDCARD_V2\n\r");
|
||||||
cdv = 1;
|
_block_size = 1;
|
||||||
return SDCARD_V2;
|
return BD_ERROR_OK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
debug_if(_dbg, "Timeout waiting for v2.x card\n");
|
debug_if(_dbg, "Timeout waiting for v2.x card\n");
|
||||||
return SDCARD_FAIL;
|
return BD_ERROR_DEVICE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SDFileSystem::disk_initialize() {
|
bd_error_t SDBlockDevice::init()
|
||||||
lock();
|
{
|
||||||
_is_initialized = initialise_card();
|
_lock.lock();
|
||||||
if (_is_initialized == 0) {
|
bd_error_t err = _initialise_card();
|
||||||
|
_is_initialized = (err == BD_ERROR_OK);
|
||||||
|
if (!_is_initialized) {
|
||||||
debug_if(_dbg, "Fail to initialize card\n");
|
debug_if(_dbg, "Fail to initialize card\n");
|
||||||
unlock();
|
_lock.unlock();
|
||||||
return 1;
|
return err;
|
||||||
}
|
}
|
||||||
debug_if(_dbg, "init card = %d\n", _is_initialized);
|
debug_if(_dbg, "init card = %d\n", _is_initialized);
|
||||||
_sectors = _sd_sectors();
|
_sectors = _sd_sectors();
|
||||||
|
|
@ -224,85 +237,119 @@ int SDFileSystem::disk_initialize() {
|
||||||
// Set block length to 512 (CMD16)
|
// Set block length to 512 (CMD16)
|
||||||
if (_cmd(16, 512) != 0) {
|
if (_cmd(16, 512) != 0) {
|
||||||
debug_if(_dbg, "Set 512-byte block timed out\n");
|
debug_if(_dbg, "Set 512-byte block timed out\n");
|
||||||
unlock();
|
_lock.unlock();
|
||||||
return 1;
|
return BD_ERROR_DEVICE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set SCK for data transfer
|
// Set SCK for data transfer
|
||||||
_spi.frequency(_transfer_sck);
|
_spi.frequency(_transfer_sck);
|
||||||
unlock();
|
_lock.unlock();
|
||||||
|
return BD_ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
bd_error_t SDBlockDevice::deinit()
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SDFileSystem::disk_write(const uint8_t* buffer, uint32_t block_number, uint32_t count) {
|
bd_error_t SDBlockDevice::program(const void *b, bd_addr_t addr, bd_size_t size)
|
||||||
lock();
|
{
|
||||||
if (!_is_initialized) {
|
if (!is_valid_program(addr, size)) {
|
||||||
unlock();
|
return BD_ERROR_PARAMETER;
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
// set write address for single block (CMD24)
|
||||||
if (_cmd(24, b * cdv) != 0) {
|
if (_cmd(24, block * _block_size) != 0) {
|
||||||
unlock();
|
_lock.unlock();
|
||||||
return 1;
|
return BD_ERROR_DEVICE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// send the data block
|
// send the data block
|
||||||
_write(buffer, 512);
|
_write(buffer, 512);
|
||||||
buffer += 512;
|
buffer += 512;
|
||||||
|
addr += 512;
|
||||||
|
size -= 512;
|
||||||
}
|
}
|
||||||
|
_lock.unlock();
|
||||||
unlock();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SDFileSystem::disk_read(uint8_t* buffer, uint32_t block_number, uint32_t count) {
|
bd_error_t SDBlockDevice::read(void *b, bd_addr_t addr, bd_size_t size)
|
||||||
lock();
|
{
|
||||||
if (!_is_initialized) {
|
if (!is_valid_read(addr, size)) {
|
||||||
unlock();
|
return BD_ERROR_PARAMETER;
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
// set read address for single block (CMD17)
|
||||||
if (_cmd(17, b * cdv) != 0) {
|
if (_cmd(17, block * _block_size) != 0) {
|
||||||
unlock();
|
_lock.unlock();
|
||||||
return 1;
|
return BD_ERROR_DEVICE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// receive the data
|
// receive the data
|
||||||
_read(buffer, 512);
|
_read(buffer, 512);
|
||||||
buffer += 512;
|
buffer += 512;
|
||||||
|
addr += 512;
|
||||||
|
size -= 512;
|
||||||
}
|
}
|
||||||
|
_lock.unlock();
|
||||||
unlock();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SDFileSystem::disk_status() {
|
bd_error_t SDBlockDevice::erase(bd_addr_t addr, bd_size_t size)
|
||||||
lock();
|
{
|
||||||
// FATFileSystem::disk_status() returns 0 when initialized
|
return 0;
|
||||||
int ret = _is_initialized ? 0 : 1;
|
|
||||||
unlock();
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int SDFileSystem::disk_sync() { return 0; }
|
bd_size_t SDBlockDevice::get_read_size()
|
||||||
uint32_t SDFileSystem::disk_sectors() {
|
{
|
||||||
lock();
|
return 512;
|
||||||
uint32_t sectors = _sectors;
|
|
||||||
unlock();
|
|
||||||
return sectors;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
_dbg = dbg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// PRIVATE FUNCTIONS
|
// PRIVATE FUNCTIONS
|
||||||
int SDFileSystem::_cmd(int cmd, int arg) {
|
int SDBlockDevice::_cmd(int cmd, int arg) {
|
||||||
_spi.lock();
|
_spi.lock();
|
||||||
_cs = 0;
|
_cs = 0;
|
||||||
|
|
||||||
|
|
@ -329,7 +376,7 @@ int SDFileSystem::_cmd(int cmd, int arg) {
|
||||||
_spi.unlock();
|
_spi.unlock();
|
||||||
return -1; // timeout
|
return -1; // timeout
|
||||||
}
|
}
|
||||||
int SDFileSystem::_cmdx(int cmd, int arg) {
|
int SDBlockDevice::_cmdx(int cmd, int arg) {
|
||||||
_spi.lock();
|
_spi.lock();
|
||||||
_cs = 0;
|
_cs = 0;
|
||||||
|
|
||||||
|
|
@ -357,7 +404,7 @@ int SDFileSystem::_cmdx(int cmd, int arg) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int SDFileSystem::_cmd58() {
|
int SDBlockDevice::_cmd58() {
|
||||||
_spi.lock();
|
_spi.lock();
|
||||||
_cs = 0;
|
_cs = 0;
|
||||||
int arg = 0;
|
int arg = 0;
|
||||||
|
|
@ -390,7 +437,7 @@ int SDFileSystem::_cmd58() {
|
||||||
return -1; // timeout
|
return -1; // timeout
|
||||||
}
|
}
|
||||||
|
|
||||||
int SDFileSystem::_cmd8() {
|
int SDBlockDevice::_cmd8() {
|
||||||
_spi.lock();
|
_spi.lock();
|
||||||
_cs = 0;
|
_cs = 0;
|
||||||
|
|
||||||
|
|
@ -422,7 +469,7 @@ int SDFileSystem::_cmd8() {
|
||||||
return -1; // timeout
|
return -1; // timeout
|
||||||
}
|
}
|
||||||
|
|
||||||
int SDFileSystem::_read(uint8_t *buffer, uint32_t length) {
|
int SDBlockDevice::_read(uint8_t *buffer, uint32_t length) {
|
||||||
_spi.lock();
|
_spi.lock();
|
||||||
_cs = 0;
|
_cs = 0;
|
||||||
|
|
||||||
|
|
@ -442,7 +489,7 @@ int SDFileSystem::_read(uint8_t *buffer, uint32_t length) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SDFileSystem::_write(const uint8_t*buffer, uint32_t length) {
|
int SDBlockDevice::_write(const uint8_t*buffer, uint32_t length) {
|
||||||
_spi.lock();
|
_spi.lock();
|
||||||
_cs = 0;
|
_cs = 0;
|
||||||
|
|
||||||
|
|
@ -488,7 +535,7 @@ static uint32_t ext_bits(unsigned char *data, int msb, int lsb) {
|
||||||
return bits;
|
return bits;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t SDFileSystem::_sd_sectors() {
|
uint32_t SDBlockDevice::_sd_sectors() {
|
||||||
uint32_t c_size, c_size_mult, read_bl_len;
|
uint32_t c_size, c_size_mult, read_bl_len;
|
||||||
uint32_t block_len, mult, blocknr, capacity;
|
uint32_t block_len, mult, blocknr, capacity;
|
||||||
uint32_t hc_c_size;
|
uint32_t hc_c_size;
|
||||||
|
|
@ -515,7 +562,7 @@ uint32_t SDFileSystem::_sd_sectors() {
|
||||||
|
|
||||||
switch (csd_structure) {
|
switch (csd_structure) {
|
||||||
case 0:
|
case 0:
|
||||||
cdv = 512;
|
_block_size = 512;
|
||||||
c_size = ext_bits(csd, 73, 62);
|
c_size = ext_bits(csd, 73, 62);
|
||||||
c_size_mult = ext_bits(csd, 49, 47);
|
c_size_mult = ext_bits(csd, 49, 47);
|
||||||
read_bl_len = ext_bits(csd, 83, 80);
|
read_bl_len = ext_bits(csd, 83, 80);
|
||||||
|
|
@ -525,11 +572,11 @@ uint32_t SDFileSystem::_sd_sectors() {
|
||||||
blocknr = (c_size + 1) * mult;
|
blocknr = (c_size + 1) * mult;
|
||||||
capacity = blocknr * block_len;
|
capacity = blocknr * block_len;
|
||||||
blocks = capacity / 512;
|
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;
|
break;
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
cdv = 1;
|
_block_size = 1;
|
||||||
hc_c_size = ext_bits(csd, 63, 48);
|
hc_c_size = ext_bits(csd, 63, 48);
|
||||||
blocks = (hc_c_size+1)*1024;
|
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);
|
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