Uso de SDIO en STM32F407 para Lectura y Escritura de Tarjetas SD con STM32CubeMX

El siguiente tutorial describe cómo configurar el periférico SDIO del STM32F407 para comunicarse con tarjetas SD en modo de 4 bits, utilizando los modos de sondeo, interrupción y DMA. Se basa en la placa de desarrollo ATK-STM32F407 Explorer V2.4 y el software STM32CubeMX (v6.10.0) con el IDE Keil MDK-ARM.

  1. Requisitos Previos

  • Placa de desarrollo STM32F407 (por ejemplo, ATK-STM32F407 Explorer V2.4)
  • STM32CubeMX versión 6.10.0
  • Keil µVision5 (MDK-ARM)
  • Depurador ST-LINK/V2 o similar
  • Adaptador lógico (opcional)
  • Monitor serie (por ejemplo, XCOM V2.6)
  1. Objetivo

Configurar el STM32CubeMX para que el STM32F407 controle una tarjeta SD mediante SDIO en modo de bus de 4 bits. Se implementarán tres métodos de lectura/escritura: por sondeo (polling), por interrupción y por DMA.

  1. Conceptos Preliminares sobre SDIO

La interfaz SDIO (Secure Digital Input/Output) del STM32F407 cumple con la especificación SD versión 2.0 y soporta tarjetas SD de alta velocidad con una frecuencia máxima de reloj de 25 MHz. El módulo consta de un adaptador SDIO y una interfaz APB2. El reloj SDIOCLK de 48 MHz se divide internamente para obtener la frecuencia SDIO_CLK según la fórmula: SDIO_CLK = SDIOCLK / (2 + factor de división) cuando el bypass del divisor está deshabilitado.

Es importante destacar que durante la inicialización de la tarjeta SD, la frecuencia del reloj no debe superar los 400 kHz y se debe utilizar un bus de 1 bit. Una vez inicializada, se puede cambiar al modo de 4 bits con una frecuencia mayor (por ejemplo, 8 MHz).

En la placa de desarrollo, el zócalo de la tarjeta SD está cableado en modo de 4 bits, requiriendo resistencias de pull-up en las líneas de datos (SDIO_D0-D3) y la línea de comando (SDIO_CMD).

  1. Configuración en STM32CubeMX

4.1. Configuración del Proyecto

  • Seleccionar el MCU (STM32F407ZGT6) y presionar "Start Project".
  • En System Core > RCC, habilitar HSE y LSE.
  • En System Core > SYS, configurar el modo de depuración (por ejemplo, Serial Wire).
  • Configurar el reloj: HCLK = 168 MHz, APB1 = 42 MHz, APB2 = 84 MHz. Asegurar que SDIOCLK esté a 48 MHz (ajustando el divisor PLL Q a 7).

4.2. Configuración de SDIO

Ir a Connectivity > SDIO y seleccionar el modo "SD 4 bits Wide bus". Configurar los parámetros:

  • Clock transition on which bit capture is made: Rising edge (por defecto).
  • SDIO Clock divider bypass: Disable.
  • SDIO hardware flow control: Disable.
  • SDIOCLK clock divide factor: 4 (esto da SDIO_CLK = 48 MHz / (2+4) = 8 MHz).

Verificar que los pines asignados coincidan con el hardwrae de la placa (por ejemplo, PC8 para SDIO_D0, PC9 para SDIO_D1, etc.).

4.3. Configuración de Pines de Usuario y UART

  • Configurar los pines de botones (WK_UP, KEY2, KEY1, KEY0) como entradas con pull-down o pull-up según la placa.
  • Configurar USART1 para comunicación serie: modo Asíncrono, 115200 baudios, 8N1. Asignar pines PA9 (TX) y PA10 (RX).

4.4. Configuración de Interrupciones (para modo IT)

Para el modo de interrupción, habilitar la interrupción global de SDIO en System Core > NVIC. Asignar una prioridad adecuada.

4.5. Configuración de DMA (para modo DMA)

En la pestaña DMA Settings de SDIO, agregar dos solicitudes DMA: una para TX y otra para RX. Configurar:

  • Mode: Normal.
  • Address Increment: Memory (incrementar).
  • Los demás parámetros (Data Width, Burst Size) no son conifgurables. Luego, en NVIC, habilitar la interrupción global de SDIO y las interrupciones de los streams DMA correspondientes (por ejemplo, DMA2 Stream3 para Rx y DMA2 Stream6 para Tx).
  1. Generación y Modificación del Código

5.1. Ajuste en MX_SDIO_SD_Init()

En el archivo sdio.c, dentro de la función MX_SDIO_SD_Init(), es necesario modificar manualmente el campo DataBusWidth de SDIO_BUS_WIDE_4B a SDIO_BUS_WIDE_1B (debido a que la herramienta CubeMX a veces inicia en 4 bits incorrectamente). Esto asegura que la inicialización se realice en modo de 1 bit como requiere la especificación SD.

5.2. Funciones de Prueba (Modo Polling)

Añadir las siguientes funciones en sdio.c y declararlas en sdio.h:

/* Muestra información de la tarjeta SD */
void SD_ShowCardInfo(void)
{
    HAL_SD_CardInfoTypeDef info;
    if (HAL_SD_GetCardInfo(&hsd, &info) != HAL_OK) { return; }
    // Imprimir campos como CardType, BlockNbr, LogBlockNbr, etc.
}

/* Muestra el estado actual de la tarjeta */
void SD_ShowCardStatus(void)
{
    HAL_SD_CardStatusTypeDef status;
    if (HAL_SD_GetCardStatus(&hsd, &status) != HAL_OK) { return; }
    // Imprimir DataBusWidth, SpeedClass, etc.
}

/* Borra bloques de inicio a fin */
void SD_EraseTest(void)
{
    if (HAL_SD_Erase(&hsd, 0, 10) != HAL_OK) { /* error */ }
    // Esperar a que la tarjeta vuelva al estado de transferencia
}

/* Escritura en bloque (modo polling) */
void SD_WritePollingTest(void)
{
    uint8_t buffer[512] = "Hola, mundo!";
    if (HAL_SD_WriteBlocks(&hsd, buffer, 5, 1, 1000) == HAL_OK)
    {
        // éxito
    }
}

/* Lectura de bloque (modo polling) */
void SD_ReadPollingTest(void)
{
    uint8_t buffer[512];
    if (HAL_SD_ReadBlocks(&hsd, buffer, 5, 1, 1000) == HAL_OK)
    {
        // imprimir contenido
    }
}

5.3. Modo Interrupción (IT)

En sdio.c, agregar las funciones de escritura/lectura con interrupción y los callbacks:

void SD_WriteIT_Test(void)
{
    HAL_SD_WriteBlocks_IT(&hsd, txBuffer, 5, 1);
}

void SD_ReadIT_Test(void)
{
    HAL_SD_ReadBlocks_IT(&hsd, rxBuffer, 5, 1);
}

void HAL_SD_TxCpltCallback(SD_HandleTypeDef *hsd)
{
    // Imprimir éxito de escritura IT
}

void HAL_SD_RxCpltCallback(SD_HandleTypeDef *hsd)
{
    // Imprimir datos leídos por IT
}

5.4. Modo DMA

Similar al modo IT, pero usando HAL_SD_WriteBlocks_DMA() y HAL_SD_ReadBlocks_DMA(). Reutilizar los mismos callbacks HAL_SD_TxCpltCallback y HAL_SD_RxCpltCallback para notificar la finalización.

5.5. Lógica de Botones en main.c

En el bucle principle, leer los botones y llamar a las funciones correspondientes:

if (HAL_GPIO_ReadPin(WK_UP_GPIO_Port, WK_UP_Pin) == GPIO_PIN_SET)
{
    HAL_Delay(50);
    // filtrar rebote
    SD_ShowCardInfo();
}
else if (HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin) == GPIO_PIN_RESET)
{
    SD_EraseTest();
}
else if (HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin) == GPIO_PIN_RESET)
{
    SD_WritePollingTest();  // o SD_WriteIT_Test() o SD_WriteDMATest()
}
else if (HAL_GPIO_ReadPin(KEY0_GPIO_Port, KEY0_Pin) == GPIO_PIN_RESET)
{
    SD_ReadPollingTest();   // o SD_ReadIT_Test() o SD_ReadDMATest()
}

  1. Verificación

Compilar el proyecto y descargar en la placa. Abrir el monitor serie a 115200 baudios. Al presionar cada botón se mostrarán los resultados por serie: información de la tarjeta, confirmación de borrado, escritura y lectura de bloques.

  1. Funciones Principales del HAL para SDIO

  • HAL_SD_ReadBlocks - Lectura por sondeo
  • HAL_SD_WriteBlocks - Escritura por sondeo
  • HAL_SD_Erase - Borrado de bloques
  • HAL_SD_GetCardInfo - Obtener información de la tarjeta
  • HAL_SD_GetCardStatus - Obtener estado actual
  • HAL_SD_ReadBlocks_IT - Lectura por interrupción
  • HAL_SD_WriteBlocks_IT - Escritura por interrupción
  • HAL_SD_ReadBlocks_DMA - Lectura por DMA
  • HAL_SD_WriteBlocks_DMA - Escritura por DMA
  • HAL_SD_TxCpltCallback - Callback de transmisión completa
  • HAL_SD_RxCpltCallback - Callback de recepción completa
  1. Notas

  • Las imágenes de referencia provienen de la documentación oficial de ST y Wikipedia.
  • Se recomienda utilizar una frecuencia de reloj SDIO de 8 MHz para evitar errores de comunicación.
  • Si se usa SDIO con tarjetas SDHC, el tamaño de bloque es de 512 bytes.

Etiquetas: STM32F407 SDIO SDCard HAL CubeMX

Publicado el 6-29 00:51