|
|
@ -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); |
|
|
|
} |
|
|
|
|
|
|
|