Перейти к содержанию

Как сделать некэшируемую область для DMA через MPU на STM32H7?

Обновлено Редакция GAW

MPU Cortex-M7 задаёт атрибуты памяти по регионам, и среди них — кэшируемость. Если накрыть буферы DMA регионом с атрибутом Normal non-cacheable, ядро будет читать и писать их мимо кэша, и вопрос когерентности с DMA исчезнет — этот путь ST предлагает в AN4839 наравне с обслуживанием кэша.

Атрибуты по таблице B3-13

TEXCBТип памяти по Armv7-MДля чего
00011Normal, write-back без выделения при записиобычные данные
00111Normal, write-back с выделением при записиобычные данные
00100Normal, non-cacheableбуферы DMA
00001Device, shareableрегистры периферии

По табл. 7 RM0433 вся SRAM1 STM32H743 — 128 КБ с адреса 0x3000 0000, и по умолчанию она кэшируется с обратной записью. Размер региона — 2^(SIZE+1) байт: для 128 КБ = 2¹⁷ поле SIZE = 16 (наш расчёт), а база 0x3000 0000 кратна 128 КБ.

Код на регистрах CMSIS

// Region 1: SRAM1 of STM32H743, 128 KB at 0x30000000, Normal non-cacheable, no execution
void mpu_dma_region(void) {
  __DMB();
  MPU->CTRL = 0;                                    // disable the MPU while changing regions
  MPU->RNR  = 1;
  MPU->RBAR = 0x30000000UL;                         // base aligned to the region size
  MPU->RASR = (1UL << MPU_RASR_XN_Pos)              // no instruction fetch
            | (3UL << MPU_RASR_AP_Pos)              // AP = 011: full access
            | (1UL << MPU_RASR_TEX_Pos)             // TEX = 001, C = 0, B = 0: non-cacheable
            | (16UL << MPU_RASR_SIZE_Pos)           // 2^(16 + 1) = 128 KB
            | MPU_RASR_ENABLE_Msk;
  MPU->CTRL = MPU_CTRL_PRIVDEFENA_Msk | MPU_CTRL_ENABLE_Msk;   // default map in background
  __DSB();
  __ISB();
}

Бит PRIVDEFENA оставляет карту памяти по умолчанию фоном для привилегированного кода, так что остальная память работает как раньше. При перекрытии регионов, по Armv7-M, действует регион с большим номером — поэтому область DMA удобно описывать регионом с номером выше, чем у общих. Барьеры после включения гарантируют, что новые атрибуты действуют для следующих инструкций — подробнее в термине «Барьер памяти».

Регион настраивают до SCB_EnableDCache() и до первого обращения DMA. Почему буфер нельзя оставить в DTCM у STM32H743 и что ещё нужно для SRAM1–SRAM3, разобрано в ответе «Почему DMA1 на STM32H743 не передаёт данные», а вариант с обслуживанием кэша вместо MPU — в ответе «DMA на STM32F7 читает старые данные».

Похожие вопросы

Можно ли сделать некэшируемым буфер на 600 байт?

Регион MPU — степень двойки от 32 байт с базой, выровненной по своему размеру, поэтому под 600 байт придётся взять регион 1 КБ и положить буфер в его начало. Удобнее собрать все буферы DMA в одну секцию компоновщика и накрыть её одним регионом.

Не замедлит ли это программу?

Обращения ядра к некэшируемой области медленнее, чем к кэшированной: каждое чтение идёт в память. Для буферов, которые ядро читает один раз после DMA, разница невелика; если ядро много раз обрабатывает данные, выгоднее кэшируемый буфер с invalidate.

Зачем XN = 1 для области буферов?

Бит XN запрещает выполнять код из региона: в буферах DMA кода нет, и случайный переход туда вызовет ошибку MemManage вместо исполнения мусора. Это не обязательно для работы DMA, но полезно для отладки.

Источники

  1. Arm. Armv7-M Architecture Reference Manual (DDI 0403E.e) — B3.5.9 MPU_RASR: XN — бит 28, AP[2:0] — 26:24, TEX[2:0] — 21:19, S — 18, C — 17, B — 16, SRD — 15:8, SIZE — 5:1, размер региона 2^(SIZE+1) байт, наименьший — 32 байта, ENABLE — бит 0; табл. B3-13: TEX = 001, C = 0, B = 0 — Normal, внешний и внутренний non-cacheable; TEX = 000, C = 1, B = 1 — write-back без выделения при записи; TEX = 001, C = 1, B = 1 — write-back с выделением при чтении и записи; табл. B3-15: AP = 011 — полный доступ; разд. B3.5.3 PMSAv7-compliant MPU operation: размер 2^N при 5 ≤ N ≤ 32, база выровнена по размеру, при перекрытии действует регион с большим номером; разд. B3.5.6 MPU_CTRL: PRIVDEFENA — бит 2, карта памяти по умолчанию как фоновый регион для привилегированного кода, ENABLE — бит 0
  2. STMicroelectronics. RM0433 Reference manual STM32H742, STM32H743/753 and STM32H750 Value line, Rev 9 — табл. 7: SRAM1 — 0x3000 0000 – 0x3001 FFFF, SRAM2 — 0x3002 0000 – 0x3003 FFFF, SRAM3 — 0x3004 0000 – 0x3004 7FFF, AXI SRAM — 0x2400 0000 – 0x2407 FFFF, тип Normal, кэш write-back с выделением при записи по умолчанию
  3. STMicroelectronics. AN4839 Level 1 cache on STM32F7 Series and STM32H7 Series, Rev 2 (March 2018) — разд. 4: вместо обслуживания кэша для обмена с DMA можно использовать некэшируемую область памяти, настроенную через MPU
  4. Arm. CMSIS 5.9.0, CMSIS/Core/Include/core_cm7.h (V5.1.6, 04 June 2021) — MPU_Type: RNR, RBAR, RASR и псевдонимы; маски MPU_RASR_XN_Pos (28), MPU_RASR_AP_Pos (24), MPU_RASR_TEX_Pos (19), MPU_RASR_S_Pos (18), MPU_RASR_C_Pos (17), MPU_RASR_B_Pos (16), MPU_RASR_SIZE_Pos (1), MPU_RASR_ENABLE_Msk; MPU_CTRL_PRIVDEFENA_Msk, MPU_CTRL_ENABLE_Msk

Нашли ошибку?