-
Notifications
You must be signed in to change notification settings - Fork 15
Sdio driver feature #4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
mathias-arm
wants to merge
23
commits into
ARMmbed:master
Choose a base branch
from
mathias-arm:sdio-driver-feature
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 22 commits
Commits
Show all changes
23 commits
Select commit
Hold shift + click to select a range
33c0600
initial commit
JojoS62 4773505
add implementation for STM32F7
JojoS62 8d1f833
changed copyright notice to standard mBed
JojoS62 088679c
changed copyright to mBed standard
JojoS62 124d0bd
code cleanup
JojoS62 26a4b7c
fiixed timeout checking
JojoS62 c0bd5f9
Restructure across the tree
eb4cb06
Rename sdio_device to sdio_api
bb0d00a
Remove tests
62eb597
API renaming
5d1d09b
Astyle fixes
orenc17 e742718
Change error type to int and use us_ticker_read
4295558
Remove timeout parameter
d5b6a08
Move documentation to sdio_api.h
7ae99b1
Compilation fix
b840f32
Minor fixes
11daa9f
Check if initialized before calling is_valid
f27d137
Add SDIO support for NXP LPC55S69
mmahadevan108 b892505
Restructure NXP implementation
744451e
Update to "new" API
a068132
Fix some warnings (tested on GCC 8)
mathias-arm c18f614
Only wait (and require USTICKER) when DEVICE_SDIO_ASYNC
mathias-arm 19bca26
Remove CamelCase symbols
mathias-arm File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
398 changes: 398 additions & 0 deletions
398
components/storage/blockdevice/COMPONENT_SDIO/SDIOBlockDevice.cpp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,398 @@ | ||
/* mbed Microcontroller Library | ||
* Copyright (c) 2019 ARM Limited | ||
* SPDX-License-Identifier: Apache-2.0 | ||
* | ||
* 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 "sdio_api.h" | ||
#if DEVICE_SDIO_ASYNC | ||
#include "us_ticker_api.h" | ||
#endif | ||
#include "SDIOBlockDevice.h" | ||
#include "platform/mbed_debug.h" | ||
|
||
using namespace mbed; | ||
|
||
#if DEVICE_SDIO | ||
|
||
/* | ||
* defines | ||
*/ | ||
|
||
#define SD_DBG 0 /*!< 1 - Enable debugging */ | ||
#define SD_CMD_TRACE 0 /*!< 1 - Enable SD command tracing */ | ||
|
||
#define SD_BLOCK_DEVICE_ERROR_WOULD_BLOCK -5001 /*!< operation would block */ | ||
#define SD_BLOCK_DEVICE_ERROR_UNSUPPORTED -5002 /*!< unsupported operation */ | ||
#define SD_BLOCK_DEVICE_ERROR_PARAMETER -5003 /*!< invalid parameter */ | ||
#define SD_BLOCK_DEVICE_ERROR_NO_INIT -5004 /*!< uninitialized */ | ||
#define SD_BLOCK_DEVICE_ERROR_NO_DEVICE -5005 /*!< device is missing or not connected */ | ||
#define SD_BLOCK_DEVICE_ERROR_WRITE_PROTECTED -5006 /*!< write protected */ | ||
#define SD_BLOCK_DEVICE_ERROR_UNUSABLE -5007 /*!< unusable card */ | ||
#define SD_BLOCK_DEVICE_ERROR_NO_RESPONSE -5008 /*!< No response from device */ | ||
#define SD_BLOCK_DEVICE_ERROR_CRC -5009 /*!< CRC error */ | ||
#define SD_BLOCK_DEVICE_ERROR_ERASE -5010 /*!< Erase error: reset/sequence */ | ||
#define SD_BLOCK_DEVICE_ERROR_WRITE -5011 /*!< SPI Write error: !SPI_DATA_ACCEPTED */ | ||
#define SD_BLOCK_DEVICE_ERROR_UNSUPPORTED_BLOCKSIZE -5012 /*!< unsupported blocksize, only 512 byte supported */ | ||
#define SD_BLOCK_DEVICE_ERROR_READBLOCKS -5013 /*!< read data blocks from SD failed */ | ||
#define SD_BLOCK_DEVICE_ERROR_WRITEBLOCKS -5014 /*!< write data blocks to SD failed */ | ||
#define SD_BLOCK_DEVICE_ERROR_ERASEBLOCKS -5015 /*!< erase data blocks to SD failed */ | ||
|
||
#define BLOCK_SIZE_HC 512 /*!< Block size supported for SD card is 512 bytes */ | ||
|
||
// Types | ||
#define SDCARD_NONE 0 /**< No card is present */ | ||
#define SDCARD_V1 1 /**< v1.x Standard Capacity */ | ||
#define SDCARD_V2 2 /**< v2.x Standard capacity SD card */ | ||
#define SDCARD_V2HC 3 /**< v2.x High capacity SD card */ | ||
#define CARD_UNKNOWN 4 /**< Unknown or unsupported card */ | ||
|
||
SDIOBlockDevice::SDIOBlockDevice(PinName cardDetect) : _cardDetect(cardDetect), | ||
_is_initialized(0), | ||
_sectors(0), | ||
_init_ref_count(0) | ||
{ | ||
// Only HC block size is supported. | ||
_block_size = BLOCK_SIZE_HC; | ||
_erase_size = BLOCK_SIZE_HC; | ||
} | ||
|
||
SDIOBlockDevice::~SDIOBlockDevice() | ||
{ | ||
if (_is_initialized) { | ||
deinit(); | ||
} | ||
} | ||
|
||
int SDIOBlockDevice::init() | ||
{ | ||
debug_if(SD_DBG, "init Card...\r\n"); | ||
|
||
lock(); | ||
|
||
if (!_is_initialized) { | ||
_init_ref_count = 0; | ||
} | ||
|
||
_init_ref_count++; | ||
|
||
if (_init_ref_count != 1) { | ||
unlock(); | ||
return BD_ERROR_OK; | ||
} | ||
|
||
if (isPresent() == false) { | ||
unlock(); | ||
return SD_BLOCK_DEVICE_ERROR_NO_DEVICE; | ||
} | ||
|
||
int status = sdio_init(); | ||
if (BD_ERROR_OK != status) { | ||
unlock(); | ||
return BD_ERROR_DEVICE_ERROR; | ||
} | ||
|
||
sdio_get_card_info(&_cardInfo); | ||
_is_initialized = true; | ||
debug_if(SD_DBG, "SD initialized: type: %lu version: %lu class: %lu\n", | ||
_cardInfo.CardType, _cardInfo.CardVersion, _cardInfo.Class); | ||
debug_if(SD_DBG, "SD size: %lu MB\n", | ||
_cardInfo.LogBlockNbr / 2 / 1024); | ||
|
||
// get sectors count from cardinfo | ||
_sectors = _cardInfo.LogBlockNbr; | ||
if (BLOCK_SIZE_HC != _cardInfo.BlockSize) { | ||
unlock(); | ||
return SD_BLOCK_DEVICE_ERROR_UNSUPPORTED_BLOCKSIZE; | ||
} | ||
|
||
unlock(); | ||
return status; | ||
} | ||
|
||
int SDIOBlockDevice::deinit() | ||
{ | ||
debug_if(SD_DBG, "deinit Card...\r\n"); | ||
lock(); | ||
|
||
if (!_is_initialized) { | ||
_init_ref_count = 0; | ||
unlock(); | ||
return BD_ERROR_OK; | ||
} | ||
|
||
_init_ref_count--; | ||
|
||
if (_init_ref_count) { | ||
unlock(); | ||
return BD_ERROR_OK; | ||
} | ||
|
||
int status = sdio_deinit(); | ||
_is_initialized = false; | ||
|
||
_sectors = 0; | ||
|
||
unlock(); | ||
return status; | ||
} | ||
|
||
int SDIOBlockDevice::read(void *buffer, bd_addr_t addr, bd_size_t size) | ||
{ | ||
int status = 0; | ||
lock(); | ||
if (isPresent() == false) { | ||
unlock(); | ||
return SD_BLOCK_DEVICE_ERROR_NO_DEVICE; | ||
} | ||
|
||
if (!_is_initialized) { | ||
unlock(); | ||
return SD_BLOCK_DEVICE_ERROR_NO_INIT; | ||
} | ||
|
||
if (!is_valid_read(addr, size)) { | ||
unlock(); | ||
return SD_BLOCK_DEVICE_ERROR_PARAMETER; | ||
} | ||
|
||
uint32_t *_buffer = static_cast<uint32_t *>(buffer); | ||
|
||
// ReadBlocks uses byte unit address | ||
// SDHC and SDXC Cards different addressing is handled in ReadBlocks() | ||
bd_addr_t blockCnt = size / _block_size; | ||
addr = addr / _block_size; | ||
|
||
#if DEVICE_SDIO_ASYNC | ||
// make sure card is ready | ||
{ | ||
uint32_t tickstart = us_ticker_read(); | ||
while (sdio_get_card_state() != SD_TRANSFER_OK) { | ||
// wait until SD ready | ||
if ((us_ticker_read() - tickstart) >= MBED_CONF_SDIO_CMD_TIMEOUT) { | ||
unlock(); | ||
return SD_BLOCK_DEVICE_ERROR_READBLOCKS; | ||
} | ||
} | ||
} | ||
|
||
// receive the data : one block/ multiple blocks is handled in ReadBlocks() | ||
status = sdio_readblocks_async(_buffer, addr, blockCnt); | ||
debug_if(SD_DBG, "ReadBlocks dbgtest addr: %lld blockCnt: %lld \n", addr, blockCnt); | ||
|
||
if (status == MSD_OK) { | ||
// wait until DMA finished | ||
uint32_t tickstart = us_ticker_read(); | ||
while (sdio_read_pending() != SD_TRANSFER_OK) { | ||
if ((us_ticker_read() - tickstart) >= MBED_CONF_SDIO_CMD_TIMEOUT) { | ||
unlock(); | ||
return SD_BLOCK_DEVICE_ERROR_READBLOCKS; | ||
} | ||
} | ||
// make sure card is ready | ||
tickstart = us_ticker_read(); | ||
while (sdio_get_card_state() != SD_TRANSFER_OK) { | ||
// wait until SD ready | ||
if ((us_ticker_read() - tickstart) >= MBED_CONF_SDIO_CMD_TIMEOUT) { | ||
unlock(); | ||
return SD_BLOCK_DEVICE_ERROR_READBLOCKS; | ||
} | ||
} | ||
} else { | ||
debug_if(SD_DBG, "ReadBlocks failed! addr: %lld blockCnt: %lld \n", addr, blockCnt); | ||
unlock(); | ||
return SD_BLOCK_DEVICE_ERROR_READBLOCKS; | ||
} | ||
#else | ||
status = sdio_readblocks(_buffer, addr, blockCnt); | ||
debug_if(SD_DBG, "ReadBlocks dbgtest addr: %lld blockCnt: %lld \n", addr, blockCnt); | ||
|
||
if (status != MSD_OK) { | ||
debug_if(SD_DBG, "ReadBlocks failed! addr: %lld blockCnt: %lld \n", addr, blockCnt); | ||
status = SD_BLOCK_DEVICE_ERROR_READBLOCKS; | ||
} | ||
#endif | ||
|
||
unlock(); | ||
return status; | ||
} | ||
|
||
int SDIOBlockDevice::program(const void *buffer, bd_addr_t addr, bd_size_t size) | ||
{ | ||
int status = 0; | ||
lock(); | ||
|
||
if (isPresent() == false) { | ||
unlock(); | ||
return SD_BLOCK_DEVICE_ERROR_NO_DEVICE; | ||
} | ||
|
||
if (!_is_initialized) { | ||
unlock(); | ||
return SD_BLOCK_DEVICE_ERROR_NO_INIT; | ||
} | ||
|
||
if (!is_valid_program(addr, size)) { | ||
unlock(); | ||
return SD_BLOCK_DEVICE_ERROR_PARAMETER; | ||
} | ||
|
||
// HAL layer uses uint32_t for addr/size | ||
uint32_t *_buffer = (uint32_t *)(buffer); | ||
|
||
// Get block count | ||
bd_size_t blockCnt = size / _block_size; | ||
addr = addr / _block_size; | ||
|
||
#if DEVICE_SDIO_ASYNC | ||
// make sure card is ready | ||
{ | ||
uint32_t tickstart = us_ticker_read(); | ||
while (sdio_get_card_state() != SD_TRANSFER_OK) { | ||
// wait until SD ready | ||
if ((us_ticker_read() - tickstart) >= MBED_CONF_SDIO_CMD_TIMEOUT) { | ||
unlock(); | ||
return SD_BLOCK_DEVICE_ERROR_WRITEBLOCKS; | ||
} | ||
} | ||
} | ||
|
||
status = sdio_writeblocks_async(_buffer, addr, blockCnt); | ||
debug_if(SD_DBG, "WriteBlocks dbgtest addr: %lld blockCnt: %lld \n", addr, blockCnt); | ||
|
||
if (status == MSD_OK) { | ||
// wait until DMA finished | ||
uint32_t tickstart = us_ticker_read(); | ||
while (sdio_write_pending() != SD_TRANSFER_OK) { | ||
if ((us_ticker_read() - tickstart) >= MBED_CONF_SDIO_CMD_TIMEOUT) { | ||
unlock(); | ||
return SD_BLOCK_DEVICE_ERROR_WRITEBLOCKS; | ||
} | ||
} | ||
// make sure card is ready | ||
tickstart = us_ticker_read(); | ||
while (sdio_get_card_state() != SD_TRANSFER_OK) { | ||
// wait until SD ready | ||
if ((us_ticker_read() - tickstart) >= MBED_CONF_SDIO_CMD_TIMEOUT) { | ||
unlock(); | ||
return SD_BLOCK_DEVICE_ERROR_WRITEBLOCKS; | ||
} | ||
} | ||
} else { | ||
debug_if(SD_DBG, "WriteBlocks failed! addr: %lld blockCnt: %lld \n", addr, blockCnt); | ||
unlock(); | ||
return SD_BLOCK_DEVICE_ERROR_WRITEBLOCKS; | ||
} | ||
#else | ||
status = sdio_writeblocks(_buffer, addr, blockCnt); | ||
|
||
debug_if(SD_DBG, "WriteBlocks dbgtest addr: %lld blockCnt: %lld \n", addr, blockCnt); | ||
|
||
if (status != MSD_OK) { | ||
debug_if(SD_DBG, "WriteBlocks failed! addr: %lld blockCnt: %lld \n", addr, blockCnt); | ||
status = SD_BLOCK_DEVICE_ERROR_WRITEBLOCKS; | ||
} | ||
#endif | ||
|
||
unlock(); | ||
return status; | ||
} | ||
|
||
int SDIOBlockDevice::trim(bd_addr_t addr, bd_size_t size) | ||
{ | ||
debug_if(SD_DBG, "trim Card...\r\n"); | ||
lock(); | ||
if (isPresent() == false) { | ||
unlock(); | ||
return SD_BLOCK_DEVICE_ERROR_NO_DEVICE; | ||
} | ||
|
||
if (!_is_initialized) { | ||
unlock(); | ||
return SD_BLOCK_DEVICE_ERROR_NO_INIT; | ||
} | ||
|
||
if (!_is_valid_trim(addr, size)) { | ||
unlock(); | ||
return SD_BLOCK_DEVICE_ERROR_PARAMETER; | ||
} | ||
|
||
bd_size_t blockCnt = size / _block_size; | ||
addr = addr / _block_size; | ||
|
||
int status = sdio_erase(addr, blockCnt); | ||
if (status != 0) { | ||
debug_if(SD_DBG, "Erase blocks failed! addr: %lld blockCnt: %lld \n", addr, blockCnt); | ||
unlock(); | ||
return SD_BLOCK_DEVICE_ERROR_ERASEBLOCKS; | ||
#if DEVICE_SDIO_ASYNC | ||
} else { | ||
uint32_t tickstart = us_ticker_read(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why is this using _us_ticker - not wait_us() rather or Ticker object? Shouldn't it |
||
while (sdio_get_card_state() != SD_TRANSFER_OK) { | ||
// wait until SD ready | ||
if ((us_ticker_read() - tickstart) >= MBED_CONF_SDIO_CMD_TIMEOUT) { | ||
unlock(); | ||
return SD_BLOCK_DEVICE_ERROR_ERASEBLOCKS; | ||
} | ||
} | ||
#endif | ||
} | ||
|
||
unlock(); | ||
return status; | ||
} | ||
|
||
bd_size_t SDIOBlockDevice::get_read_size() const | ||
{ | ||
return _block_size; | ||
} | ||
|
||
bd_size_t SDIOBlockDevice::get_program_size() const | ||
{ | ||
return _block_size; | ||
} | ||
|
||
bd_size_t SDIOBlockDevice::size() const | ||
{ | ||
return _block_size * _sectors; | ||
} | ||
|
||
void SDIOBlockDevice::debug(bool dbg) | ||
{ | ||
} | ||
|
||
bool SDIOBlockDevice::_is_valid_trim(bd_addr_t addr, bd_size_t size) | ||
{ | ||
return ( | ||
addr % _erase_size == 0 && | ||
size % _erase_size == 0 && | ||
addr + size <= this->size()); | ||
} | ||
|
||
bool SDIOBlockDevice::isPresent(void) | ||
{ | ||
if (_cardDetect.is_connected()) { | ||
return (_cardDetect.read() == 0); | ||
} else { | ||
return true; | ||
} | ||
} | ||
|
||
const char *SDIOBlockDevice::get_type() const | ||
{ | ||
return "SDIO"; | ||
} | ||
|
||
#endif //DEVICE_SDIO |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here as above, lets make them more debug friendly. I would even do enum class as we are now C++1x