/** * @brief Prepares to handle read transaction. * @details Designed for read special registers from card. * * @param[in] sdcp pointer to the @p SDCDriver object * @param[out] buf pointer to the read buffer * @param[in] bytes number of bytes to read * * @return The operation status. * @retval HAL_SUCCESS operation succeeded. * @retval HAL_FAILED operation failed. * * @notapi */ static bool sdc_lld_prepare_read_bytes(SDCDriver *sdcp, uint8_t *buf, uint32_t bytes) { osalDbgCheck(bytes < 0x1000000); sdcp->sdmmc->DTIMER = SDMMC_READ_TIMEOUT; /* Checks for errors and waits for the card to be ready for reading.*/ if (_sdc_wait_for_transfer_state(sdcp)) return HAL_FAILED; /* Prepares the DMA channel for writing.*/ dmaStreamSetMemory0(sdcp->dma, buf); dmaStreamSetTransactionSize(sdcp->dma, bytes / sizeof (uint32_t)); dmaStreamSetMode(sdcp->dma, sdcp->dmamode | STM32_DMA_CR_DIR_P2M); dmaStreamEnable(sdcp->dma); /* Setting up data transfer.*/ sdcp->sdmmc->ICR = SDMMC_ICR_ALL_FLAGS; sdcp->sdmmc->MASK = SDMMC_MASK_DCRCFAILIE | SDMMC_MASK_DTIMEOUTIE | SDMMC_MASK_RXOVERRIE | SDMMC_MASK_DATAENDIE; sdcp->sdmmc->DLEN = bytes; /* Transaction starts just after DTEN bit setting.*/ sdcp->sdmmc->DCTRL = SDMMC_DCTRL_DTDIR | SDMMC_DCTRL_DTMODE | /* multibyte data transfer */ SDMMC_DCTRL_DMAEN | SDMMC_DCTRL_DTEN; return HAL_SUCCESS; }
*/ bool_t sdc_lld_read_aligned(SDCDriver *sdcp, uint32_t startblk, uint8_t *buf, uint32_t n) { uint32_t resp[1]; chDbgCheck((n < (0x1000000 / MMCSD_BLOCK_SIZE)), "max transaction size"); //SDIO->DTIMER = STM32_SDC_READ_TIMEOUT; SDIO->DTIMER = 0xFFFFFFFF; // KL /* Checks for errors and waits for the card to be ready for reading.*/ if (_sdc_wait_for_transfer_state(sdcp)) return CH_FAILED; /* Prepares the DMA channel for writing.*/ dmaStreamSetMemory0(sdcp->dma, buf); dmaStreamSetTransactionSize(sdcp->dma, (n * MMCSD_BLOCK_SIZE) / sizeof (uint32_t)); dmaStreamSetMode(sdcp->dma, sdcp->dmamode | STM32_DMA_CR_DIR_P2M); dmaStreamEnable(sdcp->dma); /* Setting up data transfer.*/ SDIO->ICR = STM32_SDIO_ICR_ALL_FLAGS; SDIO->MASK = SDIO_MASK_DCRCFAILIE | SDIO_MASK_DTIMEOUTIE | SDIO_MASK_STBITERRIE | SDIO_MASK_RXOVERRIE | SDIO_MASK_DATAENDIE; SDIO->DLEN = n * MMCSD_BLOCK_SIZE; /* Talk to card what we want from it.*/ if (sdc_lld_prepare_read(sdcp, startblk, n, resp) == TRUE) goto error; /* Transaction starts just after DTEN bit setting.*/ SDIO->DCTRL = SDIO_DCTRL_DTDIR | SDIO_DCTRL_DBLOCKSIZE_3 | SDIO_DCTRL_DBLOCKSIZE_0 | SDIO_DCTRL_DMAEN | SDIO_DCTRL_DTEN; if (sdc_lld_wait_transaction_end(sdcp, n, resp) == TRUE) goto error; return CH_SUCCESS; error: sdc_lld_error_cleanup(sdcp, n, resp); return CH_FAILED;
/** * @brief Writes one or more blocks. * * @param[in] sdcp pointer to the @p SDCDriver object * @param[in] startblk first block to write * @param[out] buf pointer to the write buffer * @param[in] n number of blocks to write * * @return The operation status. * @retval HAL_SUCCESS operation succeeded. * @retval HAL_FAILED operation failed. * * @notapi */ bool sdc_lld_write_aligned(SDCDriver *sdcp, uint32_t startblk, const uint8_t *buf, uint32_t blocks) { uint32_t resp[1]; osalDbgCheck(blocks < 0x1000000 / MMCSD_BLOCK_SIZE); sdcp->sdio->DTIMER = STM32_SDC_WRITE_TIMEOUT; /* Checks for errors and waits for the card to be ready for writing.*/ if (_sdc_wait_for_transfer_state(sdcp)) return HAL_FAILED; /* Prepares the DMA channel for writing.*/ dmaStreamSetMemory0(sdcp->dma, buf); dmaStreamSetTransactionSize(sdcp->dma, (blocks * MMCSD_BLOCK_SIZE) / sizeof (uint32_t)); dmaStreamSetMode(sdcp->dma, sdcp->dmamode | STM32_DMA_CR_DIR_M2P); dmaStreamEnable(sdcp->dma); /* Setting up data transfer.*/ sdcp->sdio->ICR = STM32_SDIO_ICR_ALL_FLAGS; sdcp->sdio->MASK = SDIO_MASK_DCRCFAILIE | SDIO_MASK_DTIMEOUTIE | SDIO_MASK_STBITERRIE | SDIO_MASK_TXUNDERRIE | SDIO_MASK_DATAENDIE; sdcp->sdio->DLEN = blocks * MMCSD_BLOCK_SIZE; /* Talk to card what we want from it.*/ if (sdc_lld_prepare_write(sdcp, startblk, blocks, resp) == TRUE) goto error; /* Transaction starts just after DTEN bit setting.*/ sdcp->sdio->DCTRL = SDIO_DCTRL_DBLOCKSIZE_3 | SDIO_DCTRL_DBLOCKSIZE_0 | SDIO_DCTRL_DMAEN | SDIO_DCTRL_DTEN; if (sdc_lld_wait_transaction_end(sdcp, blocks, resp) == TRUE) goto error; return HAL_SUCCESS; error: sdc_lld_error_cleanup(sdcp, blocks, resp); return HAL_FAILED; }
/** * @brief Reads one or more blocks. * * @param[in] sdcp pointer to the @p SDCDriver object * @param[in] startblk first block to read * @param[out] buf pointer to the read buffer, it must be aligned to * four bytes boundary * @param[in] n number of blocks to read * @return The operation status. * @retval FALSE operation succeeded, the requested blocks have been * read. * @retval TRUE operation failed, the state of the buffer is uncertain. * * @notapi */ static bool_t sdc_lld_read_multiple(SDCDriver *sdcp, uint32_t startblk, uint8_t *buf, uint32_t n) { uint32_t resp[1]; /* Checks for errors and waits for the card to be ready for reading.*/ if (_sdc_wait_for_transfer_state(sdcp)) return TRUE; /* Prepares the DMA channel for reading.*/ dmaStreamSetMemory0(STM32_DMA2_STREAM4, buf); dmaStreamSetTransactionSize(STM32_DMA2_STREAM4, (n * SDC_BLOCK_SIZE) / sizeof (uint32_t)); dmaStreamSetMode(STM32_DMA2_STREAM4, STM32_DMA_CR_PL(STM32_SDC_SDIO_DMA_PRIORITY) | STM32_DMA_CR_DIR_P2M | STM32_DMA_CR_PSIZE_WORD | STM32_DMA_CR_MSIZE_WORD | STM32_DMA_CR_MINC); /* Setting up data transfer. Options: Card to Controller, Block mode, DMA mode, 512 bytes blocks.*/ SDIO->ICR = 0xFFFFFFFF; SDIO->MASK = SDIO_MASK_DCRCFAILIE | SDIO_MASK_DTIMEOUTIE | SDIO_MASK_DATAENDIE | SDIO_MASK_STBITERRIE; SDIO->DLEN = n * SDC_BLOCK_SIZE; SDIO->DCTRL = SDIO_DCTRL_DTDIR | SDIO_DCTRL_DBLOCKSIZE_3 | SDIO_DCTRL_DBLOCKSIZE_0 | SDIO_DCTRL_DMAEN | SDIO_DCTRL_DTEN; /* DMA channel activation.*/ dmaStreamEnable(STM32_DMA2_STREAM4); /* Read multiple blocks command.*/ if ((sdcp->cardmode & SDC_MODE_HIGH_CAPACITY) == 0) startblk *= SDC_BLOCK_SIZE; if (sdc_lld_send_cmd_short_crc(sdcp, SDC_CMD_READ_MULTIPLE_BLOCK, startblk, resp) || SDC_R1_ERROR(resp[0])) goto error; chSysLock(); if (SDIO->MASK != 0) { chDbgAssert(sdcp->thread == NULL, "sdc_lld_read_multiple(), #1", "not NULL"); sdcp->thread = chThdSelf(); chSchGoSleepS(THD_STATE_SUSPENDED); chDbgAssert(sdcp->thread == NULL, "sdc_lld_read_multiple(), #2", "not NULL"); } if ((SDIO->STA & SDIO_STA_DATAEND) == 0) { chSysUnlock(); goto error; } dmaStreamDisable(STM32_DMA2_STREAM4); SDIO->ICR = 0xFFFFFFFF; SDIO->DCTRL = 0; chSysUnlock(); return sdc_lld_send_cmd_short_crc(sdcp, SDC_CMD_STOP_TRANSMISSION, 0, resp); error: dmaStreamDisable(STM32_DMA2_STREAM4); SDIO->ICR = 0xFFFFFFFF; SDIO->MASK = 0; SDIO->DCTRL = 0; return TRUE; }
/** * @brief Writes one block. * * @param[in] sdcp pointer to the @p SDCDriver object * @param[in] startblk first block to write * @param[out] buf pointer to the write buffer, it must be aligned to * four bytes boundary * @param[in] n number of blocks to write * @return The operation status. * @retval FALSE operation succeeded, the requested blocks have been * written. * @retval TRUE operation failed. * * @notapi */ static bool_t sdc_lld_write_single(SDCDriver *sdcp, uint32_t startblk, const uint8_t *buf) { uint32_t resp[1]; /* Checks for errors and waits for the card to be ready for writing.*/ if (_sdc_wait_for_transfer_state(sdcp)) return TRUE; /* Prepares the DMA channel for writing.*/ dmaStreamSetMemory0(STM32_DMA2_STREAM4, buf); dmaStreamSetTransactionSize(STM32_DMA2_STREAM4, SDC_BLOCK_SIZE / sizeof (uint32_t)); dmaStreamSetMode(STM32_DMA2_STREAM4, STM32_DMA_CR_PL(STM32_SDC_SDIO_DMA_PRIORITY) | STM32_DMA_CR_DIR_M2P | STM32_DMA_CR_PSIZE_WORD | STM32_DMA_CR_MSIZE_WORD | STM32_DMA_CR_MINC); /* Write single block command.*/ if ((sdcp->cardmode & SDC_MODE_HIGH_CAPACITY) == 0) startblk *= SDC_BLOCK_SIZE; if (sdc_lld_send_cmd_short_crc(sdcp, SDC_CMD_WRITE_BLOCK, startblk, resp) || SDC_R1_ERROR(resp[0])) return TRUE; /* Setting up data transfer. Options: Controller to Card, Block mode, DMA mode, 512 bytes blocks.*/ SDIO->ICR = 0xFFFFFFFF; SDIO->MASK = SDIO_MASK_DCRCFAILIE | SDIO_MASK_DTIMEOUTIE | SDIO_MASK_DATAENDIE | SDIO_MASK_TXUNDERRIE | SDIO_MASK_STBITERRIE; SDIO->DLEN = SDC_BLOCK_SIZE; SDIO->DCTRL = SDIO_DCTRL_DBLOCKSIZE_3 | SDIO_DCTRL_DBLOCKSIZE_0 | SDIO_DCTRL_DMAEN | SDIO_DCTRL_DTEN; /* DMA channel activation.*/ dmaStreamEnable(STM32_DMA2_STREAM4); /* Note the mask is checked before going to sleep because the interrupt may have occurred before reaching the critical zone.*/ chSysLock(); if (SDIO->MASK != 0) { chDbgAssert(sdcp->thread == NULL, "sdc_lld_write_single(), #1", "not NULL"); sdcp->thread = chThdSelf(); chSchGoSleepS(THD_STATE_SUSPENDED); chDbgAssert(sdcp->thread == NULL, "sdc_lld_write_single(), #2", "not NULL"); } if ((SDIO->STA & SDIO_STA_DATAEND) == 0) { chSysUnlock(); goto error; } dmaStreamDisable(STM32_DMA2_STREAM4); SDIO->ICR = 0xFFFFFFFF; SDIO->DCTRL = 0; chSysUnlock(); return FALSE; error: dmaStreamDisable(STM32_DMA2_STREAM4); SDIO->ICR = 0xFFFFFFFF; SDIO->MASK = 0; SDIO->DCTRL = 0; return TRUE; }