diff --git a/demos/ARMCM3-STM32F103-FATFS/main.c b/demos/ARMCM3-STM32F103-FATFS/main.c index 16d04dd49..d3e1e7e73 100644 --- a/demos/ARMCM3-STM32F103-FATFS/main.c +++ b/demos/ARMCM3-STM32F103-FATFS/main.c @@ -30,7 +30,85 @@ #include "ff.h" /*===========================================================================*/ -/* MMC/SPI related. */ +/* Card insertion monitor. */ +/*===========================================================================*/ + +#define POLLING_INTERVAL 10 +#define POLLING_DELAY 10 + +/** + * @brief Card monitor timer. + */ +static VirtualTimer tmr; + +/** + * @brief Debounce counter. + */ +static unsigned cnt; + +/** + * @brief Card event sources. + */ +static EventSource inserted_event, removed_event; + +/** + * @brief Insertion monitor timer callback function. + * + * @param[in] p pointer to the @p BaseBlockDevice object + * + * @notapi + */ +static void tmrfunc(void *p) { + BaseBlockDevice *bbdp = p; + + /* The presence check is performed only while the driver is not in a + transfer state because it is often performed by changing the mode of + the pin connected to the CS/D3 contact of the card, this could disturb + the transfer.*/ + blkstate_t state = blkGetDriverState(bbdp); + if ((state == BLK_READING) || (state == BLK_WRITING)) + return; + + /* Safe to perform the check.*/ + chSysLockFromIsr(); + if (cnt > 0) { + if (blkIsInserted(bbdp)) { + if (--cnt == 0) { + chEvtBroadcastI(&inserted_event); + } + } + else + cnt = POLLING_INTERVAL; + } + else { + if (!blkIsInserted(bbdp)) { + cnt = POLLING_INTERVAL; + chEvtBroadcastI(&removed_event); + } + } + chVTSetI(&tmr, MS2ST(POLLING_DELAY), tmrfunc, bbdp); + chSysUnlockFromIsr(); +} + +/** + * @brief Polling monitor start. + * + * @param[in] p pointer to an object implementing @p BaseBlockDevice + * + * @notapi + */ +static void tmr_init(void *p) { + + chEvtInit(&inserted_event); + chEvtInit(&removed_event); + chSysLock(); + cnt = POLLING_INTERVAL; + chVTSetI(&tmr, MS2ST(POLLING_DELAY), tmrfunc, p); + chSysUnlock(); +} + +/*===========================================================================*/ +/* FatFs related. */ /*===========================================================================*/ /** @@ -190,6 +268,10 @@ static const ShellConfig shell_cfg1 = { commands }; +/*===========================================================================*/ +/* Main and generic code. */ +/*===========================================================================*/ + /* * Red LEDs blinker thread, times are in milliseconds. */ @@ -277,6 +359,11 @@ int main(void) { mmcObjectInit(&MMCD1); mmcStart(&MMCD1, &mmccfg); + /* + * Activates the card insertion monitor. + */ + tmr_init(&MMCD1); + /* * Creates the blinker thread. */ @@ -286,8 +373,8 @@ int main(void) { * Normal main() thread activity, in this demo it does nothing except * sleeping in a loop and listen for events. */ - chEvtRegister(&MMCD1.inserted_event, &el0, 0); - chEvtRegister(&MMCD1.removed_event, &el1, 1); + chEvtRegister(&inserted_event, &el0, 0); + chEvtRegister(&removed_event, &el1, 1); while (TRUE) { if (!shelltp) shelltp = shellCreate(&shell_cfg1, SHELL_WA_SIZE, NORMALPRIO); diff --git a/os/hal/include/io_block.h b/os/hal/include/io_block.h index 2e47eb10a..acd20ebca 100644 --- a/os/hal/include/io_block.h +++ b/os/hal/include/io_block.h @@ -38,6 +38,20 @@ #ifndef _IO_BLOCK_H_ #define _IO_BLOCK_H_ +/** + * @brief Driver state machine possible states. + */ +typedef enum { + BLK_UNINIT = 0, /**< Not initialized. */ + BLK_STOP = 1, /**< Stopped. */ + BLK_ACTIVE = 2, /**< Interface active. */ + BLK_CONNECTING = 3, /**< Connection in progress. */ + BLK_DISCONNECTING = 4, /**< Disconnection in progress. */ + BLK_READY = 5, /**< Device ready. */ + BLK_READING = 6, /**< Read operation in progress. */ + BLK_WRITING = 7, /**< Write operation in progress. */ +} blkstate_t; + /** * @brief Block device info. */ @@ -71,10 +85,10 @@ typedef struct { /** * @brief @p BaseBlockDevice specific data. - * @note It is empty because @p BaseBlockDevice is only an interface - * without implementation. */ -#define _base_block_device_data +#define _base_block_device_data \ + /* Driver state.*/ \ + blkstate_t state; /** * @brief @p BaseBlockDevice virtual methods table. @@ -97,6 +111,17 @@ typedef struct { * @name Macro Functions (BaseBlockDevice) * @{ */ +/** + * @brief Returns the driver state. + * + * @param[in] ip pointer to a @p BaseBlockDevice or derived class + * + * @return The driver state. + * + * @api + */ +#define blkGetDriverState(ip) ((ip)->state) + /** * @brief Returns the media insertion status. * diff --git a/os/hal/include/mmc_spi.h b/os/hal/include/mmc_spi.h index cff70876b..b03732992 100644 --- a/os/hal/include/mmc_spi.h +++ b/os/hal/include/mmc_spi.h @@ -73,20 +73,6 @@ /* Driver data structures and types. */ /*===========================================================================*/ -/** - * @brief Driver state machine possible states. - */ -typedef enum { - MMC_UNINIT = 0, /**< Not initialized. */ - MMC_STOP = 1, /**< Stopped. */ - MMC_READY = 2, /**< Ready. */ - MMC_CONNECTING = 3, /**< Card connection in progress. */ - MMC_DISCONNECTING = 4, /**< Card disconnection in progress. */ - MMC_ACTIVE = 5, /**< Cart initialized. */ - MMC_READING = 6, /**< Read operation in progress. */ - MMC_WRITING = 7, /**< Write operation in progress. */ -} mmcstate_t; - /** * @brief MMC/SD over SPI driver configuration structure. */ @@ -131,10 +117,6 @@ typedef struct { */ const struct MMCDriverVMT *vmt; _mmcsd_block_device_data - /** - * @brief Driver state. - */ - mmcstate_t state; /** * @brief Current configuration data. */ @@ -153,16 +135,6 @@ typedef struct { * @name Macro Functions * @{ */ -/** - * @brief Returns the driver state. - * - * @param[in] mmcp pointer to the @p MMCDriver object - * @return The driver state. - * - * @api - */ -#define mmcGetDriverState(mmcp) ((mmcp)->state) - /** * @brief Returns the card insertion status. * @note This macro wraps a low level function named diff --git a/os/hal/include/mmcsd.h b/os/hal/include/mmcsd.h index a05c2602f..8eaba8ed7 100644 --- a/os/hal/include/mmcsd.h +++ b/os/hal/include/mmcsd.h @@ -216,6 +216,22 @@ typedef struct { /* Driver macros. */ /*===========================================================================*/ +/** + * @name Macro Functions + * @{ + */ +/** + * @brief Returns the card capacity in blocks. + * + * @param[in] ip pointer to a @p MMCSDBlockDevice or derived class + * + * @return The card capacity. + * + * @api + */ +#define mmcsdGetCardCapacity(ip) ((ip)->capacity) +/** @} */ + /*===========================================================================*/ /* External declarations. */ /*===========================================================================*/ diff --git a/os/hal/src/mmc_spi.c b/os/hal/src/mmc_spi.c index 1b9271944..96167a950 100644 --- a/os/hal/src/mmc_spi.c +++ b/os/hal/src/mmc_spi.c @@ -380,7 +380,7 @@ void mmcInit(void) { void mmcObjectInit(MMCDriver *mmcp) { mmcp->vmt = &mmc_vmt; - mmcp->state = MMC_STOP; + mmcp->state = BLK_STOP; mmcp->config = NULL; mmcp->block_addresses = FALSE; } @@ -396,13 +396,11 @@ void mmcObjectInit(MMCDriver *mmcp) { void mmcStart(MMCDriver *mmcp, const MMCConfig *config) { chDbgCheck((mmcp != NULL) && (config != NULL), "mmcStart"); - - chSysLock(); - chDbgAssert((mmcp->state == MMC_STOP) || (mmcp->state == MMC_READY), + chDbgAssert((mmcp->state == BLK_STOP) || (mmcp->state == BLK_ACTIVE), "mmcStart(), #1", "invalid state"); + mmcp->config = config; - mmcp->state = MMC_READY; - chSysUnlock(); + mmcp->state = BLK_ACTIVE; } /** @@ -415,13 +413,11 @@ void mmcStart(MMCDriver *mmcp, const MMCConfig *config) { void mmcStop(MMCDriver *mmcp) { chDbgCheck(mmcp != NULL, "mmcStop"); - - chSysLock(); - chDbgAssert((mmcp->state == MMC_STOP) || (mmcp->state == MMC_READY), + chDbgAssert((mmcp->state == BLK_STOP) || (mmcp->state == BLK_ACTIVE), "mmcStop(), #1", "invalid state"); - mmcp->state = MMC_STOP; - chSysUnlock(); + spiStop(mmcp->config->spip); + mmcp->state = BLK_STOP; } /** @@ -446,11 +442,11 @@ bool_t mmcConnect(MMCDriver *mmcp) { chDbgCheck(mmcp != NULL, "mmcConnect"); - chSysLock(); - chDbgAssert((mmcp->state == MMC_READY) || (mmcp->state == MMC_ACTIVE), + chDbgAssert((mmcp->state == BLK_ACTIVE) || (mmcp->state == BLK_READY), "mmcConnect(), #1", "invalid state"); - mmcp->state = MMC_CONNECTING; - chSysUnlock(); + + /* Connection procedure in progress.*/ + mmcp->state = BLK_CONNECTING; /* Slow clock mode and 128 clock pulses.*/ spiStart(mmcp->config->spip, mmcp->config->lscfg); @@ -491,7 +487,7 @@ bool_t mmcConnect(MMCDriver *mmcp) { 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] & 0x40) + if (r3[0] & 0x40) mmcp->block_addresses = TRUE; } @@ -526,10 +522,13 @@ bool_t mmcConnect(MMCDriver *mmcp) { if (read_CxD(mmcp, MMCSD_CMD_SEND_CID, mmcp->cid)) goto failed; - mmcp->state = MMC_READY; + mmcp->state = BLK_READY; return CH_SUCCESS; + + /* Connection failed, state reset to BLK_ACTIVE.*/ failed: - mmcp->state = MMC_READY; + spiStop(mmcp->config->spip); + mmcp->state = BLK_ACTIVE; return CH_FAILED; } @@ -550,20 +549,20 @@ bool_t mmcDisconnect(MMCDriver *mmcp) { chDbgCheck(mmcp != NULL, "mmcDisconnect"); chSysLock(); - chDbgAssert((mmcp->state == MMC_READY) || (mmcp->state == MMC_ACTIVE), + chDbgAssert((mmcp->state == BLK_ACTIVE) || (mmcp->state == BLK_READY), "mmcDisconnect(), #1", "invalid state"); - if (mmcp->state == MMC_READY) { + if (mmcp->state == BLK_ACTIVE) { chSysUnlock(); return CH_SUCCESS; } - mmcp->state = MMC_DISCONNECTING; + mmcp->state = BLK_DISCONNECTING; chSysUnlock(); /* Wait for the pending write operations to complete.*/ sync(mmcp); - spiStop(mmcp->config->spip); - mmcp->state = MMC_READY; + spiStop(mmcp->config->spip); + mmcp->state = BLK_ACTIVE; return CH_SUCCESS; } @@ -582,25 +581,24 @@ bool_t mmcDisconnect(MMCDriver *mmcp) { bool_t mmcStartSequentialRead(MMCDriver *mmcp, uint32_t startblk) { chDbgCheck(mmcp != NULL, "mmcStartSequentialRead"); - - chSysLock(); - chDbgAssert(mmcp->state == MMC_ACTIVE, + chDbgAssert(mmcp->state == BLK_READY, "mmcStartSequentialRead(), #1", "invalid state"); - mmcp->state = MMC_READING; - chSysUnlock(); + + /* 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) + 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) != 0x00) { - mmcp->state = MMC_READY; + spiStop(mmcp->config->spip); return CH_FAILED; } return CH_SUCCESS; @@ -623,7 +621,7 @@ bool_t mmcSequentialRead(MMCDriver *mmcp, uint8_t *buffer) { chDbgCheck((mmcp != NULL) && (buffer != NULL), "mmcSequentialRead"); - if (mmcp->state != MMC_READING) + if (mmcp->state != BLK_READING) return CH_FAILED; for (i = 0; i < MMC_WAIT_DATA; i++) { @@ -637,7 +635,7 @@ bool_t mmcSequentialRead(MMCDriver *mmcp, uint8_t *buffer) { } /* Timeout.*/ spiUnselect(mmcp->config->spip); - mmcp->state = MMC_READY; + spiStop(mmcp->config->spip); return CH_FAILED; } @@ -658,7 +656,7 @@ bool_t mmcStopSequentialRead(MMCDriver *mmcp) { chDbgCheck(mmcp != NULL, "mmcStopSequentialRead"); - if (mmcp->state != MMC_READING) + if (mmcp->state != BLK_READING) return CH_FAILED; spiSend(mmcp->config->spip, sizeof(stopcmd), stopcmd); @@ -666,8 +664,9 @@ bool_t mmcStopSequentialRead(MMCDriver *mmcp) { /* Note, ignored r1 response, it can be not zero, unknown issue.*/ (void) recvr1(mmcp); + /* Read operation finished.*/ spiUnselect(mmcp->config->spip); - mmcp->state = MMC_READY; + mmcp->state = BLK_READY; return CH_SUCCESS; } @@ -686,23 +685,22 @@ bool_t mmcStopSequentialRead(MMCDriver *mmcp) { bool_t mmcStartSequentialWrite(MMCDriver *mmcp, uint32_t startblk) { chDbgCheck(mmcp != NULL, "mmcStartSequentialWrite"); - - chSysLock(); - chDbgAssert(mmcp->state == MMC_ACTIVE, + chDbgAssert(mmcp->state == BLK_READY, "mmcStartSequentialWrite(), #1", "invalid state"); - mmcp->state = MMC_WRITING; - chSysUnlock(); + + /* Write operation in progress.*/ + mmcp->state = BLK_WRITING; spiStart(mmcp->config->spip, mmcp->config->hscfg); spiSelect(mmcp->config->spip); - if(mmcp->block_addresses) + 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) != 0x00) { - mmcp->state = MMC_READY; + spiStop(mmcp->config->spip); return CH_FAILED; } return CH_SUCCESS; @@ -726,7 +724,7 @@ bool_t mmcSequentialWrite(MMCDriver *mmcp, const uint8_t *buffer) { chDbgCheck((mmcp != NULL) && (buffer != NULL), "mmcSequentialWrite"); - if (mmcp->state != MMC_WRITING) + if (mmcp->state != BLK_WRITING) return CH_FAILED; spiSend(mmcp->config->spip, sizeof(start), start); /* Data prologue. */ @@ -740,7 +738,7 @@ bool_t mmcSequentialWrite(MMCDriver *mmcp, const uint8_t *buffer) { /* Error.*/ spiUnselect(mmcp->config->spip); - mmcp->state = MMC_READY; + spiStop(mmcp->config->spip); return CH_FAILED; } @@ -760,14 +758,14 @@ bool_t mmcStopSequentialWrite(MMCDriver *mmcp) { chDbgCheck(mmcp != NULL, "mmcStopSequentialWrite"); - if (mmcp->state != MMC_WRITING) + if (mmcp->state != BLK_WRITING) return CH_FAILED; spiSend(mmcp->config->spip, sizeof(stop), stop); spiUnselect(mmcp->config->spip); - chSysLock(); - mmcp->state = MMC_READY; + /* Write operation finished.*/ + mmcp->state = BLK_READY; return CH_SUCCESS; } @@ -786,7 +784,7 @@ bool_t mmcSync(MMCDriver *mmcp) { chDbgCheck(mmcp != NULL, "mmcSync"); - if (mmcp->state != MMC_READY) + if (mmcp->state != BLK_READY) return CH_FAILED; sync(mmcp); @@ -809,11 +807,12 @@ bool_t mmcGetInfo(MMCDriver *mmcp, BlockDeviceInfo *bdip) { chDbgCheck((mmcp != NULL) && (bdip != NULL), "mmcGetInfo"); - if (mmcp->state != MMC_READY) + if (mmcp->state != BLK_READY) return CH_FAILED; bdip->blk_num = mmcp->capacity; bdip->blk_size = MMCSD_BLOCK_SIZE; + return CH_SUCCESS; } @@ -834,18 +833,28 @@ bool_t mmcErase(MMCDriver *mmcp, uint32_t startblk, uint32_t endblk) { chDbgCheck((mmcp != NULL), "mmcErase"); + /* 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)) - return CH_FAILED; + goto failed; if (send_command_R1(mmcp, MMCSD_CMD_ERASE_RW_BLK_END, endblk)) - return CH_FAILED; + goto failed; if (send_command_R1(mmcp, MMCSD_CMD_ERASE, 0)) - return CH_FAILED; + goto failed; return CH_SUCCESS; -} + /* Command failed, state reset to BLK_ACTIVE.*/ +failed: + spiStop(mmcp->config->spip); + return CH_FAILED; +} #endif /* HAL_USE_MMC_SPI */ diff --git a/os/various/fatfs_bindings/fatfs_diskio.c b/os/various/fatfs_bindings/fatfs_diskio.c index 3a8b6866e..40f3666a4 100644 --- a/os/various/fatfs_bindings/fatfs_diskio.c +++ b/os/various/fatfs_bindings/fatfs_diskio.c @@ -49,7 +49,7 @@ DSTATUS disk_initialize ( case MMC: stat = 0; /* It is initialized externally, just reads the status.*/ - if (mmcGetDriverState(&MMCD1) != MMC_READY) + if (blkGetDriverState(&MMCD1) != BLK_READY) stat |= STA_NOINIT; if (mmcIsWriteProtected(&MMCD1)) stat |= STA_PROTECT; @@ -58,7 +58,7 @@ DSTATUS disk_initialize ( case SDC: stat = 0; /* It is initialized externally, just reads the status.*/ - if (sdcGetDriverState(&SDCD1) != SDC_ACTIVE) + if (blkGetDriverState(&SDCD1) != BLK_READY) stat |= STA_NOINIT; if (sdcIsWriteProtected(&SDCD1)) stat |= STA_PROTECT; @@ -84,7 +84,7 @@ DSTATUS disk_status ( case MMC: stat = 0; /* It is initialized externally, just reads the status.*/ - if (mmcGetDriverState(&MMCD1) != MMC_READY) + if (blkGetDriverState(&MMCD1) != BLK_READY) stat |= STA_NOINIT; if (mmcIsWriteProtected(&MMCD1)) stat |= STA_PROTECT; @@ -93,7 +93,7 @@ DSTATUS disk_status ( case SDC: stat = 0; /* It is initialized externally, just reads the status.*/ - if (sdcGetDriverState(&SDCD1) != SDC_ACTIVE) + if (blkGetDriverState(&SDCD1) != BLK_READY) stat |= STA_NOINIT; if (sdcIsWriteProtected(&SDCD1)) stat |= STA_PROTECT; @@ -118,7 +118,7 @@ DRESULT disk_read ( switch (drv) { #if HAL_USE_MMC_SPI case MMC: - if (mmcGetDriverState(&MMCD1) != MMC_READY) + if (blkGetDriverState(&MMCD1) != BLK_READY) return RES_NOTRDY; if (mmcStartSequentialRead(&MMCD1, sector)) return RES_ERROR; @@ -133,7 +133,7 @@ DRESULT disk_read ( return RES_OK; #else case SDC: - if (sdcGetDriverState(&SDCD1) != SDC_ACTIVE) + if (blkGetDriverState(&SDCD1) != BLK_READY) return RES_NOTRDY; if (sdcRead(&SDCD1, sector, buff, count)) return RES_ERROR; @@ -159,7 +159,7 @@ DRESULT disk_write ( switch (drv) { #if HAL_USE_MMC_SPI case MMC: - if (mmcGetDriverState(&MMCD1) != MMC_READY) + if (blkGetDriverState(&MMCD1) != BLK_READY) return RES_NOTRDY; if (mmcIsWriteProtected(&MMCD1)) return RES_WRPRT; @@ -176,7 +176,7 @@ DRESULT disk_write ( return RES_OK; #else case SDC: - if (sdcGetDriverState(&SDCD1) != SDC_ACTIVE) + if (blkGetDriverState(&SDCD1) != BLK_READY) return RES_NOTRDY; if (sdcWrite(&SDCD1, sector, buff, count)) return RES_ERROR;