diff --git a/ports/stm32/sdio.c b/ports/stm32/sdio.c index df4aec25e2..12d8326f9a 100644 --- a/ports/stm32/sdio.c +++ b/ports/stm32/sdio.c @@ -62,12 +62,18 @@ void sdio_init(uint32_t irq_pri) { __HAL_RCC_SDMMC1_CLK_ENABLE(); // enable SDIO peripheral SDMMC_TypeDef *SDIO = SDMMC1; - SDIO->CLKCR = SDMMC_CLKCR_HWFC_EN | SDMMC_CLKCR_PWRSAV | 118; // 1-bit, 400kHz + #if defined(STM32F7) + SDIO->CLKCR = SDMMC_CLKCR_HWFC_EN | SDMMC_CLKCR_PWRSAV | (120 - 2); // 1-bit, 400kHz + #else + SDIO->CLKCR = SDMMC_CLKCR_HWFC_EN | SDMMC_CLKCR_PWRSAV | (120 / 2); // 1-bit, 400kHz + #endif mp_hal_delay_us(10); SDIO->POWER = 3; // the card is clocked mp_hal_delay_us(10); - SDIO->DCTRL = 1 << 10; // RWMOD is SDIO_CK + SDIO->DCTRL = SDMMC_DCTRL_RWMOD; // RWMOD is SDIO_CK + #if defined(STM32F7) SDIO->CLKCR |= SDMMC_CLKCR_CLKEN; + #endif mp_hal_delay_us(10); __HAL_RCC_DMA2_CLK_ENABLE(); // enable DMA2 peripheral @@ -79,20 +85,28 @@ void sdio_init(uint32_t irq_pri) { } void sdio_deinit(void) { - RCC->APB2ENR &= ~RCC_APB2ENR_SDMMC1EN; // disable SDIO peripheral - RCC->AHB1ENR &= ~RCC_AHB1ENR_DMA2EN; // disable DMA2 peripheral + __HAL_RCC_SDMMC1_CLK_DISABLE(); + #if defined(STM32F7) + __HAL_RCC_DMA2_CLK_DISABLE(); + #endif } void sdio_enable_high_speed_4bit(void) { SDMMC_TypeDef *SDIO = SDMMC1; SDIO->POWER = 0; // power off mp_hal_delay_us(10); + #if defined(STM32F7) SDIO->CLKCR = SDMMC_CLKCR_HWFC_EN | SDMMC_CLKCR_WIDBUS_0 | SDMMC_CLKCR_BYPASS /*| SDMMC_CLKCR_PWRSAV*/; // 4-bit, 48MHz + #else + SDIO->CLKCR = SDMMC_CLKCR_HWFC_EN | SDMMC_CLKCR_WIDBUS_0; // 4-bit, 48MHz + #endif mp_hal_delay_us(10); SDIO->POWER = 3; // the card is clocked mp_hal_delay_us(10); - SDIO->DCTRL = 1 << 11 | 1 << 10; // SDIOEN, RWMOD is SDIO_CK + SDIO->DCTRL = SDMMC_DCTRL_SDIOEN | SDMMC_DCTRL_RWMOD; // SDIOEN, RWMOD is SDIO_CK + #if defined(STM32F7) SDIO->CLKCR |= SDMMC_CLKCR_CLKEN; + #endif SDIO->MASK = DEFAULT_MASK; mp_hal_delay_us(10); } @@ -108,6 +122,14 @@ void SDMMC1_IRQHandler(void) { sdmmc_irq_state = SDMMC_IRQ_STATE_DONE; return; } + #if defined(STM32H7) + if (!sdmmc_dma) { + while (sdmmc_buf_cur < sdmmc_buf_top && (SDMMC1->STA & SDMMC_STA_DPSMACT) && !(SDMMC1->STA & SDMMC_STA_RXFIFOE)) { + *(uint32_t*)sdmmc_buf_cur = SDMMC1->FIFO; + sdmmc_buf_cur += 4; + } + } + #endif if (sdmmc_buf_cur >= sdmmc_buf_top) { // data transfer finished, so we are done SDMMC1->MASK &= SDMMC_MASK_SDIOITIE; @@ -115,7 +137,16 @@ void SDMMC1_IRQHandler(void) { return; } if (sdmmc_write) { - SDMMC1->DCTRL = (sdmmc_block_size_log2 << 4) | 1 | (1 << 11) | (!sdmmc_write << 1) | (sdmmc_dma << 3) | (0 << 10); + SDMMC1->DCTRL = + SDMMC_DCTRL_SDIOEN + | SDMMC_DCTRL_RWMOD + | sdmmc_block_size_log2 << SDMMC_DCTRL_DBLOCKSIZE_Pos + #if defined(STM32F7) + | (sdmmc_dma << SDMMC_DCTRL_DMAEN_Pos) + #endif + | (!sdmmc_write) << SDMMC_DCTRL_DTDIR_Pos + | SDMMC_DCTRL_DTEN + ; if (!sdmmc_dma) { SDMMC1->MASK |= SDMMC_MASK_TXFIFOHEIE; } @@ -125,6 +156,7 @@ void SDMMC1_IRQHandler(void) { // data transfer complete // note: it's possible to get DATAEND before CMDREND SDMMC1->ICR = SDMMC_ICR_DATAENDC; + #if defined(STM32F7) // check if there is some remaining data in RXFIFO if (!sdmmc_dma) { while (SDMMC1->STA & SDMMC_STA_RXDAVL) { @@ -132,6 +164,7 @@ void SDMMC1_IRQHandler(void) { sdmmc_buf_cur += 4; } } + #endif if (sdmmc_irq_state == SDMMC_IRQ_STATE_CMD_DONE) { // command and data finished, so we are done SDMMC1->MASK &= SDMMC_MASK_SDIOITIE; @@ -177,9 +210,11 @@ void SDMMC1_IRQHandler(void) { } int sdio_transfer(uint32_t cmd, uint32_t arg, uint32_t *resp) { + #if defined(STM32F7) // Wait for any outstanding TX to complete while (SDMMC1->STA & SDMMC_STA_TXACT) { } + #endif DMA2_Stream3->CR = 0; // ensure DMA is reset SDMMC1->ICR = SDMMC_STATIC_FLAGS; // clear interrupts @@ -226,9 +261,11 @@ int sdio_transfer(uint32_t cmd, uint32_t arg, uint32_t *resp) { } int sdio_transfer_cmd53(bool write, uint32_t block_size, uint32_t arg, size_t len, uint8_t *buf) { + #if defined(STM32F7) // Wait for any outstanding TX to complete while (SDMMC1->STA & SDMMC_STA_TXACT) { } + #endif // for SDIO_BYTE_MODE the SDIO chuck of data must be a single block of the length of buf int block_size_log2 = 0; @@ -264,8 +301,10 @@ int sdio_transfer_cmd53(bool write, uint32_t block_size, uint32_t arg, size_t le if (dma) { // prepare DMA so it's ready when the DPSM starts its transfer + #if defined(STM32F7) // enable DMA2 peripheral in case it was turned off by someone else RCC->AHB1ENR |= RCC_AHB1ENR_DMA2EN; + #endif if (write) { // make sure cache is flushed to RAM so the DMA can read the correct data @@ -276,6 +315,7 @@ int sdio_transfer_cmd53(bool write, uint32_t block_size, uint32_t arg, size_t le MP_HAL_CLEANINVALIDATE_DCACHE(buf, len); } + #if defined(STM32F7) DMA2->LIFCR = 0x3f << 22; DMA2_Stream3->FCR = 0x07; // ? DMA2_Stream3->PAR = (uint32_t)&SDMMC1->FIFO; @@ -297,6 +337,14 @@ int sdio_transfer_cmd53(bool write, uint32_t block_size, uint32_t arg, size_t le | 1 << 5 // PFCTRL periph is flow controller | 1 << 0 // EN ; + #else + SDMMC1->IDMABASE0 = (uint32_t)buf; + SDMMC1->IDMACTRL = SDMMC_IDMA_IDMAEN; + #endif + } else { + #if defined(STM32H7) + SDMMC1->IDMACTRL = 0; + #endif } // for reading, need to initialise the DPSM before starting the CPSM @@ -304,7 +352,16 @@ int sdio_transfer_cmd53(bool write, uint32_t block_size, uint32_t arg, size_t le // (and in case we get a long-running unrelated IRQ here on the host just // after writing to CMD to initiate the command) if (!write) { - SDMMC1->DCTRL = (block_size_log2 << 4) | 1 | (1 << 11) | (!write << 1) | (dma << 3); + SDMMC1->DCTRL = + SDMMC_DCTRL_SDIOEN + | SDMMC_DCTRL_RWMOD + | block_size_log2 << SDMMC_DCTRL_DBLOCKSIZE_Pos + #if defined(STM32F7) + | (dma << SDMMC_DCTRL_DMAEN_Pos) + #endif + | (!write) << SDMMC_DCTRL_DTDIR_Pos + | SDMMC_DCTRL_DTEN + ; } SDMMC1->ARG = arg; @@ -328,7 +385,11 @@ int sdio_transfer_cmd53(bool write, uint32_t block_size, uint32_t arg, size_t le } if (mp_hal_ticks_ms() - start > 200) { SDMMC1->MASK &= SDMMC_MASK_SDIOITIE; + #if defined(STM32F7) printf("sdio_transfer_cmd53: timeout wr=%d len=%u dma=%u buf_idx=%u STA=%08x SDMMC=%08x:%08x DMA=%08x:%08x:%08x RCC=%08x\n", write, (uint)len, (uint)dma, sdmmc_buf_cur - buf, (uint)SDMMC1->STA, (uint)SDMMC1->DCOUNT, (uint)SDMMC1->FIFOCNT, (uint)DMA2->LISR, (uint)DMA2->HISR, (uint)DMA2_Stream3->NDTR, (uint)RCC->AHB1ENR); + #else + printf("sdio_transfer_cmd53: timeout wr=%d len=%u dma=%u buf_idx=%u STA=%08x SDMMC=%08x:%08x IDMA=%08x\n", write, (uint)len, (uint)dma, sdmmc_buf_cur - buf, (uint)SDMMC1->STA, (uint)SDMMC1->DCOUNT, (uint)SDMMC1->DCTRL, (uint)SDMMC1->IDMACTRL); + #endif return -MP_ETIMEDOUT; } } @@ -336,7 +397,11 @@ int sdio_transfer_cmd53(bool write, uint32_t block_size, uint32_t arg, size_t le SDMMC1->MASK &= SDMMC_MASK_SDIOITIE; if (sdmmc_error) { + #if defined(STM32F7) printf("sdio_transfer_cmd53: error=%08lx wr=%d len=%u dma=%u buf_idx=%u STA=%08x SDMMC=%08x:%08x DMA=%08x:%08x:%08x RCC=%08x\n", sdmmc_error, write, (uint)len, (uint)dma, sdmmc_buf_cur - buf, (uint)SDMMC1->STA, (uint)SDMMC1->DCOUNT, (uint)SDMMC1->FIFOCNT, (uint)DMA2->LISR, (uint)DMA2->HISR, (uint)DMA2_Stream3->NDTR, (uint)RCC->AHB1ENR); + #else + printf("sdio_transfer_cmd53: error=%08lx wr=%d len=%u dma=%u buf_idx=%u STA=%08x SDMMC=%08x:%08x IDMA=%08x\n", sdmmc_error, write, (uint)len, (uint)dma, sdmmc_buf_cur - buf, (uint)SDMMC1->STA, (uint)SDMMC1->DCOUNT, (uint)SDMMC1->DCTRL, (uint)SDMMC1->IDMACTRL); + #endif return -(0x1000000 | sdmmc_error); }