Improvements to the STM32 SDC driver.
git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@3001 35acf78f-673a-0410-8e92-d51de3d6d3f4master
parent
a3239bf257
commit
88e92b3fc3
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 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;
|
||||
}
|
||||
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_write_single(sdcp, startblk, buf);
|
||||
return sdc_lld_write_multiple(sdcp, startblk, buf, n);
|
||||
}
|
||||
|
||||
#endif /* HAL_USE_SDC */
|
||||
|
|
|
@ -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. */
|
||||
/*===========================================================================*/
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue