STM32F746GDISCOVERY.
Cortex®M7, организация памяти.
Документация на русском языке
На сегодняшний день эта публикация, скорее не набор решений, а некий тестовый стенд, на котором эти решения можно попробовать
STM32F746GDISCOVERY – уже не новая, но очень серьезная железка, которая умеет все, ну или почти все.
Сказка начинается уже в CubeMX.
System Core
CORTEX_M7
Cortex interface Setting
Flash Interface
ART ACCLERATOR
Instruction Prefetch
CPU ICache
CPU DCache
Cortex Memory Protection Unit…
Все и везде пишут по-разному от моего древнего перевода LCD-TFT display controller (LTDC) on STM32 MCUs (Rus) стр. 47 «Пример конфигурации MPU…» до видео уроков narodstream.ru/programmirovanie-mk-stm32/. Если что-то поменять, то либо перестает работать, либо ничего особо не меняется. Что, почему? – Никто не пишет!
Читаем:
RM0385 Reference manual
STM32F75xxx and STM32F74xxx advanced Arm®-based 32-bit MCUs.
2 System and memory overview
3 Embedded Flash memory (FLASH)
Ищем:
И, собственно, все… Ясности это все мне, особенно, не добавило.
Есть интересная статья:
AN4667 Application note
STM32F7 Series system architecture and performance
«Это примечание по применению предоставляется со встроенным программным пакетом X-CUBE-32F7PERF…» То есть содержит не только примеры кода и файлы компоновщика, но и «…советы о том, как разделить код и данные в памяти STM32F7, чтобы получить наилучшую компромиссную производительность в зависимости от кода и размеров данных.»
Что делать! )))
Все недоумение в начале статьи вызвали примеры, где вся память объединена:
1 2 |
define symbol __ICFEDIT_region_RAM_start__ = 0x20000000; define symbol __ICFEDIT_region_RAM_end__ = 0x2004FFFF; |
Действительно, в рамках используемых ресурсов, визуально не заметно как дисплей выводит строчку чуть быстрее или чуть медленнее.
Однако мы знаем, что плата умеет считать и выводить на экран быстрое преобразование Фурье и цифровые фильтры. Примеры этих решений есть в библиотеке X-CUBE-DSPDEMO.
В идеале нужно разделить команды и данные. Дальше можно использовать кэширование, разные интерфейсы и DMA.
Есть мнение, что можно все это изящно попробовать и на простом примере.
Воспользуемся навыками написания файлов компоновщика из предыдущей статьи: «IAR C/C++ Development Guide» и напишем файл, разбив память правильно.
Мне не удалось здесь сохранить расширение *.icf. Поэтому придется переименовать из *.txt.
В публикации «CCM (core coupled memory) data RAM» я рассказал, как можно использовать память ядра, декларируемую, но де факто не используемую в примерах для STM32F407.
Посмотрим еще раз документ AN4296 (Use STM32F3/STM32G4 CCM SRAM with IAR™ EWARM, Keil® MDK-ARM and GNU-based toolchains).
В нем подробно описано, как перенести таблицу прерываний в память ядра и сделаем тоже самое для Cortex®M7.
Где особенно изящно будет выглядеть:

Поскольку память ядра команд именно так и должна использоваться.
И уже никого не будем обманывать со схемой управления памятью heap_5.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
// IAR C/C++ Development Guide // Compiling and Linking for Arm // Linking your application pg. 116 static uint8_t* p_heap1; static uint8_t* p_heap2; #pragma section = "HEAP1" __no_init uint8_t heap_DTCM[16*1024]; #pragma section = "HEAP2" __no_init uint8_t heap_SRAM1[16*1024]; // Используйте эту директиву pragma для определения имени раздела, которое может использоваться операторами раздела __section_begin, __section_end и __section_size. // Все объявления разделов для определенного раздела должны иметь одинаковое выравнивание. // Примечание. Чтобы разместить переменные или функции в определенном разделе, используйте директиву #pragma location или оператор @. // Use this pragma directive to define a section name that can be used by the __section_begin, __section_end, and __section_size section operators. // All section declarations for a specific section must have the same alignment. // Note. To place variables or functions in a specific section, use the #pragma location directive or the @ operator. /* USER CODE BEGIN 1 */ p_heap1 = __section_begin("HEAP1"); // 0x2000'8000 "" p_heap2 = __section_begin("HEAP2"); // 0x2004'4000 "" HeapRegion_t xHeapRegions[] = { { p_heap1, sizeof(heap_DTCM) }, { p_heap2, sizeof(heap_SRAM1) }, { NULL, 0 } }; vPortDefineHeapRegions( xHeapRegions ); // Используется для определения нескольких областей кучи для использования heap_5.c. // Эта функция должна вызываться перед любыми вызовами pvPortMalloc () - отсутствие создания задачи, // очереди, семафора, мьютекса, программного таймера, группы событий и т. д. Приведет к вызову pvPortMalloc. // // pxHeapRegions передает массив структур HeapRegion_t, каждая из которых определяет область памяти, // которую можно использовать в качестве кучи. Массив завершается структурой HeapRegions_t, размер которой равен 0. // Область с наименьшим начальным адресом должна появляться первой в массиве. // Used to define multiple heap areas to use heap_5.c. // This function must be called before any calls to pvPortMalloc () - no task creation, // queue, semaphore, mutex, program timer, event group, etc. Will call pvPortMalloc. // // pxHeapRegions passes an array of HeapRegion_t structures, each of which defines a memory area, // which can be used as a heap. The array ends with a HeapRegions_t structure of size 0. // The area with the lowest start address should appear first in the array. /* USER CODE END 1 */ |
Есть смысл отметить, что кучу таким образом можно организовать и в SDRAM
К сожалению, на сегодняшний день у меня нет интересного проекта, реализующего эти моменты. Однако все, описанное выше, проверено и работает в тестовом примере.
С уважением Петр.
Реализуем коммерческие проекты.
Возможна работа по договору подряда.
t654rk@mail.ru
Ваши комментарии к статье: