Устройство ядра Cortex-M4F: тактирование, память и запуск программы … ↩
mod. Четверг, 15 октября 2026 22:55 . См. 3
BeeFC · Урок S3 из 33 · Уровень «Старт»
Что происходит в микроконтроллере от подачи питания до функции main, как получить частоту ядра 168 МГц от кварцевого резонатора 8 МГц, как устроена память STM32F405 и как найти причину аварийной остановки программы.
В этом уроке BeeFC получает собственный сценарий компоновщика, настройку тактирования и обработчик аварий. Расчёт коэффициентов умножителя частоты проверяется модульным тестом на компьютере.
Содержание
1. Цели урока
Продолжительность урока — три часа: один час теории и два часа практики. После урока слушатель:
- описывает последовательность запуска программы от сброса до функции
main; - рассчитывает коэффициенты умножителя частоты для заданного кварцевого резонатора;
- объясняет назначение каждой области памяти STM32F405 и описывает её в сценарии компоновщика;
- находит адрес инструкции, вызвавшей аварийную остановку, по сохранённым регистрам.
2. Термины и сокращения
| Термин | Определение |
|---|---|
| внешний высокочастотный генератор (HSE) | генератор с кварцевым резонатором на плате, на полётных контроллерах обычно 8 МГц |
| внутренний генератор (HSI) | генератор внутри микроконтроллера частотой 16 МГц, работает сразу после сброса |
| умножитель частоты (PLL) | узел, который получает высокую частоту из частоты генератора |
| генератор, управляемый напряжением (ГУН) | часть умножителя частоты, которая формирует частоту, заданную коэффициентом N; допустимый диапазон 100–432 МГц |
| сопроцессор плавающей точки (FPU) | блок ядра, выполняющий операции с числами типа float |
| память, связанная с ядром (CCM) | область ОЗУ объёмом 64 КБ, доступная только ядру |
| оперативное запоминающее устройство (ОЗУ) | память для переменных и стека |
| таблица векторов | массив адресов обработчиков в начале флеш-памяти |
| сценарий компоновщика | файл, который сообщает компоновщику, где расположена каждая область памяти |
| блок трассировки (DWT) | отладочный блок ядра со счётчиком тактов CYCCNT |
3. Запуск программы
После сброса ядро Cortex-M4 читает два слова из начала флеш-памяти. Первое слово — начальное значение указателя стека, второе — адрес обработчика сброса Reset_Handler. Дальше выполняется код запуска из файла startup_stm32f405xx.s.
- Установить указатель стека на конец ОЗУ.
- Вызвать функцию
SystemInit. - Скопировать начальные значения инициализированных переменных из флеш-памяти в ОЗУ.
- Обнулить неинициализированные переменные.
- Вызвать конструкторы стандартной библиотеки функцией
__libc_init_array. - Вызвать функцию
main.
SystemInit вызывается до копирования начальных значений и до обнуления переменных. Если в ней записать значение в глобальную переменную, оно будет затёрто на третьем или четвёртом шаге. Поэтому в SystemInit BeeFC выполняется только одно действие — включение сопроцессора плавающей точки.Файл hal/stm32f4/system_beefc.c
4. Тактирование
Дерево тактовых сигналов
Частота ядра STM32F405 после сброса — 16 МГц от внутреннего генератора. Максимальная частота — 168 МГц. Для её получения сигнал кварцевого резонатора проходит через умножитель частоты, а затем распределяется по шинам.
| Шина | Делитель | Частота | Таймеры шины | Примеры периферии |
|---|---|---|---|---|
| AHB | 1 | 168 МГц | — | порты ввода-вывода, контроллер прямого доступа к памяти |
| APB1 | 4 | 42 МГц | 84 МГц | TIM2–TIM5, USART2, USART3, SPI2, SPI3 |
| APB2 | 2 | 84 МГц | 168 МГц | TIM1, TIM8–TIM11, USART1, SPI1, АЦП |
Если делитель шины больше единицы, таймеры этой шины тактируются удвоенной частотой шины. Это правило понадобится в уроке S8 при расчёте частоты ШИМ.

Расчёт умножителя частоты
Умножитель частоты описывается четырьмя коэффициентами: M, N, P и Q.
\( f_{VCO} = \frac{f_{HSE}}{M} \cdot N, \quad f_{SYS} = \frac{f_{VCO}}{P}, \quad f_{USB} = \frac{f_{VCO}}{Q} \)
Справочное руководство накладывает ограничения: частота на входе генератора \( f_{HSE}/M \) лежит в диапазоне 1–2 МГц, частота генератора \( f_{VCO} \) — в диапазоне 100–432 МГц, коэффициент \( P \in \{2, 4, 6, 8\} \), а частота для USB должна быть ровно 48 МГц. Для кварца 8 МГц получается M = 4, N = 168, P = 2, Q = 7: генератор работает на частоте 336 МГц, ядро — на 168 МГц, USB — на 48 МГц.
Расчёт выполняется функцией ядра BeeFC, а не вручную: на учебных платах встречаются кварцы 8, 16 и 25 МГц.
Файл core/clock_calc.c
Настройка тактирования
Функция clock_init выполняет шесть шагов в строгом порядке. Порядок важен: каждый шаг готовит условия для следующего.
Файл hal/stm32f4/clock_stm32.c
5. Память
| Область | Начальный адрес | Объём | Особенности |
|---|---|---|---|
| флеш-память | 0x08000000 | 1 МБ | код, константы, начальные значения переменных |
| SRAM1 и SRAM2 | 0x20000000 | 128 КБ | переменные, стек, буферы прямого доступа к памяти |
| CCM | 0x10000000 | 64 КБ | доступна только ядру, недоступна для прямого доступа к памяти |
| постоянная память загрузчика | 0x1FFF0000 | 30 КБ | загрузчик производителя |
Всего у STM32F405 192 КБ ОЗУ, но только 128 КБ доступны контроллеру прямого доступа к памяти. Буфер, в который приём по последовательному порту выполняется без участия процессора, нельзя размещать в CCM: передача не произойдёт, ошибки при этом не возникнет. Зато CCM хорошо подходит для данных фильтров и регуляторов, к которым ядро обращается на каждом проходе цикла.

Сценарий компоновщика
Файл ld/beefc_f405.ld
Сценарий определяет символы _sidata, _sdata, _edata, _sbss и _ebss, которыми пользуется код запуска на третьем и четвёртом шагах. Переменная размещается в CCM атрибутом __attribute__((section(".ccm"))). Секция объявлена как NOLOAD, поэтому такие переменные не обнуляются кодом запуска и должны инициализироваться программой.
6. Счётчик тактов и аварийная остановка
Счётчик тактов DWT
Блок трассировки ядра содержит 32-битный счётчик CYCCNT, который увеличивается на единицу каждый такт ядра. На частоте 168 МГц его разрешение около 6 нс, а переполнение наступает примерно через 25,6 секунды. Счётчиком измеряется время выполнения фрагментов кода: разность двух показаний, вычисленная в беззнаковой арифметике, верна и при переполнении.
Обработчик аварийной остановки
При обращении по недопустимому адресу, делении на ноль с включённой проверкой или ошибке выравнивания ядро вызывает обработчик HardFault_Handler. Перед вызовом ядро сохраняет в стеке восемь регистров, среди них адрес инструкции, на которой произошла авария.
Файл hal/stm32f4/clock_stm32.c
Шестой элемент массива g_fault_regs — регистр PC. Команда info line *0x08000abc в отладчике GDB показывает строку исходного кода по этому адресу.
7. Практика
Задание S3.1. Расчёт умножителя частоты
Продолжительность — 30 минут, выполняется на компьютере.
Реализовать функции pll_calc и flash_wait_states в файле core/clock_calc.c. Функция должна подбирать коэффициенты для кварцев 8, 16 и 25 МГц и возвращать false, если получить ровно 48 МГц для USB невозможно.
Файл tests/unit/test_level1.c
Критерий автоматической проверки: тесты test_pll_* пройдены.
Задание S3.2. Тактирование 168 МГц на плате
Продолжительность — 50 минут.
Подключить clock_init и dwt_init в функции main. Измерить счётчиком CYCCNT число тактов одного прохода пустого цикла задержки из урока S2 до и после настройки тактирования. Записать результаты в отчёт docs/s3_report.md.
Критерий автоматической проверки: в модели Renode переменная SystemCoreClock после вызова clock_init равна 168 000 000.
Задание S3.3. Намеренная авария
Продолжительность — 40 минут.
Добавить в программу чтение по адресу 0x30000000, где нет памяти. Убедиться, что программа останавливается в HardFault_Handler, найти по значению регистра PC строку с ошибкой и приложить снимок экрана отладчика к отчёту.
8. Как это сделано в больших прошивках
| Прошивка | Версия | Файл в исходном коде |
|---|---|---|
| Betaflight | 2026.6.2 | src/platform/STM32/startup/startup_stm32f40xx.s, src/platform/STM32/link/stm32_flash_f405.ld, src/platform/STM32/system_stm32f4xx.c |
| INAV | 9.1.0 | src/main/startup/startup_stm32f40xx.s, src/main/drivers/system_stm32f4xx.c |
| ArduPilot | Copter-4.7.2 | libraries/AP_HAL_ChibiOS/hwdef/scripts/chibios_hwdef.py |
| PX4 | v1.17.0 | ROMFS/px4fmu_common/init.d/rcS |
- Betaflight использует собственный сценарий компоновщика
stm32_flash_f405.ld. В нём область CCM получает два псевдонима:STACKRAMиFASTRAM: в CCM размещаются стек и данные, помеченные макросамиFAST_DATAиFAST_DATA_ZERO_INIT. В файлеbuild_config.hпрямо указано, что на F4 прямой доступ к памяти в CCM невозможен. - Файл
system_stm32f4xx.cв Betaflight и INAV основан на файле производителя и содержит ту же последовательность: такты ожидания, умножитель, переключение на него. - ArduPilot не хранит настройку тактирования в коде вручную: сценарий
chibios_hwdef.pyгенерирует её из строкиOSCILLATOR_HZ 8000000файлаhwdef.dat. - В PX4 после запуска операционной системы NuttX выполняется сценарий
rcS, который запускает модули прошивки по очереди. Это пример того, что в крупной прошивке функцияmain— лишь начало длинной цепочки запуска.
9. Проверьте себя
- Какие два слова читает ядро Cortex-M4 из начала флеш-памяти после сброса?
- Почему в функции
SystemInitнельзя сохранять значения в глобальные переменные? - Рассчитайте коэффициенты умножителя частоты для кварца 8 МГц и частоты ядра 168 МГц.
- Почему буфер приёма с прямым доступом к памяти нельзя размещать в CCM?
- С какой частотой тактируются таймеры шины APB1 при частоте шины 42 МГц и почему?
- Как найти строку кода, вызвавшую аварийную остановку?
10. Чек-лист самопроверки
11. Источники
- Справочное руководство RM0090, разделы 2 «Memory and bus architecture», 3 «Embedded Flash memory interface» и 7 «Reset and clock control».
- Техническое описание STM32F405RG.
- Руководство программиста PM0214 по ядру Cortex-M4, разделы об исключениях и регистре CPACR.
- Заголовочные файлы и файлы запуска CMSIS для STM32F4.
- CMSIS версии 5.
12. Что дальше
- Следующий урок: S4. Язык C для встраиваемых систем и архитектура BeeFC.
- Полный перечень уроков приведён в статье «Курс BeeFC: содержание уровня „Старт“».
Проверено: 13.10.2026
↑ К оглавлению- мод. : Четверг, 15 октября 2026