aboutsummaryrefslogtreecommitdiffstats
path: root/os
diff options
context:
space:
mode:
authorgdisirio <gdisirio@35acf78f-673a-0410-8e92-d51de3d6d3f4>2011-05-08 09:58:19 +0000
committergdisirio <gdisirio@35acf78f-673a-0410-8e92-d51de3d6d3f4>2011-05-08 09:58:19 +0000
commit82f529d70e6e0c3e1af5d2598809f307f40c95c0 (patch)
tree7eeb4caf86adee32cc2b74ef13c31b8222a01da4 /os
parenteb36dbf4fe229a76e09219fc6ed0b3ce9d81095f (diff)
downloadChibiOS-82f529d70e6e0c3e1af5d2598809f307f40c95c0.tar.gz
ChibiOS-82f529d70e6e0c3e1af5d2598809f307f40c95c0.tar.bz2
ChibiOS-82f529d70e6e0c3e1af5d2598809f307f40c95c0.zip
SDC write implemented (not tested yet=, optimizations to the SDC read.
git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@2934 35acf78f-673a-0410-8e92-d51de3d6d3f4
Diffstat (limited to 'os')
-rw-r--r--os/hal/platforms/STM32/sdc_lld.c78
1 files changed, 70 insertions, 8 deletions
diff --git a/os/hal/platforms/STM32/sdc_lld.c b/os/hal/platforms/STM32/sdc_lld.c
index d6876d3be..a7a598c45 100644
--- a/os/hal/platforms/STM32/sdc_lld.c
+++ b/os/hal/platforms/STM32/sdc_lld.c
@@ -70,7 +70,9 @@ CH_IRQ_HANDLER(SDIO_IRQHandler) {
}
chSysUnlockFromIsr();
- SDIO->ICR = 0xFFFFFFFF;
+ /* Disables the source but the status flags are not reset because the
+ read/write function need to check them.*/
+ SDIO->MASK = 0;
CH_IRQ_EPILOGUE();
}
@@ -332,7 +334,7 @@ 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 sta, resp[1];
+ uint32_t resp[1];
/* Setting up data transfer.
Options: Card to Controller, Block mode, DMA mode, 512 bytes blocks.*/
@@ -353,26 +355,27 @@ bool_t sdc_lld_read(SDCDriver *sdcp, uint32_t startblk,
DMA_CCR1_PSIZE_1 | DMA_CCR1_MSIZE_1 |
DMA_CCR1_EN);
+ /* Read multiple blocks command.*/
if (sdc_lld_send_cmd_short_crc(sdcp, SDC_CMD_READ_MULTIPLE_BLOCK,
startblk, resp) ||
(resp[0] & SDC_R1_ERROR_MASK))
goto error;
+ /* Note the mask is checked before going to sleep because the interrupt
+ may have occurred before reaching the critical zone.*/
chSysLock();
- sta = SDIO->STA;
- if ((sta & (SDIO_STA_DCRCFAIL | SDIO_STA_DTIMEOUT |
- SDIO_STA_DATAEND | SDIO_STA_STBITERR)) == 0) {
- chDbgAssert(sdcp->thread == NULL, "sdc_lld_read_blocks(), #1", "not NULL");
+ 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_blocks(), #2", "not NULL");
+ chDbgAssert(sdcp->thread == NULL, "sdc_lld_read(), #2", "not NULL");
if (chThdSelf()->p_u.rdymsg != RDY_OK) {
chSysUnlock();
goto error;
}
}
else {
- if ((sta & SDIO_STA_DATAEND) == 0) {
+ if ((SDIO->STA & SDIO_STA_DATAEND) == 0) {
chSysUnlock();
goto error;
}
@@ -410,7 +413,66 @@ error:
*/
bool_t sdc_lld_write(SDCDriver *sdcp, uint32_t startblk,
const uint8_t *buf, uint32_t n) {
+ uint32_t resp[1];
+ /* Write multiple blocks command.*/
+ if (sdc_lld_send_cmd_short_crc(sdcp, SDC_CMD_WRITE_MULTIPLE_BLOCK,
+ startblk, resp) ||
+ (resp[0] & SDC_R1_ERROR_MASK))
+ 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.*/
+ /* 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_DIR | DMA_CCR1_EN);
+
+ /* 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 (chThdSelf()->p_u.rdymsg != RDY_OK) {
+ chSysUnlock();
+ goto error;
+ }
+ }
+ else {
+ if ((SDIO->STA & SDIO_STA_DATAEND) == 0) {
+ chSysUnlock();
+ goto error;
+ }
+ }
+ dmaDisableChannel(STM32_DMA2, STM32_DMA_CHANNEL_4);
+ SDIO->ICR = 0xFFFFFFFF;
+ SDIO->MASK = 0;
+ SDIO->DCTRL = 0;
+ chSysUnlock();
+
+ if (sdc_lld_send_cmd_short_crc(sdcp, SDC_CMD_STOP_TRANSMISSION, 0, resp))
+ goto error;
+ return FALSE;
+error:
+ dmaDisableChannel(STM32_DMA2, STM32_DMA_CHANNEL_4);
+ SDIO->ICR = 0xFFFFFFFF;
+ SDIO->MASK = 0;
+ SDIO->DCTRL = 0;
return TRUE;
}