Как сделать некэшируемую область для DMA через MPU на STM32H7?
Обновлено Редакция GAW
MPU Cortex-M7 задаёт атрибуты памяти по регионам, и среди них — кэшируемость. Если накрыть буферы DMA регионом с атрибутом Normal non-cacheable, ядро будет читать и писать их мимо кэша, и вопрос когерентности с DMA исчезнет — этот путь ST предлагает в AN4839 наравне с обслуживанием кэша.
Атрибуты по таблице B3-13
| TEX | C | B | Тип памяти по Armv7-M | Для чего |
|---|---|---|---|---|
| 000 | 1 | 1 | Normal, write-back без выделения при записи | обычные данные |
| 001 | 1 | 1 | Normal, write-back с выделением при записи | обычные данные |
| 001 | 0 | 0 | Normal, non-cacheable | буферы DMA |
| 000 | 0 | 1 | Device, 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, но полезно для отладки.
Источники
- 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
- 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 с выделением при записи по умолчанию
- STMicroelectronics. AN4839 Level 1 cache on STM32F7 Series and STM32H7 Series, Rev 2 (March 2018) — разд. 4: вместо обслуживания кэша для обмена с DMA можно использовать некэшируемую область памяти, настроенную через MPU
- 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
Нашли ошибку?
Смотрите также
- Блок защиты памяти (MPU)Права доступа к областям памяти в Cortex-M
- Когерентность кэша (cache coherency)Согласование кэша ядра с памятью, в которую пишет DMA
- Почему после приёма по DMA STM32F7 читает старые данные?Кэш данных хранит старую копию; invalidate буфера после приёма, буфер по 32 байта
- Почему DMA1 на STM32H743 не передаёт данные из буфера?Буфер лежит в DTCM, куда DMA1, DMA2 и BDMA доступа не имеют; перенести в AXI SRAM или SRAM1–3
- Барьер памятиГраница, через которую нельзя переставлять обращения к памяти