diff options
-rw-r--r-- | docs/Doxyfile_chm | 2 | ||||
-rw-r--r-- | docs/Doxyfile_html | 2 | ||||
-rw-r--r-- | os/hal/include/sdc.h | 2 | ||||
-rw-r--r-- | os/hal/platforms/STM32/sdc_lld.c | 470 | ||||
-rw-r--r-- | os/hal/platforms/STM32/sdc_lld.h | 7 | ||||
-rw-r--r-- | os/hal/src/sdc.c | 8 | ||||
-rw-r--r-- | os/kernel/include/ch.h | 4 | ||||
-rw-r--r-- | readme.txt | 3 | ||||
-rw-r--r-- | testhal/STM32/SDIO/main.c | 43 |
9 files changed, 417 insertions, 124 deletions
diff --git a/docs/Doxyfile_chm b/docs/Doxyfile_chm index f6580b758..f088be782 100644 --- a/docs/Doxyfile_chm +++ b/docs/Doxyfile_chm @@ -31,7 +31,7 @@ PROJECT_NAME = ChibiOS/RT # This could be handy for archiving the generated documentation or
# if some version control system is used.
-PROJECT_NUMBER = 2.3.3
+PROJECT_NUMBER = 2.3.4
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer
diff --git a/docs/Doxyfile_html b/docs/Doxyfile_html index 0d2e6e31b..ab9d037da 100644 --- a/docs/Doxyfile_html +++ b/docs/Doxyfile_html @@ -31,7 +31,7 @@ PROJECT_NAME = ChibiOS/RT # This could be handy for archiving the generated documentation or
# if some version control system is used.
-PROJECT_NUMBER = 2.3.3
+PROJECT_NUMBER = 2.3.4
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer
diff --git a/os/hal/include/sdc.h b/os/hal/include/sdc.h index 1c095221b..2c35b8a0e 100644 --- a/os/hal/include/sdc.h +++ b/os/hal/include/sdc.h @@ -74,8 +74,10 @@ #define SDC_CMD_STOP_TRANSMISSION 12
#define SDC_CMD_SEND_STATUS 13
#define SDC_CMD_SET_BLOCKLEN 16
+#define SDC_CMD_READ_SINGLE_BLOCK 17
#define SDC_CMD_READ_MULTIPLE_BLOCK 18
#define SDC_CMD_SET_BLOCK_COUNT 23
+#define SDC_CMD_WRITE_BLOCK 24
#define SDC_CMD_WRITE_MULTIPLE_BLOCK 25
#define SDC_CMD_APP_OP_COND 41
#define SDC_CMD_LOCK_UNLOCK 42
diff --git a/os/hal/platforms/STM32/sdc_lld.c b/os/hal/platforms/STM32/sdc_lld.c index 755fdf5ab..c790f49d9 100644 --- a/os/hal/platforms/STM32/sdc_lld.c +++ b/os/hal/platforms/STM32/sdc_lld.c @@ -26,6 +26,8 @@ * @{
*/
+#include <string.h>
+
#include "ch.h"
#include "hal.h"
@@ -42,10 +44,339 @@ SDCDriver SDCD1; /* Driver local variables. */
/*===========================================================================*/
+#if STM32_SDC_UNALIGNED_SUPPORT
+/**
+ * @brief Buffer for temporary storage during unaligned transfers.
+ */
+static union {
+ uint32_t alignment;
+ uint8_t buf[SDC_BLOCK_SIZE];
+} u;
+#endif
+
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
+/**
+ * @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.*/
+ dmaChannelSetup(&STM32_DMA2->channels[STM32_DMA_CHANNEL_4],
+ (n * SDC_BLOCK_SIZE) / sizeof (uint32_t), buf,
+ (STM32_SDC_SDIO_DMA_PRIORITY << 12) |
+ DMA_CCR1_PSIZE_1 | DMA_CCR1_MSIZE_1 |
+ DMA_CCR1_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.*/
+ dmaEnableChannel(STM32_DMA2, STM32_DMA_CHANNEL_4);
+
+ /* 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;
+ }
+ dmaDisableChannel(STM32_DMA2, STM32_DMA_CHANNEL_4);
+ SDIO->ICR = 0xFFFFFFFF;
+ SDIO->DCTRL = 0;
+ chSysUnlock();
+
+ return sdc_lld_send_cmd_short_crc(sdcp, SDC_CMD_STOP_TRANSMISSION, 0, resp);
+error:
+ dmaDisableChannel(STM32_DMA2, STM32_DMA_CHANNEL_4);
+ SDIO->ICR = 0xFFFFFFFF;
+ SDIO->MASK = 0;
+ SDIO->DCTRL = 0;
+ return TRUE;
+}
+
+/**
+ * @brief Reads one block.
+ *
+ * @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
+ * @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_single(SDCDriver *sdcp, uint32_t startblk,
+ uint8_t *buf) {
+ 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.*/
+ dmaChannelSetup(&STM32_DMA2->channels[STM32_DMA_CHANNEL_4],
+ SDC_BLOCK_SIZE / sizeof (uint32_t), buf,
+ (STM32_SDC_SDIO_DMA_PRIORITY << 12) |
+ DMA_CCR1_PSIZE_1 | DMA_CCR1_MSIZE_1 |
+ DMA_CCR1_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 = 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.*/
+ dmaEnableChannel(STM32_DMA2, STM32_DMA_CHANNEL_4);
+
+ /* Read 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_READ_SINGLE_BLOCK,
+ startblk, resp) ||
+ SDC_R1_ERROR(resp[0]))
+ goto error;
+
+ chSysLock();
+ if (SDIO->MASK != 0) {
+ chDbgAssert(sdcp->thread == NULL,
+ "sdc_lld_read_single(), #1", "not NULL");
+ sdcp->thread = chThdSelf();
+ chSchGoSleepS(THD_STATE_SUSPENDED);
+ chDbgAssert(sdcp->thread == NULL,
+ "sdc_lld_read_single(), #2", "not NULL");
+ }
+ if ((SDIO->STA & SDIO_STA_DATAEND) == 0) {
+ chSysUnlock();
+ goto error;
+ }
+ dmaDisableChannel(STM32_DMA2, STM32_DMA_CHANNEL_4);
+ SDIO->ICR = 0xFFFFFFFF;
+ SDIO->DCTRL = 0;
+ chSysUnlock();
+
+ return FALSE;
+error:
+ dmaDisableChannel(STM32_DMA2, STM32_DMA_CHANNEL_4);
+ SDIO->ICR = 0xFFFFFFFF;
+ SDIO->MASK = 0;
+ SDIO->DCTRL = 0;
+ return TRUE;
+}
+
+/**
+ * @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, 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_multiple(SDCDriver *sdcp, uint32_t startblk,
+ const uint8_t *buf, uint32_t n) {
+ 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.*/
+ dmaChannelSetup(&STM32_DMA2->channels[STM32_DMA_CHANNEL_4],
+ (n * SDC_BLOCK_SIZE) / sizeof (uint32_t), buf,
+ (STM32_SDC_SDIO_DMA_PRIORITY << 12) |
+ DMA_CCR1_PSIZE_1 | DMA_CCR1_MSIZE_1 |
+ DMA_CCR1_MINC | DMA_CCR1_DIR);
+
+ /* Write 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_WRITE_MULTIPLE_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 = n * SDC_BLOCK_SIZE;
+ SDIO->DCTRL = SDIO_DCTRL_DBLOCKSIZE_3 | SDIO_DCTRL_DBLOCKSIZE_0 |
+ SDIO_DCTRL_DMAEN |
+ SDIO_DCTRL_DTEN;
+
+ /* DMA channel activation.*/
+ dmaEnableChannel(STM32_DMA2, STM32_DMA_CHANNEL_4);
+
+ /* 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_multiple(), #1", "not NULL");
+ sdcp->thread = chThdSelf();
+ chSchGoSleepS(THD_STATE_SUSPENDED);
+ chDbgAssert(sdcp->thread == NULL,
+ "sdc_lld_write_multiple(), #2", "not NULL");
+ }
+ if ((SDIO->STA & SDIO_STA_DATAEND) == 0) {
+ chSysUnlock();
+ goto error;
+ }
+ dmaDisableChannel(STM32_DMA2, STM32_DMA_CHANNEL_4);
+ SDIO->ICR = 0xFFFFFFFF;
+ SDIO->DCTRL = 0;
+ chSysUnlock();
+
+ return sdc_lld_send_cmd_short_crc(sdcp, SDC_CMD_STOP_TRANSMISSION, 0, resp);
+error:
+ dmaDisableChannel(STM32_DMA2, STM32_DMA_CHANNEL_4);
+ 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.*/
+ dmaChannelSetup(&STM32_DMA2->channels[STM32_DMA_CHANNEL_4],
+ SDC_BLOCK_SIZE / sizeof (uint32_t), buf,
+ (STM32_SDC_SDIO_DMA_PRIORITY << 12) |
+ DMA_CCR1_PSIZE_1 | DMA_CCR1_MSIZE_1 |
+ DMA_CCR1_MINC | DMA_CCR1_DIR);
+
+ /* 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.*/
+ dmaEnableChannel(STM32_DMA2, STM32_DMA_CHANNEL_4);
+
+ /* 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;
+ }
+ dmaDisableChannel(STM32_DMA2, STM32_DMA_CHANNEL_4);
+ SDIO->ICR = 0xFFFFFFFF;
+ SDIO->DCTRL = 0;
+ chSysUnlock();
+
+ return FALSE;
+error:
+ dmaDisableChannel(STM32_DMA2, STM32_DMA_CHANNEL_4);
+ SDIO->ICR = 0xFFFFFFFF;
+ SDIO->MASK = 0;
+ SDIO->DCTRL = 0;
+ return TRUE;
+}
+
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
@@ -331,61 +662,23 @@ bool_t sdc_lld_send_cmd_long_crc(SDCDriver *sdcp, uint8_t cmd, uint32_t arg, */
bool_t sdc_lld_read(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.*/
- dmaChannelSetup(&STM32_DMA2->channels[STM32_DMA_CHANNEL_4],
- (n * SDC_BLOCK_SIZE) / sizeof (uint32_t), buf,
- (STM32_SDC_SDIO_DMA_PRIORITY << 12) |
- DMA_CCR1_PSIZE_1 | DMA_CCR1_MSIZE_1 |
- DMA_CCR1_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.*/
- dmaEnableChannel(STM32_DMA2, STM32_DMA_CHANNEL_4);
-
- 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(), #1", "not NULL");
- sdcp->thread = chThdSelf();
- chSchGoSleepS(THD_STATE_SUSPENDED);
- chDbgAssert(sdcp->thread == NULL, "sdc_lld_read(), #2", "not NULL");
+#if STM32_SDC_UNALIGNED_SUPPORT
+ if (((unsigned)buf & 3) != 0) {
+ uint32_t i;
+ for (i = 0; i < n; i++) {
+ if (sdc_lld_read_single(sdcp, startblk, u.buf))
+ return TRUE;
+ memcpy(buf, u.buf, SDC_BLOCK_SIZE);
+ buf += SDC_BLOCK_SIZE;
+ startblk++;
+ }
+ return FALSE;
}
- if ((SDIO->STA & SDIO_STA_DATAEND) == 0) {
- chSysUnlock();
- goto error;
- }
- dmaDisableChannel(STM32_DMA2, STM32_DMA_CHANNEL_4);
- SDIO->ICR = 0xFFFFFFFF;
- SDIO->DCTRL = 0;
- chSysUnlock();
-
- return sdc_lld_send_cmd_short_crc(sdcp, SDC_CMD_STOP_TRANSMISSION, 0, resp);
-error:
- dmaDisableChannel(STM32_DMA2, STM32_DMA_CHANNEL_4);
- SDIO->ICR = 0xFFFFFFFF;
- SDIO->MASK = 0;
- SDIO->DCTRL = 0;
- return TRUE;
+#endif
+ if (n == 1)
+ return sdc_lld_read_single(sdcp, startblk, buf);
+ return sdc_lld_read_multiple(sdcp, startblk, buf, n);
}
/**
@@ -404,64 +697,23 @@ error: */
bool_t sdc_lld_write(SDCDriver *sdcp, uint32_t startblk,
const uint8_t *buf, uint32_t n) {
- 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.*/
- dmaChannelSetup(&STM32_DMA2->channels[STM32_DMA_CHANNEL_4],
- (n * SDC_BLOCK_SIZE) / sizeof (uint32_t), buf,
- (STM32_SDC_SDIO_DMA_PRIORITY << 12) |
- DMA_CCR1_PSIZE_1 | DMA_CCR1_MSIZE_1 |
- DMA_CCR1_MINC | DMA_CCR1_DIR);
-
- /* Write multiple blocks command.*/
- if (sdc_lld_send_cmd_short_crc(sdcp, SDC_CMD_WRITE_MULTIPLE_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 = n * SDC_BLOCK_SIZE;
- SDIO->DCTRL = SDIO_DCTRL_DBLOCKSIZE_3 | SDIO_DCTRL_DBLOCKSIZE_0 |
- SDIO_DCTRL_DMAEN |
- SDIO_DCTRL_DTEN;
- /* DMA channel activation.*/
- dmaEnableChannel(STM32_DMA2, STM32_DMA_CHANNEL_4);
-
- /* 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(), #1", "not NULL");
- sdcp->thread = chThdSelf();
- chSchGoSleepS(THD_STATE_SUSPENDED);
- chDbgAssert(sdcp->thread == NULL, "sdc_lld_write(), #2", "not NULL");
- }
- if ((SDIO->STA & SDIO_STA_DATAEND) == 0) {
- chSysUnlock();
- goto error;
+ #if STM32_SDC_UNALIGNED_SUPPORT
+ if (((unsigned)buf & 3) != 0) {
+ uint32_t i;
+ for (i = 0; i < n; i++) {
+ memcpy(u.buf, buf, SDC_BLOCK_SIZE);
+ buf += SDC_BLOCK_SIZE;
+ if (sdc_lld_write_single(sdcp, startblk, u.buf))
+ return TRUE;
+ startblk++;
+ }
+ return FALSE;
}
- dmaDisableChannel(STM32_DMA2, STM32_DMA_CHANNEL_4);
- SDIO->ICR = 0xFFFFFFFF;
- SDIO->DCTRL = 0;
- chSysUnlock();
-
- return sdc_lld_send_cmd_short_crc(sdcp, SDC_CMD_STOP_TRANSMISSION, 0, resp);
-error:
- dmaDisableChannel(STM32_DMA2, STM32_DMA_CHANNEL_4);
- SDIO->ICR = 0xFFFFFFFF;
- SDIO->MASK = 0;
- SDIO->DCTRL = 0;
- return TRUE;
+#endif
+ if (n == 1)
+ return sdc_lld_write_single(sdcp, startblk, buf);
+ return sdc_lld_write_multiple(sdcp, startblk, buf, n);
}
#endif /* HAL_USE_SDC */
diff --git a/os/hal/platforms/STM32/sdc_lld.h b/os/hal/platforms/STM32/sdc_lld.h index 4263e5d6d..c0d1b8bdd 100644 --- a/os/hal/platforms/STM32/sdc_lld.h +++ b/os/hal/platforms/STM32/sdc_lld.h @@ -61,6 +61,13 @@ #define STM32_SDC_SDIO_IRQ_PRIORITY 9
#endif
+/**
+ * @brief SDIO support for unaligned transfers.
+ */
+#if !defined(STM32_SDC_UNALIGNED_SUPPORT) || defined(__DOXYGEN__)
+#define STM32_SDC_UNALIGNED_SUPPORT TRUE
+#endif
+
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
diff --git a/os/hal/src/sdc.c b/os/hal/src/sdc.c index 7eaa8e631..a7a39c268 100644 --- a/os/hal/src/sdc.c +++ b/os/hal/src/sdc.c @@ -343,9 +343,6 @@ bool_t sdcRead(SDCDriver *sdcp, uint32_t startblk, sdcp->state = SDC_READING;
chSysUnlock();
- if ((sdcp->cardmode & SDC_MODE_HIGH_CAPACITY) == 0)
- startblk *= SDC_BLOCK_SIZE;
-
err = sdc_lld_read(sdcp, startblk, buf, n);
sdcp->state = SDC_ACTIVE;
return err;
@@ -371,16 +368,13 @@ bool_t sdcWrite(SDCDriver *sdcp, uint32_t startblk, const uint8_t *buf, uint32_t n) {
bool_t err;
- chDbgCheck((sdcp != NULL) && (buf != NULL) && (n > 0), "sdcRead");
+ chDbgCheck((sdcp != NULL) && (buf != NULL) && (n > 0), "sdcWrite");
chSysLock();
chDbgAssert(sdcp->state == SDC_ACTIVE, "sdcWrite(), #1", "invalid state");
sdcp->state = SDC_WRITING;
chSysUnlock();
- if ((sdcp->cardmode & SDC_MODE_HIGH_CAPACITY) == 0)
- startblk *= SDC_BLOCK_SIZE;
-
err = sdc_lld_write(sdcp, startblk, buf, n);
sdcp->state = SDC_ACTIVE;
return err;
diff --git a/os/kernel/include/ch.h b/os/kernel/include/ch.h index db96d4338..250f6adbf 100644 --- a/os/kernel/include/ch.h +++ b/os/kernel/include/ch.h @@ -40,7 +40,7 @@ /**
* @brief Kernel version string.
*/
-#define CH_KERNEL_VERSION "2.3.3unstable"
+#define CH_KERNEL_VERSION "2.3.4unstable"
/**
* @brief Kernel version major number.
@@ -55,7 +55,7 @@ /**
* @brief Kernel version patch number.
*/
-#define CH_KERNEL_PATCH 3
+#define CH_KERNEL_PATCH 4
/*
* Common values.
diff --git a/readme.txt b/readme.txt index 4c7893b37..cfa33c642 100644 --- a/readme.txt +++ b/readme.txt @@ -70,6 +70,9 @@ *** Releases ***
*****************************************************************************
+*** 2.3.4 ***
+- NEW: Now the STM32 SDC driver supports unaligned buffers transparently.
+
*** 2.3.3 ***
- FIX: Fixed race condition in output queues (bug 3303908)(backported
to 2.2.4).
diff --git a/testhal/STM32/SDIO/main.c b/testhal/STM32/SDIO/main.c index 8c5452ed7..9736f0268 100644 --- a/testhal/STM32/SDIO/main.c +++ b/testhal/STM32/SDIO/main.c @@ -28,7 +28,7 @@ static const SDCConfig sdccfg = { 0
};
-static uint8_t blkbuf[SDC_BLOCK_SIZE * 4];
+static uint8_t blkbuf[SDC_BLOCK_SIZE * 4 + 1];
/*
* Application entry point.
@@ -51,12 +51,36 @@ int main(void) { sdcStart(&SDCD1, &sdccfg);
if (!sdcConnect(&SDCD1)) {
int i;
- /* Repeated multiple reads.*/
- for (i = 0; i < 5000; i++) {
+
+ /* Single aligned read.*/
+ if (sdcRead(&SDCD1, 0, blkbuf, 1))
+ chSysHalt();
+
+ /* Single unaligned read.*/
+ if (sdcRead(&SDCD1, 0, blkbuf + 1, 1))
+ chSysHalt();
+
+ /* Multiple aligned read.*/
+ if (sdcRead(&SDCD1, 0, blkbuf, 4))
+ chSysHalt();
+
+ /* Multiple unaligned read.*/
+ if (sdcRead(&SDCD1, 0, blkbuf + 1, 4))
+ chSysHalt();
+
+ /* Repeated multiple aligned reads.*/
+ for (i = 0; i < 1000; i++) {
if (sdcRead(&SDCD1, 0, blkbuf, 4))
chSysHalt();
}
- /* Repeated multiple write.*/
+
+ /* Repeated multiple unaligned reads.*/
+ for (i = 0; i < 1000; i++) {
+ if (sdcRead(&SDCD1, 0, blkbuf + 1, 4))
+ chSysHalt();
+ }
+
+ /* Repeated multiple aligned writes.*/
for (i = 0; i < 100; i++) {
if (sdcRead(&SDCD1, 0x10000, blkbuf, 4))
chSysHalt();
@@ -65,6 +89,17 @@ int main(void) { if (sdcWrite(&SDCD1, 0x10000, blkbuf, 4))
chSysHalt();
}
+
+ /* Repeated multiple unaligned writes.*/
+ for (i = 0; i < 100; i++) {
+ if (sdcRead(&SDCD1, 0x10000, blkbuf + 1, 4))
+ chSysHalt();
+ if (sdcWrite(&SDCD1, 0x10000, blkbuf + 1, 4))
+ chSysHalt();
+ if (sdcWrite(&SDCD1, 0x10000, blkbuf + 1, 4))
+ chSysHalt();
+ }
+
if (sdcDisconnect(&SDCD1))
chSysHalt();
}
|