🛠 TCM, DMA et cache sur le STM32H743ZI : placer ses données pour un temps réel déterministe

STM32H7 Nucleo-144 (modèle phare : NUCLEO-H743ZI) · avance · Schéma : IMG-stm32h7-nucleo-avance-3-stm32h743zi-tcm-dma-cache.svg — carte mémoire du STM32H743ZI : 192 Ko de TCM RAM en accès cycle unique à côté du Cortex-M7, 864 Ko de SRAM utilisateur reliés par l'interconnect AXI/MBX, contrôleur DMA à 16 canaux traversant les zones cacheables, flat vector style, étiquettes en français, fond blanc.

Qué vas a construir

El H743ZI es un MCU para ingenieros de memoria: 192 KB de RAM TCM (acoplada estrechamente, acceso determinista de un solo ciclo) más hasta 864 KB de SRAM de usuario y 4 KB de SRAM de respaldo, conectados mediante una interconexión AXI/MBX, con un motor DMA de 16 canales y un Cortex-M7 que realiza caché de forma agresiva. Este tutorial coloca el código y los datos a propósito, no por accidente: la diferencia entre un bucle de control determinista y un heisenbug.

Las reglas de la casa

> NO VERIFICADO: números de ítems individuales de ES0392 — la capa de texto del PDF no pudo extraerse con los fetchers de investigación.

  1. TCM para lo que nunca debe fallar: las ISRs, los bucles críticos de tiempo y las pilas de tareas colocadas en TCM obtienen tiempos deterministas: la hoja de especificaciones de la placa destaca la RAM TCM para la ejecución en tiempo real determinista como una característica principal.
  2. Los búferes DMA deben ser seguros para la caché: con la caché de datos del M7 activada, un búfer en SRAM cacheable puede ser leído obsoleto por la CPU o sobrescrito por el DMA antes de la expulsión. Coloca los búferes en regiones MPU no cacheables o gestiona el mantenimiento explícitamente.
  3. Las erratas son reales: la hoja de erratas de ST ES0392 (H742/H743/H750/H753) debe leerse antes de usar casos extremos de DMA/caché intensiva o Ethernet.
  4. Haz benchmarks solo después de verificar los relojes: Zephyr arranca a 96 MHz, el núcleo STM32duino a 480 MHz (VOS0, AHB a HCLK/2 = 240 MHz). Mismo silicio, 5× la puntuación: primero el reloj, luego los números.

Paso 1 — Coloca las cosas explícitamente

/* GCC linker-section attributes (linker script must define the regions). */
__attribute__((section(".dtcmram")))
volatile uint32_t ctrl_state;          /* hot state in TCM: single-cycle */

__attribute__((section(".dma_buffers")))   /* MPU-marked Non-cacheable */
uint8_t spi_dma_buf[4096];

void __attribute__((section(".itcmram"), optimize("Ofast")))
fast_control_loop(void) {              /* time-critical loop out of flash */
  for (uint32_t i = 0; i < 64; i++) acc += k[i];
}

Paso 2 — Demuestra la determinación

  1. Ejecuta el bucle de control desde flash con la caché activada, alterna un GPIO por iteración y mide el jitter en un osciloscopio.
  2. Mueve el bucle a ITCM y los datos a DTCM; vuelve a medir: la banda de jitter se colapsa porque ni la búsqueda ni la carga cruzan la ruta AXI cacheada.
  3. Añade un flujo DMA que sature la interconexión AXI/MBX: la versión cacheada en flash se degrada, la versión TCM no.

Paso 3 — Mantenimiento de la caché cuando no puedes mover el búfer

/* Clean before DMA transmit, invalidate before CPU read after receive. */
SCB_CleanDCache_by_Addr(spi_dma_buf, sizeof spi_dma_buf);
HAL_SPI_Transmit_DMA(&hspi1, spi_dma_buf, len);
/* ... on transfer-complete callback: */
SCB_InvalidateDCache_by_Addr(spi_dma_buf, sizeof spi_dma_buf);

Mantén los búferes alineados a 32 bytes y rellenados al tamaño de la línea de caché para que las variables vecinas nunca compartan una línea con un búfer DMA.

Resultado esperado

Una ruta de control cuyo tiempo de peor caso no se mueve cuando el resto del sistema se vuelve más ocupado, además de un mapa escrito de qué regiones declara tu script de enlace como cacheables o no.

Errores comunes

Otros tutoriales para esta placa

Ejemplos de código para esta placa

← Volver a la ficha 🛠 Todos los tutoriales