2016-03-30 5 views
0

У нас есть проект на работе, так как ребята пытаются заставить внешнюю оперативную память работать на MCU STM32F417. Проект пробует некоторые вещи, которые действительно ресурс голодны, и внутренней памяти просто недостаточно.STM32F4 работает FreeRTOS во внешнем ОЗУ

Вопрос в том, как наилучшим образом сделать это.

Текущий подход состоял в том, чтобы просто заменить адрес RAM в скрипте связи (gnu ld) адресом для внешней ОЗУ.

Проблема с этим подходом заключается в том, что во время инициализации чип должен работать во внутренней памяти, поскольку FSMC не был инициализирован.

Кажется, что все работает, но как только pvPortMalloc запускается, мы получаем жесткую ошибку и, вероятно, из-за разыгрывания фиктивных адресов, мы видим, что переменные не инициализируются правильно в системном init (что имеет смысл, я думаю, внутренняя память не используется вообще, когда она, вероятно, должна быть).

Я понимаю, что это неопределенный вопрос, но каков общий подход при запуске кода во внешней RAM на Cortex M4 MCU, а точнее в STM32F4?

Благодаря

+0

Что именно вам нужно разместить во внешней SRAM? Большая структура данных? Все ваши данные для чтения и записи? Вам нужен ваш код для запуска из SRAM или он может находиться во флэш-памяти? –

+0

Наша первоначальная мысль заключалась в том, что было бы проще разместить все во внешнем баране. Существуют криптографические ключи и вычисления, которые действительно слишком велики для MCU. Но по определенным причинам нам все равно нужно это делать. Код может выполняться со вспышки просто отлично, поэтому все, что я имею в виду стека и кучи. – evading

+0

Какую версию исходного файла управления кучей FreeRTOS вы используете (heap_1.c, heap_2.c и т. Д.)?Я считаю, что FreeRTOS выделяет стек задач в куче (используя pvPortMalloc), так что это может быть единственное, что вам нужно переместить в SRAM, но это в значительной степени зависит от используемой версии кучи _ *. C. –

ответ

2

FreeRTOS определяет и использует одну большую область памяти для управления стеком и кучей; это просто массив байтов, размер которого указан символом configTOTAL_HEAP_SIZE в FreeRTOSConfig.h. FreeRTOS выделяет стек задач в этой области памяти с помощью функции pvPortMalloc, поэтому основная цель здесь - разместить область кучи FreeRTOS во внешнюю SRAM.

область динамической памяти FreeRTOS определяется в heap_*.c (за исключением heap_3.c, который использует стандартную библиотеку таНос и не определяет пользовательскую область динамической памяти), то переменная называется ucHeap. Вы можете использовать расширения своего компилятора, чтобы установить его раздел. Для НКИ, это было бы что-то вроде:

static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ] __attribute__ ((section (".sram_data"))); 

Теперь нам нужно настроить скрипт компоновщика, чтобы поместить этот пользовательский раздел в внешнюю SRAM. Существует несколько способов сделать это, и это снова зависит от используемой toolchain. С GCC один из способов сделать это было бы определить область памяти для SRAM и раздел для ".sram_data" добавляемых к области SRAM, что-то вроде:

MEMORY 
{ 
    ... 
    /* Define SRAM region */ 
    sram : ORIGIN = <SRAM_START_ADDR>, LENGTH = <SRAM_SIZE> 
} 

SECTIONS 
{ 
    ... 
    /* Define .sram_data section and place it in sram region */ 
    .sram_data : 
    { 
     *(.sram_data) 
    } >sram 
    ... 
} 

Это поместит ucHeap области во внешней SRAM, в то время как все остальные разделы текста и данных будут помещены в области памяти по умолчанию (внутренняя вспышка и барабан).

Несколько замечаний:

  • убедитесь, что вы инициализировать контроллер SRAM/ФКЦБ до вызова любой функции Freertos (как xTaskCreate)
  • как только вы начинаете задачи, все стека выделяются переменные будут размещены в ucHeap (т.е. оперативная память), но глобальные переменные по-прежнему распределяются во внутренней ОЗУ. Если у вас все еще есть проблемы с внутренним объемом ОЗУ, вы можете настроить другие глобальные переменные, которые должны быть размещены в ".sram_section", используя расширения компилятора (как показано для ucHeap)
  • , если ваш код использует динамическое выделение памяти, убедитесь, что вы используете pvPortMalloc/vPortFree, а не stdlib malloc/free. Это связано с тем, что только pvPortMalloc/vPortFree будет использовать область ucHeap в ext RAM (и они являются потокобезопасными, что является плюсом)
  • , если вы делаете много создания/удаления динамических задач и распределения памяти с помощью pvPortMalloc/vPortFree с разной памятью размеры блоков, используйте heap_4.c вместо heap_2.c. heap_2.c имеет проблемы фрагментации памяти при использовании нескольких различных размеров блоков, тогда как heap_4.c способна объединить соседние блоки свободной памяти в один большой блок

Другой (и, возможно, проще) решением было бы определить переменную ucHeap как указатель вместо массива, например:

static uint8_t * const ucHeap = <SRAM_START_ADDR>; 

Это не требует никакого специального редактирования компоновщик сценария, все могут быть размещены в разделах по умолчанию. Обратите внимание, что с этим решением компоновщик не будет явно резервировать любую память для кучи, и вы потеряете некоторые потенциально полезные сведения/ошибки (например, область кучи не подходит для внешней RAM). Но до тех пор, пока у вас есть только ucHeap во внешней памяти, и у вас есть configTOTAL_HEAP_SIZE меньше, чем внешний размер оперативной памяти, который может работать нормально.

1

При запуске приложения он будет пытаться инициализировать данные, либо очищая его к нулю, или инициализацией его ненулевое значение, в зависимости от сечения переменной помещается. Используя обычный модель времени выполнения, которая будет выполняться до вызова main(). Так что у вас есть что-то вроде:

1) Сбросить вектор вызывает инициализацию код 2) C запуск временной код инициализации инициализирует переменные 3) C код времени выполнения инициализации называют основными()

Если вы используете компоновщик место переменные во внешней ОЗУ, то вам необходимо обеспечить доступность ОЗУ до того, как произойдет эта инициализация, иначе вы получите жесткую ошибку. Поэтому вам нужно либо иметь загрузчик, который настраивает систему для вас, а затем запускает ваше приложение .... или просто просто отредактируйте код запуска, чтобы сделать следующее:

1) Сбросить векторные вызовы init code 2) >>> C код запуска времени инициализации настраивает внешнюю оперативную память < < < 3) C инициализируемые переменные инициализации времени запуска 4) C запускается код инициализации вызовов main().

Таким образом, оперативная память доступна до того, как вы попытаетесь получить к ней доступ.

Однако, если все, что вы хотите сделать, это иметь кучу FreeRTOS во внешней ОЗУ, то вы можете оставить код инициализации нетронутым и просто использовать соответствующую реализацию кучи - в основном такую, которая не просто объявляет большой статический массив. Например, если вы используете heap_5, все, что вам нужно сделать, это обеспечить, чтобы функция инициализации кучи вызывалась до того, как выполняется какое-либо распределение, потому что init кучи просто описывает, какую ОЗУ использовать в качестве кучи, а не статически объявлять кучу.