Simplified FatFS bindings. Removed MMCSD experiment files.

git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@15831 27425a3e-05d8-49a3-a47f-9c15f0e5edd8
This commit is contained in:
Giovanni Di Sirio 2022-11-13 10:56:02 +00:00
parent bcb707c494
commit 8f967fe2af
6 changed files with 231 additions and 1434 deletions

View File

@ -31,10 +31,10 @@
/* Driver constants. */
/*===========================================================================*/
#define MMC_CMD0_RETRY 10U
#define MMC_CMD1_RETRY 100U
#define MMC_ACMD41_RETRY 100U
#define MMC_WAIT_DATA 10000U
#define MMC_CMD0_RETRY 10U
#define MMC_CMD1_RETRY 100U
#define MMC_ACMD41_RETRY 100U
#define MMC_WAIT_DATA 10000U
/*===========================================================================*/
/* Driver pre-compile time settings. */
@ -46,14 +46,21 @@
*/
/**
* @brief Delays insertions.
* @details If enabled this options inserts delays into the MMC waiting
* @details If enabled this options inserts delays into the card waiting
* routines releasing some extra CPU time for the threads with
* lower priority, this may slow down the driver a bit however.
* This option is recommended also if the SPI driver does not
* use a DMA channel and heavily loads the CPU.
*/
#if !defined(MMC_NICE_WAITING) || defined(__DOXYGEN__)
#define MMC_NICE_WAITING TRUE
#define MMC_NICE_WAITING TRUE
#endif
/**
* @brief Mutual exclusion on the SPI bus.
*/
#if !defined(MMC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
#define MMC_USE_MUTUAL_EXCLUSION TRUE
#endif
/** @} */
@ -65,32 +72,42 @@
#error "MMC_SPI driver requires HAL_USE_SPI and SPI_USE_WAIT"
#endif
#if (MMC_USE_MUTUAL_EXCLUSION == TRUE) && (SPI_USE_MUTUAL_EXCLUSION == FALSE)
#error "MMC_USE_MUTUAL_EXCLUSION requires SPI_USE_MUTUAL_EXCLUSION"
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief MMC/SD over SPI driver configuration structure.
* @brief Type of a MMC/SD over SPI driver configuration structure.
*/
typedef struct {
/**
* @brief SPI driver associated to this MMC driver.
*/
SPIDriver *spip;
SPIDriver *spip;
/**
* @brief SPI low speed configuration used during initialization.
*/
const SPIConfig *lscfg;
const SPIConfig *lscfg;
/**
* @brief SPI high speed configuration used during transfers.
*/
const SPIConfig *hscfg;
} MMCConfig;
const SPIConfig *hscfg;
} mmc_spi_config_t;
/**
* @brief Legacy name for compatibility.
* @deprecated
*/
typedef mmc_spi_config_t MMCConfig;
/**
* @brief @p MMCDriver specific methods.
*/
#define _mmc_driver_methods \
#define __mmc_driver_methods \
_mmcsd_block_device_methods
/**
@ -98,8 +115,8 @@ typedef struct {
*
* @brief @p MMCDriver virtual methods table.
*/
struct MMCDriverVMT {
_mmc_driver_methods
struct mmc_spi_driver_vmt {
__mmc_driver_methods
};
/**
@ -111,17 +128,23 @@ typedef struct {
/**
* @brief Virtual Methods Table.
*/
const struct MMCDriverVMT *vmt;
const struct mmc_spi_driver_vmt *vmt;
_mmcsd_block_device_data
/**
* @brief Current configuration data.
*/
const MMCConfig *config;
const mmc_spi_config_t *config;
/**
* @brief Addresses use blocks instead of bytes.
*/
bool block_addresses;
} MMCDriver;
bool block_addresses;
} mmc_spi_driver_t;
/**
* @brief Legacy name for compatibility.
* @deprecated
*/
typedef mmc_spi_driver_t MMCDriver;
/*===========================================================================*/
/* Driver macros. */

View File

@ -1,919 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
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.
*/
/*
Parts of this file have been contributed by Matthias Blaicher.
*/
/**
* @file hal_mmc_spi.c
* @brief hal_mmcsd_spi over SPI driver code.
*
* @addtogroup MMCSD_SPI
* @{
*/
#include <string.h>
#include "hal_mmcsd_spi.h"
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/* Forward declarations required by mmc_vmt.*/
static bool mmc_read(void *instance, uint32_t startblk,
uint8_t *buffer, uint32_t n);
static bool mmc_write(void *instance, uint32_t startblk,
const uint8_t *buffer, uint32_t n);
/**
* @brief Virtual methods table.
*/
static const struct mmcsd_spi_driver_vmt mmc_vmt = {
(size_t)0,
(bool (*)(void *))mmc_lld_is_card_inserted,
(bool (*)(void *))mmc_lld_is_write_protected,
(bool (*)(void *))mmcConnect,
(bool (*)(void *))mmcDisconnect,
mmc_read,
mmc_write,
(bool (*)(void *))mmcSync,
(bool (*)(void *, BlockDeviceInfo *))mmcGetInfo
};
/**
* @brief Lookup table for CRC-7 ( based on polynomial x^7 + x^3 + 1).
*/
static const uint8_t crc7_lookup_table[256] = {
0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, 0x48, 0x41, 0x5a, 0x53,
0x6c, 0x65, 0x7e, 0x77, 0x19, 0x10, 0x0b, 0x02, 0x3d, 0x34, 0x2f, 0x26,
0x51, 0x58, 0x43, 0x4a, 0x75, 0x7c, 0x67, 0x6e, 0x32, 0x3b, 0x20, 0x29,
0x16, 0x1f, 0x04, 0x0d, 0x7a, 0x73, 0x68, 0x61, 0x5e, 0x57, 0x4c, 0x45,
0x2b, 0x22, 0x39, 0x30, 0x0f, 0x06, 0x1d, 0x14, 0x63, 0x6a, 0x71, 0x78,
0x47, 0x4e, 0x55, 0x5c, 0x64, 0x6d, 0x76, 0x7f, 0x40, 0x49, 0x52, 0x5b,
0x2c, 0x25, 0x3e, 0x37, 0x08, 0x01, 0x1a, 0x13, 0x7d, 0x74, 0x6f, 0x66,
0x59, 0x50, 0x4b, 0x42, 0x35, 0x3c, 0x27, 0x2e, 0x11, 0x18, 0x03, 0x0a,
0x56, 0x5f, 0x44, 0x4d, 0x72, 0x7b, 0x60, 0x69, 0x1e, 0x17, 0x0c, 0x05,
0x3a, 0x33, 0x28, 0x21, 0x4f, 0x46, 0x5d, 0x54, 0x6b, 0x62, 0x79, 0x70,
0x07, 0x0e, 0x15, 0x1c, 0x23, 0x2a, 0x31, 0x38, 0x41, 0x48, 0x53, 0x5a,
0x65, 0x6c, 0x77, 0x7e, 0x09, 0x00, 0x1b, 0x12, 0x2d, 0x24, 0x3f, 0x36,
0x58, 0x51, 0x4a, 0x43, 0x7c, 0x75, 0x6e, 0x67, 0x10, 0x19, 0x02, 0x0b,
0x34, 0x3d, 0x26, 0x2f, 0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c,
0x3b, 0x32, 0x29, 0x20, 0x1f, 0x16, 0x0d, 0x04, 0x6a, 0x63, 0x78, 0x71,
0x4e, 0x47, 0x5c, 0x55, 0x22, 0x2b, 0x30, 0x39, 0x06, 0x0f, 0x14, 0x1d,
0x25, 0x2c, 0x37, 0x3e, 0x01, 0x08, 0x13, 0x1a, 0x6d, 0x64, 0x7f, 0x76,
0x49, 0x40, 0x5b, 0x52, 0x3c, 0x35, 0x2e, 0x27, 0x18, 0x11, 0x0a, 0x03,
0x74, 0x7d, 0x66, 0x6f, 0x50, 0x59, 0x42, 0x4b, 0x17, 0x1e, 0x05, 0x0c,
0x33, 0x3a, 0x21, 0x28, 0x5f, 0x56, 0x4d, 0x44, 0x7b, 0x72, 0x69, 0x60,
0x0e, 0x07, 0x1c, 0x15, 0x2a, 0x23, 0x38, 0x31, 0x46, 0x4f, 0x54, 0x5d,
0x62, 0x6b, 0x70, 0x79
};
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
static bool mmc_read(void *instance, uint32_t startblk,
uint8_t *buffer, uint32_t n) {
if (mmcStartSequentialRead((MMCDriver *)instance, startblk)) {
return HAL_FAILED;
}
while (n > 0U) {
if (mmcSequentialRead((MMCDriver *)instance, buffer)) {
return HAL_FAILED;
}
buffer += MMCSD_BLOCK_SIZE;
n--;
}
if (mmcStopSequentialRead((MMCDriver *)instance)) {
return HAL_FAILED;
}
return HAL_SUCCESS;
}
static bool mmc_write(void *instance, uint32_t startblk,
const uint8_t *buffer, uint32_t n) {
if (mmcStartSequentialWrite((MMCDriver *)instance, startblk)) {
return HAL_FAILED;
}
while (n > 0U) {
if (mmcSequentialWrite((MMCDriver *)instance, buffer)) {
return HAL_FAILED;
}
buffer += MMCSD_BLOCK_SIZE;
n--;
}
if (mmcStopSequentialWrite((MMCDriver *)instance)) {
return HAL_FAILED;
}
return HAL_SUCCESS;
}
/**
* @brief Calculate the MMC standard CRC-7 based on a lookup table.
*
* @param[in] crc start value for CRC
* @param[in] buffer pointer to data buffer
* @param[in] len length of data
* @return Calculated CRC
*/
static uint8_t crc7(uint8_t crc, const uint8_t *buffer, size_t len) {
while (len > 0U) {
crc = crc7_lookup_table[(crc << 1) ^ (*buffer++)];
len--;
}
return crc;
}
/**
* @brief Waits an idle condition.
*
* @param[in] mmcp pointer to the @p MMCDriver object
*
* @notapi
*/
static void wait(MMCDriver *mmcp) {
int i;
uint8_t buf[4];
for (i = 0; i < 16; i++) {
spiReceive(mmcp->config->spip, 1, buf);
if (buf[0] == 0xFFU) {
return;
}
}
/* Looks like it is a long wait.*/
while (true) {
spiReceive(mmcp->config->spip, 1, buf);
if (buf[0] == 0xFFU) {
break;
}
#if MMC_NICE_WAITING == TRUE
/* Trying to be nice with the other threads.*/
osalThreadSleepMilliseconds(1);
#endif
}
}
/**
* @brief Sends a command header.
*
* @param[in] mmcp pointer to the @p MMCDriver object
* @param[in] cmd the command id
* @param[in] arg the command argument
*
* @notapi
*/
static void send_hdr(MMCDriver *mmcp, uint8_t cmd, uint32_t arg) {
uint8_t buf[6];
/* Wait for the bus to become idle if a write operation was in progress.*/
wait(mmcp);
buf[0] = (uint8_t)0x40U | cmd;
buf[1] = (uint8_t)(arg >> 24U);
buf[2] = (uint8_t)(arg >> 16U);
buf[3] = (uint8_t)(arg >> 8U);
buf[4] = (uint8_t)arg;
/* Calculate CRC for command header, shift to right position, add stop bit.*/
buf[5] = ((crc7(0, buf, 5U) & 0x7FU) << 1U) | 0x01U;
spiSend(mmcp->config->spip, 6, buf);
}
/**
* @brief Receives a single byte response.
*
* @param[in] mmcp pointer to the @p MMCDriver object
* @return The response as an @p uint8_t value.
* @retval 0xFF timed out.
*
* @notapi
*/
static uint8_t recvr1(MMCDriver *mmcp) {
int i;
uint8_t r1[1];
for (i = 0; i < 9; i++) {
spiReceive(mmcp->config->spip, 1, r1);
if (r1[0] != 0xFFU) {
return r1[0];
}
}
return 0xFFU;
}
/**
* @brief Receives a three byte response.
*
* @param[in] mmcp pointer to the @p MMCDriver object
* @param[out] buffer pointer to four bytes wide buffer
* @return First response byte as an @p uint8_t value.
* @retval 0xFF timed out.
*
* @notapi
*/
static uint8_t recvr3(MMCDriver *mmcp, uint8_t* buffer) {
uint8_t r1;
r1 = recvr1(mmcp);
spiReceive(mmcp->config->spip, 4, buffer);
return r1;
}
/**
* @brief Sends a command an returns a single byte response.
*
* @param[in] mmcp pointer to the @p MMCDriver object
* @param[in] cmd the command id
* @param[in] arg the command argument
* @return The response as an @p uint8_t value.
* @retval 0xFF timed out.
*
* @notapi
*/
static uint8_t send_command_R1(MMCDriver *mmcp, uint8_t cmd, uint32_t arg) {
uint8_t r1;
spiSelect(mmcp->config->spip);
send_hdr(mmcp, cmd, arg);
r1 = recvr1(mmcp);
spiUnselect(mmcp->config->spip);
return r1;
}
/**
* @brief Sends a command which returns a five bytes response (R3).
*
* @param[in] mmcp pointer to the @p MMCDriver object
* @param[in] cmd the command id
* @param[in] arg the command argument
* @param[out] response pointer to four bytes wide uint8_t buffer
* @return The first byte of the response (R1) as an @p
* uint8_t value.
* @retval 0xFF timed out.
*
* @notapi
*/
static uint8_t send_command_R3(MMCDriver *mmcp, uint8_t cmd, uint32_t arg,
uint8_t *response) {
uint8_t r1;
spiSelect(mmcp->config->spip);
send_hdr(mmcp, cmd, arg);
r1 = recvr3(mmcp, response);
spiUnselect(mmcp->config->spip);
return r1;
}
/**
* @brief Reads the CSD.
*
* @param[in] mmcp pointer to the @p MMCDriver object
* @param[out] cmd command
* @param[out] cxd pointer to the CSD/CID buffer
*
* @return The operation status.
* @retval HAL_SUCCESS the operation succeeded.
* @retval HAL_FAILED the operation failed.
*
* @notapi
*/
static bool read_CxD(MMCDriver *mmcp, uint8_t cmd, uint32_t cxd[4]) {
unsigned i;
uint8_t *bp, buf[16];
spiSelect(mmcp->config->spip);
send_hdr(mmcp, cmd, 0);
if (recvr1(mmcp) != 0x00U) {
spiUnselect(mmcp->config->spip);
return HAL_FAILED;
}
/* Wait for data availability.*/
for (i = 0U; i < MMC_WAIT_DATA; i++) {
spiReceive(mmcp->config->spip, 1, buf);
if (buf[0] == 0xFEU) {
uint32_t *wp;
spiReceive(mmcp->config->spip, 16, buf);
bp = buf;
for (wp = &cxd[3]; wp >= cxd; wp--) {
*wp = ((uint32_t)bp[0] << 24U) | ((uint32_t)bp[1] << 16U) |
((uint32_t)bp[2] << 8U) | (uint32_t)bp[3];
bp += 4;
}
/* CRC ignored then end of transaction. */
spiIgnore(mmcp->config->spip, 2);
spiUnselect(mmcp->config->spip);
return HAL_SUCCESS;
}
}
return HAL_FAILED;
}
/**
* @brief Waits that the card reaches an idle state.
*
* @param[in] mmcp pointer to the @p MMCDriver object
*
* @notapi
*/
static void sync(MMCDriver *mmcp) {
uint8_t buf[1];
spiSelect(mmcp->config->spip);
while (true) {
spiReceive(mmcp->config->spip, 1, buf);
if (buf[0] == 0xFFU) {
break;
}
#if MMC_NICE_WAITING == TRUE
/* Trying to be nice with the other threads.*/
osalThreadSleepMilliseconds(1);
#endif
}
spiUnselect(mmcp->config->spip);
}
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief MMC over SPI driver initialization.
* @note This function is implicitly invoked by @p halInit(), there is
* no need to explicitly initialize the driver.
*
* @init
*/
void mmcInit(void) {
}
/**
* @brief Initializes an instance.
*
* @param[out] mmcp pointer to the @p MMCDriver object
*
* @init
*/
void mmcObjectInit(MMCDriver *mmcp) {
mmcp->vmt = &mmc_vmt;
mmcp->state = BLK_STOP;
mmcp->config = NULL;
mmcp->block_addresses = false;
}
/**
* @brief Configures and activates the MMC peripheral.
*
* @param[in] mmcp pointer to the @p MMCDriver object
* @param[in] config pointer to the @p MMCConfig object.
* @return The operation status.
*
* @api
*/
msg_t mmcStart(MMCDriver *mmcp, const MMCConfig *config) {
osalDbgCheck((mmcp != NULL) && (config != NULL));
osalDbgAssert((mmcp->state == BLK_STOP) || (mmcp->state == BLK_ACTIVE),
"invalid state");
mmcp->config = config;
mmcp->state = BLK_ACTIVE;
return HAL_RET_SUCCESS;
}
/**
* @brief Disables the MMC peripheral.
*
* @param[in] mmcp pointer to the @p MMCDriver object
*
* @api
*/
void mmcStop(MMCDriver *mmcp) {
osalDbgCheck(mmcp != NULL);
osalDbgAssert((mmcp->state == BLK_STOP) || (mmcp->state == BLK_ACTIVE),
"invalid state");
spiStop(mmcp->config->spip);
mmcp->config = NULL;
mmcp->state = BLK_STOP;
}
/**
* @brief Performs the initialization procedure on the inserted card.
* @details This function should be invoked when a card is inserted and
* brings the driver in the @p MMC_READY state where it is possible
* to perform read and write operations.
* @note It is possible to invoke this function from the insertion event
* handler.
*
* @param[in] mmcp pointer to the @p MMCDriver object
*
* @return The operation status.
* @retval HAL_SUCCESS the operation succeeded and the driver is now
* in the @p MMC_READY state.
* @retval HAL_FAILED the operation failed.
*
* @api
*/
bool mmcConnect(MMCDriver *mmcp) {
unsigned i;
uint8_t r3[4];
osalDbgCheck(mmcp != NULL);
osalDbgAssert((mmcp->state == BLK_ACTIVE) || (mmcp->state == BLK_READY),
"invalid state");
/* Connection procedure in progress.*/
mmcp->state = BLK_CONNECTING;
mmcp->block_addresses = false;
/* Slow clock mode and 128 clock pulses.*/
spiStart(mmcp->config->spip, mmcp->config->lscfg);
spiIgnore(mmcp->config->spip, 16);
/* SPI mode selection.*/
i = 0;
while (true) {
if (send_command_R1(mmcp, MMCSD_CMD_GO_IDLE_STATE, 0) == 0x01U) {
break;
}
if (++i >= MMC_CMD0_RETRY) {
goto failed;
}
osalThreadSleepMilliseconds(10);
}
/* Try to detect if this is a high capacity card and switch to block
addresses if possible.
This method is based on "How to support SDC Ver2 and high capacity cards"
by ElmChan.*/
if (send_command_R3(mmcp, MMCSD_CMD_SEND_IF_COND,
MMCSD_CMD8_PATTERN, r3) != 0x05U) {
/* Switch to SDHC mode.*/
i = 0;
while (true) {
/*lint -save -e9007 [13.5] Side effect unimportant.*/
if ((send_command_R1(mmcp, MMCSD_CMD_APP_CMD, 0) <= 0x01U) &&
(send_command_R3(mmcp, MMCSD_CMD_APP_OP_COND, 0x400001AAU, r3) == 0x00U)) {
/*lint -restore*/
break;
}
if (++i >= MMC_ACMD41_RETRY) {
goto failed;
}
osalThreadSleepMilliseconds(10);
}
/* Execute dedicated read on OCR register */
(void) send_command_R3(mmcp, MMCSD_CMD_READ_OCR, 0, r3);
/* Check if CCS is set in response. Card operates in block mode if set.*/
if ((r3[0] & 0x40U) != 0U) {
mmcp->block_addresses = true;
}
}
/* Initialization.*/
i = 0;
while (true) {
uint8_t b = send_command_R1(mmcp, MMCSD_CMD_INIT, 0);
if (b == 0x00U) {
break;
}
if (b != 0x01U) {
goto failed;
}
if (++i >= MMC_CMD1_RETRY) {
goto failed;
}
osalThreadSleepMilliseconds(10);
}
/* Initialization complete, full speed.*/
spiStart(mmcp->config->spip, mmcp->config->hscfg);
/* Setting block size.*/
if (send_command_R1(mmcp, MMCSD_CMD_SET_BLOCKLEN,
MMCSD_BLOCK_SIZE) != 0x00U) {
goto failed;
}
/* Determine capacity.*/
if (read_CxD(mmcp, MMCSD_CMD_SEND_CSD, mmcp->csd)) {
goto failed;
}
mmcp->capacity = _mmcsd_get_capacity(mmcp->csd);
if (mmcp->capacity == 0U) {
goto failed;
}
if (read_CxD(mmcp, MMCSD_CMD_SEND_CID, mmcp->cid)) {
goto failed;
}
mmcp->state = BLK_READY;
return HAL_SUCCESS;
/* Connection failed, state reset to BLK_ACTIVE.*/
failed:
spiStop(mmcp->config->spip);
mmcp->state = BLK_ACTIVE;
return HAL_FAILED;
}
/**
* @brief Brings the driver in a state safe for card removal.
*
* @param[in] mmcp pointer to the @p MMCDriver object
* @return The operation status.
*
* @retval HAL_SUCCESS the operation succeeded and the driver is now
* in the @p MMC_INSERTED state.
* @retval HAL_FAILED the operation failed.
*
* @api
*/
bool mmcDisconnect(MMCDriver *mmcp) {
osalDbgCheck(mmcp != NULL);
osalSysLock();
osalDbgAssert((mmcp->state == BLK_ACTIVE) || (mmcp->state == BLK_READY),
"invalid state");
if (mmcp->state == BLK_ACTIVE) {
osalSysUnlock();
return HAL_SUCCESS;
}
mmcp->state = BLK_DISCONNECTING;
osalSysUnlock();
/* Wait for the pending write operations to complete.*/
spiStart(mmcp->config->spip, mmcp->config->hscfg);
sync(mmcp);
spiStop(mmcp->config->spip);
mmcp->state = BLK_ACTIVE;
return HAL_SUCCESS;
}
/**
* @brief Starts a sequential read.
*
* @param[in] mmcp pointer to the @p MMCDriver object
* @param[in] startblk first block to read
*
* @return The operation status.
* @retval HAL_SUCCESS the operation succeeded.
* @retval HAL_FAILED the operation failed.
*
* @api
*/
bool mmcStartSequentialRead(MMCDriver *mmcp, uint32_t startblk) {
osalDbgCheck(mmcp != NULL);
osalDbgAssert(mmcp->state == BLK_READY, "invalid state");
/* Read operation in progress.*/
mmcp->state = BLK_READING;
/* (Re)starting the SPI in case it has been reprogrammed externally, it can
happen if the SPI bus is shared among multiple peripherals.*/
spiStart(mmcp->config->spip, mmcp->config->hscfg);
spiSelect(mmcp->config->spip);
if (mmcp->block_addresses) {
send_hdr(mmcp, MMCSD_CMD_READ_MULTIPLE_BLOCK, startblk);
}
else {
send_hdr(mmcp, MMCSD_CMD_READ_MULTIPLE_BLOCK, startblk * MMCSD_BLOCK_SIZE);
}
if (recvr1(mmcp) != 0x00U) {
spiStop(mmcp->config->spip);
mmcp->state = BLK_READY;
return HAL_FAILED;
}
return HAL_SUCCESS;
}
/**
* @brief Reads a block within a sequential read operation.
*
* @param[in] mmcp pointer to the @p MMCDriver object
* @param[out] buffer pointer to the read buffer
*
* @return The operation status.
* @retval HAL_SUCCESS the operation succeeded.
* @retval HAL_FAILED the operation failed.
*
* @api
*/
bool mmcSequentialRead(MMCDriver *mmcp, uint8_t *buffer) {
unsigned i;
osalDbgCheck((mmcp != NULL) && (buffer != NULL));
if (mmcp->state != BLK_READING) {
return HAL_FAILED;
}
for (i = 0; i < MMC_WAIT_DATA; i++) {
spiReceive(mmcp->config->spip, 1, buffer);
if (buffer[0] == 0xFEU) {
spiReceive(mmcp->config->spip, MMCSD_BLOCK_SIZE, buffer);
/* CRC ignored. */
spiIgnore(mmcp->config->spip, 2);
return HAL_SUCCESS;
}
}
/* Timeout.*/
spiUnselect(mmcp->config->spip);
spiStop(mmcp->config->spip);
mmcp->state = BLK_READY;
return HAL_FAILED;
}
/**
* @brief Stops a sequential read gracefully.
*
* @param[in] mmcp pointer to the @p MMCDriver object
*
* @return The operation status.
* @retval HAL_SUCCESS the operation succeeded.
* @retval HAL_FAILED the operation failed.
*
* @api
*/
bool mmcStopSequentialRead(MMCDriver *mmcp) {
static const uint8_t stopcmd[] = {
(uint8_t)(0x40U | MMCSD_CMD_STOP_TRANSMISSION), 0, 0, 0, 0, 1, 0xFF
};
osalDbgCheck(mmcp != NULL);
if (mmcp->state != BLK_READING) {
return HAL_FAILED;
}
spiSend(mmcp->config->spip, sizeof(stopcmd), stopcmd);
/* result = recvr1(mmcp) != 0x00U;*/
/* Note, ignored r1 response, it can be not zero, unknown issue.*/
(void) recvr1(mmcp);
/* Read operation finished.*/
spiUnselect(mmcp->config->spip);
mmcp->state = BLK_READY;
return HAL_SUCCESS;
}
/**
* @brief Starts a sequential write.
*
* @param[in] mmcp pointer to the @p MMCDriver object
* @param[in] startblk first block to write
*
* @return The operation status.
* @retval HAL_SUCCESS the operation succeeded.
* @retval HAL_FAILED the operation failed.
*
* @api
*/
bool mmcStartSequentialWrite(MMCDriver *mmcp, uint32_t startblk) {
osalDbgCheck(mmcp != NULL);
osalDbgAssert(mmcp->state == BLK_READY, "invalid state");
/* Write operation in progress.*/
mmcp->state = BLK_WRITING;
spiStart(mmcp->config->spip, mmcp->config->hscfg);
spiSelect(mmcp->config->spip);
if (mmcp->block_addresses) {
send_hdr(mmcp, MMCSD_CMD_WRITE_MULTIPLE_BLOCK, startblk);
}
else {
send_hdr(mmcp, MMCSD_CMD_WRITE_MULTIPLE_BLOCK,
startblk * MMCSD_BLOCK_SIZE);
}
if (recvr1(mmcp) != 0x00U) {
spiStop(mmcp->config->spip);
mmcp->state = BLK_READY;
return HAL_FAILED;
}
return HAL_SUCCESS;
}
/**
* @brief Writes a block within a sequential write operation.
*
* @param[in] mmcp pointer to the @p MMCDriver object
* @param[out] buffer pointer to the write buffer
*
* @return The operation status.
* @retval HAL_SUCCESS the operation succeeded.
* @retval HAL_FAILED the operation failed.
*
* @api
*/
bool mmcSequentialWrite(MMCDriver *mmcp, const uint8_t *buffer) {
static const uint8_t start[] = {0xFF, 0xFC};
uint8_t b[1];
osalDbgCheck((mmcp != NULL) && (buffer != NULL));
if (mmcp->state != BLK_WRITING) {
return HAL_FAILED;
}
spiSend(mmcp->config->spip, sizeof(start), start); /* Data prologue. */
spiSend(mmcp->config->spip, MMCSD_BLOCK_SIZE, buffer);/* Data. */
spiIgnore(mmcp->config->spip, 2); /* CRC ignored. */
spiReceive(mmcp->config->spip, 1, b);
if ((b[0] & 0x1FU) == 0x05U) {
wait(mmcp);
return HAL_SUCCESS;
}
/* Error.*/
spiUnselect(mmcp->config->spip);
spiStop(mmcp->config->spip);
mmcp->state = BLK_READY;
return HAL_FAILED;
}
/**
* @brief Stops a sequential write gracefully.
*
* @param[in] mmcp pointer to the @p MMCDriver object
*
* @return The operation status.
* @retval HAL_SUCCESS the operation succeeded.
* @retval HAL_FAILED the operation failed.
*
* @api
*/
bool mmcStopSequentialWrite(MMCDriver *mmcp) {
static const uint8_t stop[] = {0xFD, 0xFF};
osalDbgCheck(mmcp != NULL);
if (mmcp->state != BLK_WRITING) {
return HAL_FAILED;
}
spiSend(mmcp->config->spip, sizeof(stop), stop);
spiUnselect(mmcp->config->spip);
/* Write operation finished.*/
mmcp->state = BLK_READY;
return HAL_SUCCESS;
}
/**
* @brief Waits for card idle condition.
*
* @param[in] mmcp pointer to the @p MMCDriver object
*
* @return The operation status.
* @retval HAL_SUCCESS the operation succeeded.
* @retval HAL_FAILED the operation failed.
*
* @api
*/
bool mmcSync(MMCDriver *mmcp) {
osalDbgCheck(mmcp != NULL);
if (mmcp->state != BLK_READY) {
return HAL_FAILED;
}
/* Synchronization operation in progress.*/
mmcp->state = BLK_SYNCING;
spiStart(mmcp->config->spip, mmcp->config->hscfg);
sync(mmcp);
/* Synchronization operation finished.*/
mmcp->state = BLK_READY;
return HAL_SUCCESS;
}
/**
* @brief Returns the media info.
*
* @param[in] mmcp pointer to the @p MMCDriver object
* @param[out] bdip pointer to a @p BlockDeviceInfo structure
*
* @return The operation status.
* @retval HAL_SUCCESS the operation succeeded.
* @retval HAL_FAILED the operation failed.
*
* @api
*/
bool mmcGetInfo(MMCDriver *mmcp, BlockDeviceInfo *bdip) {
osalDbgCheck((mmcp != NULL) && (bdip != NULL));
if (mmcp->state != BLK_READY) {
return HAL_FAILED;
}
bdip->blk_num = mmcp->capacity;
bdip->blk_size = MMCSD_BLOCK_SIZE;
return HAL_SUCCESS;
}
/**
* @brief Erases blocks.
*
* @param[in] mmcp pointer to the @p MMCDriver object
* @param[in] startblk starting block number
* @param[in] endblk ending block number
*
* @return The operation status.
* @retval HAL_SUCCESS the operation succeeded.
* @retval HAL_FAILED the operation failed.
*
* @api
*/
bool mmcErase(MMCDriver *mmcp, uint32_t startblk, uint32_t endblk) {
osalDbgCheck((mmcp != NULL));
/* Erase operation in progress.*/
mmcp->state = BLK_WRITING;
/* Handling command differences between HC and normal cards.*/
if (!mmcp->block_addresses) {
startblk *= MMCSD_BLOCK_SIZE;
endblk *= MMCSD_BLOCK_SIZE;
}
if (send_command_R1(mmcp, MMCSD_CMD_ERASE_RW_BLK_START, startblk) != 0x00U) {
goto failed;
}
if (send_command_R1(mmcp, MMCSD_CMD_ERASE_RW_BLK_END, endblk) != 0x00U) {
goto failed;
}
if (send_command_R1(mmcp, MMCSD_CMD_ERASE, 0) != 0x00U) {
goto failed;
}
mmcp->state = BLK_READY;
return HAL_SUCCESS;
/* Command failed, state reset to BLK_ACTIVE.*/
failed:
spiStop(mmcp->config->spip);
mmcp->state = BLK_READY;
return HAL_FAILED;
}
/** @} */

View File

@ -1,220 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
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.
*/
/**
* @file hal_mmcsd_spi.h
* @brief MMC/SD over SPI driver header.
*
* @addtogroup MMCSD_SPI
* @{
*/
#ifndef HAL_MMCSD_SPI_H
#define HAL_MMCSD_SPI_H
#include "hal.h"
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
#define MMC_CMD0_RETRY 10U
#define MMC_CMD1_RETRY 100U
#define MMC_ACMD41_RETRY 100U
#define MMC_WAIT_DATA 10000U
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name SDMMC_SPI configuration options
* @{
*/
/**
* @brief Delays insertions.
* @details If enabled this options inserts delays into the card waiting
* routines releasing some extra CPU time for the threads with
* lower priority, this may slow down the driver a bit however.
* This option is recommended also if the SPI driver does not
* use a DMA channel and heavily loads the CPU.
*/
#if !defined(MMCSD_SPI_NICE_WAITING) || defined(__DOXYGEN__)
#define MMCSD_SPI_NICE_WAITING TRUE
#endif
/**
* @brief Mutual exclusion on the SPI bus.
*/
#if !defined(MMCSD_SPI_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
#define MMCSD_SPI_USE_MUTUAL_EXCLUSION TRUE
#endif
/** @} */
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if HAL_USE_MMC_SPI == TRUE
#error "SDMMC_SPI driver requires HAL_USE_MMC_SPI to be disabled"
#endif
#if (HAL_USE_SPI == FALSE) || (SPI_USE_WAIT == FALSE)
#error "SDMMC_SPI driver requires HAL_USE_SPI and SPI_USE_WAIT"
#endif
#if (MMCSD_SPI_USE_MUTUAL_EXCLUSION == TRUE) && (SPI_USE_MUTUAL_EXCLUSION == FALSE)
#error "MMCSD_SPI_USE_MUTUAL_EXCLUSION requires SPI_USE_MUTUAL_EXCLUSION"
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Type of a SD/MMC over SPI driver configuration structure.
*/
typedef struct {
/**
* @brief SPI driver associated to this MMC driver.
*/
SPIDriver *spip;
/**
* @brief SPI low speed configuration used during initialization.
*/
const SPIConfig *lscfg;
/**
* @brief SPI high speed configuration used during transfers.
*/
const SPIConfig *hscfg;
} mmcsd_spi_config_t;
/**
* @brief Legacy name for compatibility.
* @deprecated
*/
typedef mmcsd_spi_config_t MMCConfig;
/**
* @brief @p MMCDriver specific methods.
*/
#define __mmcsd_driver_methods \
_mmcsd_block_device_methods
/**
* @extends MMCSDBlockDeviceVMT
*
* @brief @p MMCDriver virtual methods table.
*/
struct mmcsd_spi_driver_vmt {
__mmcsd_driver_methods
};
/**
* @extends MMCSDBlockDevice
*
* @brief Structure representing a MMC/SD over SPI driver.
*/
typedef struct {
/**
* @brief Virtual Methods Table.
*/
const struct mmcsd_spi_driver_vmt *vmt;
_mmcsd_block_device_data
/**
* @brief Current configuration data.
*/
const mmcsd_spi_config_t *config;
/**
* @brief Addresses use blocks instead of bytes.
*/
bool block_addresses;
} mmcsd_spi_driver_t;
/**
* @brief Legacy name for compatibility.
* @deprecated
*/
typedef mmcsd_spi_driver_t MMCDriver;
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @name Macro Functions
* @{
*/
/**
* @brief Returns the card insertion status.
* @note This macro wraps a low level function named
* @p sdc_lld_is_card_inserted(), this function must be
* provided by the application because it is not part of the
* SDC driver.
*
* @param[in] mmcp pointer to the @p MMCDriver object
* @return The card state.
* @retval false card not inserted.
* @retval true card inserted.
*
* @api
*/
#define mmcIsCardInserted(mmcp) mmc_lld_is_card_inserted(mmcp)
/**
* @brief Returns the write protect status.
*
* @param[in] mmcp pointer to the @p MMCDriver object
* @return The card state.
* @retval false card not inserted.
* @retval true card inserted.
*
* @api
*/
#define mmcIsWriteProtected(mmcp) mmc_lld_is_write_protected(mmcp)
/** @} */
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
void mmcInit(void);
void mmcObjectInit(MMCDriver *mmcp);
msg_t mmcStart(MMCDriver *mmcp, const MMCConfig *config);
void mmcStop(MMCDriver *mmcp);
bool mmcConnect(MMCDriver *mmcp);
bool mmcDisconnect(MMCDriver *mmcp);
bool mmcStartSequentialRead(MMCDriver *mmcp, uint32_t startblk);
bool mmcSequentialRead(MMCDriver *mmcp, uint8_t *buffer);
bool mmcStopSequentialRead(MMCDriver *mmcp);
bool mmcStartSequentialWrite(MMCDriver *mmcp, uint32_t startblk);
bool mmcSequentialWrite(MMCDriver *mmcp, const uint8_t *buffer);
bool mmcStopSequentialWrite(MMCDriver *mmcp);
bool mmcSync(MMCDriver *mmcp);
bool mmcGetInfo(MMCDriver *mmcp, BlockDeviceInfo *bdip);
bool mmcErase(MMCDriver *mmcp, uint32_t startblk, uint32_t endblk);
bool mmc_lld_is_card_inserted(MMCDriver *mmcp);
bool mmc_lld_is_write_protected(MMCDriver *mmcp);
#ifdef __cplusplus
}
#endif
#endif /* HAL_MMCSD_SPI_H */
/** @} */

View File

@ -1,9 +0,0 @@
# List of all the MMC_SPI subsystem files.
MMCSDSPISRC := $(CHIBIOS)/os/hal/lib/complex/mmcsd_spi/hal_mmcsd_spi.c
# Required include directories
MMCSDSPIINC := $(CHIBIOS)/os/hal/lib/complex/mmcsd_spi
# Shared variables
ALLCSRC += $(MMCSDSPISRC)
ALLINC += $(MMCSDSPIINC)

View File

@ -52,7 +52,7 @@ static bool mmc_write(void *instance, uint32_t startblk,
/**
* @brief Virtual methods table.
*/
static const struct MMCDriverVMT mmc_vmt = {
static const struct mmc_spi_driver_vmt mmc_vmt = {
(size_t)0,
(bool (*)(void *))mmc_lld_is_card_inserted,
(bool (*)(void *))mmc_lld_is_write_protected,

View File

@ -1,267 +1,189 @@
/*-----------------------------------------------------------------------*/
/* Low level disk I/O module skeleton for FatFs (C)ChaN, 2007 */
/*-----------------------------------------------------------------------*/
/* This is a stub disk I/O module that acts as front end of the existing */
/* disk I/O modules and attach it to FatFs module with common interface. */
/*-----------------------------------------------------------------------*/
#include "hal.h"
#include "ffconf.h"
#include "ff.h"
#include "diskio.h"
#if HAL_USE_MMC_SPI && HAL_USE_SDC
#error "cannot specify both MMC_SPI and SDC drivers"
#endif
#if !defined(FATFS_HAL_DEVICE)
#if HAL_USE_MMC_SPI
#define FATFS_HAL_DEVICE MMCD1
#else
#define FATFS_HAL_DEVICE SDCD1
#endif
#endif
#if HAL_USE_MMC_SPI
extern MMCDriver FATFS_HAL_DEVICE;
#elif HAL_USE_SDC
extern SDCDriver FATFS_HAL_DEVICE;
#else
#error "MMC_SPI or SDC driver must be specified"
#endif
#if HAL_USE_RTC
extern RTCDriver RTCD1;
#endif
/*-----------------------------------------------------------------------*/
/* Correspondence between physical drive number and physical drive. */
#define MMC 0
#define SDC 0
/*-----------------------------------------------------------------------*/
/* Inidialize a Drive */
DSTATUS disk_initialize (
BYTE pdrv /* Physical drive number (0..) */
)
{
DSTATUS stat;
switch (pdrv) {
#if HAL_USE_MMC_SPI
case MMC:
stat = 0;
/* It is initialized externally, just reads the status.*/
if (blkGetDriverState(&FATFS_HAL_DEVICE) != BLK_READY)
stat |= STA_NOINIT;
if (mmcIsWriteProtected(&FATFS_HAL_DEVICE))
stat |= STA_PROTECT;
return stat;
#else
case SDC:
stat = 0;
/* It is initialized externally, just reads the status.*/
if (blkGetDriverState(&FATFS_HAL_DEVICE) != BLK_READY)
stat |= STA_NOINIT;
if (sdcIsWriteProtected(&FATFS_HAL_DEVICE))
stat |= STA_PROTECT;
return stat;
#endif
}
return STA_NOINIT;
}
/*-----------------------------------------------------------------------*/
/* Return Disk Status */
DSTATUS disk_status (
BYTE pdrv /* Physical drive number (0..) */
)
{
DSTATUS stat;
switch (pdrv) {
#if HAL_USE_MMC_SPI
case MMC:
stat = 0;
/* It is initialized externally, just reads the status.*/
if (blkGetDriverState(&FATFS_HAL_DEVICE) != BLK_READY)
stat |= STA_NOINIT;
if (mmcIsWriteProtected(&FATFS_HAL_DEVICE))
stat |= STA_PROTECT;
return stat;
#else
case SDC:
stat = 0;
/* It is initialized externally, just reads the status.*/
if (blkGetDriverState(&FATFS_HAL_DEVICE) != BLK_READY)
stat |= STA_NOINIT;
if (sdcIsWriteProtected(&FATFS_HAL_DEVICE))
stat |= STA_PROTECT;
return stat;
#endif
}
return STA_NOINIT;
}
/*-----------------------------------------------------------------------*/
/* Read Sector(s) */
DRESULT disk_read (
BYTE pdrv, /* Physical drive number (0..) */
BYTE *buff, /* Data buffer to store read data */
DWORD sector, /* Sector address (LBA) */
UINT count /* Number of sectors to read (1..255) */
)
{
switch (pdrv) {
#if HAL_USE_MMC_SPI
case MMC:
if (blkGetDriverState(&FATFS_HAL_DEVICE) != BLK_READY)
return RES_NOTRDY;
if (mmcStartSequentialRead(&FATFS_HAL_DEVICE, sector))
return RES_ERROR;
while (count > 0) {
if (mmcSequentialRead(&FATFS_HAL_DEVICE, buff))
return RES_ERROR;
buff += MMCSD_BLOCK_SIZE;
count--;
}
if (mmcStopSequentialRead(&FATFS_HAL_DEVICE))
return RES_ERROR;
return RES_OK;
#else
case SDC:
if (blkGetDriverState(&FATFS_HAL_DEVICE) != BLK_READY)
return RES_NOTRDY;
if (sdcRead(&FATFS_HAL_DEVICE, sector, buff, count))
return RES_ERROR;
return RES_OK;
#endif
}
return RES_PARERR;
}
/*-----------------------------------------------------------------------*/
/* Write Sector(s) */
#if !FF_FS_READONLY
DRESULT disk_write (
BYTE pdrv, /* Physical drive number (0..) */
const BYTE *buff, /* Data to be written */
DWORD sector, /* Sector address (LBA) */
UINT count /* Number of sectors to write (1..255) */
)
{
switch (pdrv) {
#if HAL_USE_MMC_SPI
case MMC:
if (blkGetDriverState(&FATFS_HAL_DEVICE) != BLK_READY)
return RES_NOTRDY;
if (mmcIsWriteProtected(&FATFS_HAL_DEVICE))
return RES_WRPRT;
if (mmcStartSequentialWrite(&FATFS_HAL_DEVICE, sector))
return RES_ERROR;
while (count > 0) {
if (mmcSequentialWrite(&FATFS_HAL_DEVICE, buff))
return RES_ERROR;
buff += MMCSD_BLOCK_SIZE;
count--;
}
if (mmcStopSequentialWrite(&FATFS_HAL_DEVICE))
return RES_ERROR;
return RES_OK;
#else
case SDC:
if (blkGetDriverState(&FATFS_HAL_DEVICE) != BLK_READY)
return RES_NOTRDY;
if (sdcWrite(&FATFS_HAL_DEVICE, sector, buff, count))
return RES_ERROR;
return RES_OK;
#endif
}
return RES_PARERR;
}
#endif /* _FS_READONLY */
/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions */
DRESULT disk_ioctl (
BYTE pdrv, /* Physical drive number (0..) */
BYTE cmd, /* Control code */
void *buff /* Buffer to send/receive control data */
)
{
(void)buff;
switch (pdrv) {
#if HAL_USE_MMC_SPI
case MMC:
switch (cmd) {
case CTRL_SYNC:
return RES_OK;
#if FF_MAX_SS > FF_MIN_SS
case GET_SECTOR_SIZE:
*((WORD *)buff) = MMCSD_BLOCK_SIZE;
return RES_OK;
#endif
#if FF_USE_TRIM
case CTRL_TRIM:
mmcErase(&FATFS_HAL_DEVICE, *((DWORD *)buff), *((DWORD *)buff + 1));
return RES_OK;
#endif
default:
return RES_PARERR;
}
#else
case SDC:
switch (cmd) {
case CTRL_SYNC:
return RES_OK;
case GET_SECTOR_COUNT:
*((DWORD *)buff) = mmcsdGetCardCapacity(&FATFS_HAL_DEVICE);
return RES_OK;
#if FF_MAX_SS > FF_MIN_SS
case GET_SECTOR_SIZE:
*((WORD *)buff) = MMCSD_BLOCK_SIZE;
return RES_OK;
#endif
case GET_BLOCK_SIZE:
*((DWORD *)buff) = 256; /* 512b blocks in one erase block */
return RES_OK;
#if FF_USE_TRIM
case CTRL_TRIM:
sdcErase(&FATFS_HAL_DEVICE, *((DWORD *)buff), *((DWORD *)buff + 1));
return RES_OK;
#endif
default:
return RES_PARERR;
}
#endif
}
return RES_PARERR;
}
DWORD get_fattime(void) {
#if HAL_USE_RTC
RTCDateTime timespec;
rtcGetTime(&RTCD1, &timespec);
return rtcConvertDateTimeToFAT(&timespec);
#else
return ((uint32_t)0 | (1 << 16)) | (1 << 21); /* wrong but valid time */
#endif
}
/*-----------------------------------------------------------------------*/
/* Low level disk I/O module skeleton for FatFs (C)ChaN, 2007 */
/*-----------------------------------------------------------------------*/
/* This is a stub disk I/O module that acts as front end of the existing */
/* disk I/O modules and attach it to FatFs module with common interface. */
/*-----------------------------------------------------------------------*/
#include "hal.h"
#include "ffconf.h"
#include "ff.h"
#include "diskio.h"
#if !defined(FATFS_HAL_DEVICE)
#if HAL_USE_SDC
#define FATFS_HAL_DEVICE SDCD1
#else
#define FATFS_HAL_DEVICE MMCD1
#endif
#endif
#if HAL_USE_MMC_SPI
extern MMCDriver FATFS_HAL_DEVICE;
#elif HAL_USE_SDC
extern SDCDriver FATFS_HAL_DEVICE;
#else
#error "MMC_SPI or SDC driver must be specified"
#endif
#if HAL_USE_RTC
extern RTCDriver RTCD1;
#endif
/*-----------------------------------------------------------------------*/
/* Correspondence between physical drive number and physical drive. */
/*-----------------------------------------------------------------------*/
/* Inidialize a Drive */
DSTATUS disk_initialize (
BYTE pdrv /* Physical drive number (0..) */
)
{
DSTATUS stat;
switch (pdrv) {
case 0:
stat = 0;
/* It is initialized externally, just reads the status.*/
if (blkGetDriverState(&FATFS_HAL_DEVICE) != BLK_READY)
stat |= STA_NOINIT;
if (blkIsWriteProtected(&FATFS_HAL_DEVICE))
stat |= STA_PROTECT;
return stat;
}
return STA_NOINIT;
}
/*-----------------------------------------------------------------------*/
/* Return Disk Status */
DSTATUS disk_status (
BYTE pdrv /* Physical drive number (0..) */
)
{
DSTATUS stat;
switch (pdrv) {
case 0:
stat = 0;
/* It is initialized externally, just reads the status.*/
if (blkGetDriverState(&FATFS_HAL_DEVICE) != BLK_READY)
stat |= STA_NOINIT;
if (blkIsWriteProtected(&FATFS_HAL_DEVICE))
stat |= STA_PROTECT;
return stat;
}
return STA_NOINIT;
}
/*-----------------------------------------------------------------------*/
/* Read Sector(s) */
DRESULT disk_read (
BYTE pdrv, /* Physical drive number (0..) */
BYTE *buff, /* Data buffer to store read data */
DWORD sector, /* Sector address (LBA) */
UINT count /* Number of sectors to read (1..255) */
)
{
switch (pdrv) {
case 0:
if (blkGetDriverState(&FATFS_HAL_DEVICE) != BLK_READY)
return RES_NOTRDY;
if (blkRead(&FATFS_HAL_DEVICE, sector, buff, count))
return RES_ERROR;
return RES_OK;
}
return RES_PARERR;
}
/*-----------------------------------------------------------------------*/
/* Write Sector(s) */
#if !FF_FS_READONLY
DRESULT disk_write (
BYTE pdrv, /* Physical drive number (0..) */
const BYTE *buff, /* Data to be written */
DWORD sector, /* Sector address (LBA) */
UINT count /* Number of sectors to write (1..255) */
)
{
switch (pdrv) {
case 0:
if (blkGetDriverState(&FATFS_HAL_DEVICE) != BLK_READY)
return RES_NOTRDY;
if (blkWrite(&FATFS_HAL_DEVICE, sector, buff, count))
return RES_ERROR;
return RES_OK;
}
return RES_PARERR;
}
#endif /* _FS_READONLY */
/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions */
DRESULT disk_ioctl (
BYTE pdrv, /* Physical drive number (0..) */
BYTE cmd, /* Control code */
void *buff /* Buffer to send/receive control data */
)
{
BlockDeviceInfo bdi;
(void)buff;
switch (pdrv) {
case 0:
switch (cmd) {
case CTRL_SYNC:
return RES_OK;
case GET_SECTOR_COUNT:
if (blkGetInfo(&FATFS_HAL_DEVICE, &bdi)) {
return RES_ERROR;
}
*((DWORD *)buff) = bdi.blk_num;
return RES_OK;
#if FF_MAX_SS > FF_MIN_SS
case GET_SECTOR_SIZE:
if (blkGetInfo(&FATFS_HAL_DEVICE, &bdi)) {
return RES_ERROR;
}
*((WORD *)buff) = bdi.blk_size;
return RES_OK;
#endif
#if FF_USE_TRIM
case GET_BLOCK_SIZE:
/* unsupported */
break;
case CTRL_TRIM:
/* unsupported */
break;
#endif
default:
return RES_PARERR;
}
}
return RES_PARERR;
}
DWORD get_fattime(void) {
#if HAL_USE_RTC
RTCDateTime timespec;
rtcGetTime(&RTCD1, &timespec);
return rtcConvertDateTimeToFAT(&timespec);
#else
return ((uint32_t)0 | (1 << 16)) | (1 << 21); /* wrong but valid time */
#endif
}