Дополнение статьи «Размещение кучи FreeRTOS в разделе CCMRAM для STM32», и в продолжение серии статей про различные полезности для STM32 (1, 2 и 3), хочу обратить внимание на одну особенность работы с CCM RAM памятью, которая может быть причиной совершенно не очевидных ошибок в работе устройств, одна из которых выпила у автора достаточно много крови, так что с чистой совестью её действительно можно назвать «кровавой».

А сама история такова. В логике алгоритма некого устройства засела трудноуловимая плавающая ошибка. И чтобы временно купировать её влияние, было принято решение периодически устройство перезагружать. Сам знаю, что это не очень хорошее решение, но как временный костыль пойдет.

Вот только костыль не пом��г. Помогало только физическое выключения питания, а программная перезагрузка микроконтроллера не помогала! Более того, даже перезагрузка с помощью кнопки RESET иногда не срабатывала! Устройство перезагружалось, но неправильное поведение устройства никуда не исчезало и в итоге все равно приходилось отключать питание физически.


Так как даже аппаратный сброс не всегда помогает, я сперва грешил на проблемы с железом. Ведь если проблема остается и после перезагрузки по кнопке RESET и по NVIC_SystemReset(), то самое логичное, это искать ошибку в аппаратной части. Если бы не одно, но очень веское НО, подобное поведение было у всех устройств, а не на единичном экземпляре оборудования.

Детальный анализ проблемы показал, что такое поведение (некорректная работа устройства после программной перезагрузки), было характерно только для одного класса микроконтроллеров, а именно для STM32F4xx, и тот же самый алгоритм вполне корректно работал на микроконтроллерах младших серий (STM32F1xx и STM32F2xx).

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

По всему выходило, что логика программы почему-то ошибочно считала, что текущие настройки линий связи соответствуют заданным (сравнивались параметры, сохраненные в памяти), хотя после программной перезагрузки это было уже не так! Причину неработоспособности оборудования была выявлена и оставалось понять, почему сбоит логика работы прошивки.

Вы наверно уже догадались, что причина была в том, что куча для STM32F4xx была перенесена в регион CCMRAM, а параметры работы оборудования хранились именно там.
uint8_t ucHeap[ configTOTAL_HEAP_SIZE ] __attribute__((section(".ccmram"))) = {0};

И несмотря на инициализацию, данная область памяти не очищалась при старте прошивки микроконтроллера и продолжала хранить свое предыдущее состояние даже после перезагрузки. Причем, память не очищалась и после нажатия на кнопку RESET.

Дальше все было просто. Достаточно при перезагрузке или при старте приложения обнулять данную секцию памяти (наверно было бы правильнее поправить ассемблерный загрузчик, но я сделал это с помощью обычного memset), и все стало корректно работать.

Имейте ввиду, что раздел CCMRAM не очищается загрузчиком прошивки и после сброса микроконтроллера содержит остаточную информацию от предыдущего запуска, что может являться причиной не очевидных ошибок в работе устройств!