STM32F100: включение и выход в рабочий режим
Своё знакомство с кортексами я начинал с нового и модного тогда ядра M3,
на камушке STM32F103. Было интересно писать короткие фрагменты кода
и следить за реакцией процессора в отладчике.
Кейл по своей природе недоделаный и сырой, но всё же глаза округлялись, видя бегающие по экрану циферки!
Естественно хотелось скорости.
Поэтому моей первой серьёзной работой стала инициализация
ядра c выходом на штатные 72 MHz.
В момент подачи питания на микроконтроллер или после сигнала сброса,
независимо от других обстоятельств, ядро
тактируется от внутреннего RC-генератора частотой 8 мГц.
При этом PLL (умножитель частоты) отключен
а время задержки чтения из FLASH (latency time) равно нулю.
Такая схема включения гарантирует, что микроконтроллер запустится
и начнёт работать всегда, даже если внешний кварц неисправен.
Запуск кварца осуществляется программным способом.
Процесс инициализации можно контролировать, а в случае неисправности кварца,
обработать ошибку и оставаться затактированным от внутреннего RC.
Микроконтроллеры STM32 имеют в своём составе ещё одну схему защиты, когда
при сбое внешнего кварца, схема тактирования может автоматически переключиться
на внутренний RC и без остановок продолжить работу камня, сигнализируя об ошибке.
По умолчанию эта возможность отключена.
Что бы вывести микроконтроллер на проектную мощность - одноцикловый
режим работы на частоте 72 мГц, нужно выполнить три простых шага.
Включить усилитель кварца и дождаться его стабилизации.
Включить PLL и дождаться стабилизации.
Затем переключить тактирование с внутреннего RC на PLL.
В случае, если вы используете кварц на 8 мГц, PLL должен быть настроен
на 9-кратное умножение частоты.
; Для BitBand под рукой всегда должны быть нолик и единичка
MOV R10, 0
MOV R11, 1
; Шаг первый. Затактировать POWER control
; Используем метод BitBand
MOV32 R0, (RCC_APB1ENR & 0x00FFFFFF) * 0x20 \
+ 0x42000000 \
+ 28 * 4
; ^^ здесь 28 - номер бита, который нужно включить
STR R11, [R0]
; Установить LATENCY time = 2 машинных цикла
; + задействовать буферизацию FLASH (по умолчанию всегда включена)
MOV32 R0, FLASH_ACR
MOV R1, FLASH_ACR_LATENCY_2 + FLASH_ACR_PRFTBE
STR R1, [R0]
; Включить усилитель кварца
MOV32 R0, (RCC_CR & 0x00FFFFFF) * 0x20 \
+ 0x42000000 \
+ 16 * 4
STR R11, [R0]
Питание на усилитель кварца подано.
И по идее, теперь нужно дождаться стабилизации частоты,
пока он раскочегарится, так сказать. И мы будем ждать, смотрите код ниже.
Хотя можно было заняться в это время чем-нибудь полезным. Например, настроить порты,
запустить экран. И не транжирить ценные миллисекунды.
; Ждём готовности кварца, контролируя бит RCC_CR_HSERDY
MOV32 R0, RCC_CR
wait_hserdy
LDR R1, [R0]
TST R1, RCC_CR_HSERDY
BEQ wait_hserdy
; Если кварц окажется неисправен
; Этот цикл рискует стать бесконечным
; Установим коэфф умножения * 9 для PLL
; И деления на 2 для APB1
MOV32 R0, RCC_CFGR
MOV32 R1, ((9-2) << 18) + RCC_CFGR_PLLSRC + RCC_CFGR_PPRE1_DIV2
; ^^^ здесь 9 = коэфф. умножения PLLMUL. 8*9 = 72 mHz
STR R1, [R0]
; Включаем PLL
; На его стабилизацию то же потребуется время.
MOV32 R0, (RCC_CR & 0x00FFFFFF) * 0x20 \
+ 0x42000000 \
+ 24 * 4
STR R11, [R0]
; Ждём готовности PLL
MOV32 R0, RCC_CR
wait_pllrdy
LDR R1, [R0]
TST R1, RCC_CR_PLLRDY
BEQ wait_pllrdy
; Выбираем PLL как источник тактового сигнала для микроконтроллера
MOV32 R0, (RCC_CFGR & 0x00FFFFFF) * 0x20 \
+ 0x42000000 \
+ 1 * 4
STR R11, [R0]
; Ждём готовности
MOV32 R0, RCC_CFGR
wait_swspll
LDR R1, [R0]
TST R1, RCC_CFGR_SWS_PLL
BEQ wait_swspll
Вот и всё, и совсем даже не больно! Теперь наш камень работает
на full speed, full power, крейсерские 72 мГц.
Теперь ассемблерный код только подавай! Вперёд и с песней!
p.s. этот код считается устаревшим. Я давно не работаю в кейле.
Средой разработки теперь является блокнот. А компилятором - утилиты из пакета
GCC binutils.