Browse Source

stm32/sdio: Add support for H7 MCUs.

The cyw43 driver on stm32 will now work with H7 MCUs.
pull/5598/head
Damien George 5 years ago
parent
commit
257b17ec10
  1. 79
      ports/stm32/sdio.c

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

Loading…
Cancel
Save