STM32F100: включение и выход в рабочий режим
В момент подачи питания на микроконтроллер или после сигнала сброса,
независимо от других обстоятельств, ядро
тактируется от внутреннего RC-генератора частотой 8 мГц.
При этом PLL (умножитель частоты) отключен
а время задержки чтения из FLASH (latency time) равно нулю.
Такая схема включения гарантирует, что микроконтроллер запустится
и начнёт работать всегда, даже если внешний кварц неисправен.
Запуск кварца осуществляется вручную, программным способом.
Запуск можно проконтролировать и в случае неисправности кварца,
обработать ошибку и оставаться затактированным от внутреннего RC.
Микроконтроллер STM32 серии F100 имеет в своём составе ещё одну схему защиты, когда
при сбое внешнего кварца он может автоматически переключиться
на внутренний 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 мГц.
Теперь ассемблерный код только подавай! Вперёд и с песней!
Ах да! Ещё же есть RTC и внешний часовой кварц. Их то же надо запустить,
примерно по такой же схеме.
; Шаг первый. Разрешить доступ к backup domain
; Установкой бита DBP = 1
MOV32 R0, (PWR_CR & 0x00FFFFFF) * 0x20 \
+ 0x42000000 \
+ 8 * 4
STR R11, [R0]
; Проверить готовность CNF
MOV32 R0, RTC_CRL
wait_cnf
LDR R1, [R0]
TST R1, RTC_CRL_RTOFF
BEQ wait_cnf
; Разрешить перезапись регистров RTC
; Установкой в 1 бита CNF
MOV32 R0, (RTC_CRL & 0x00FFFFFF) * 0x20 \
+ 0x42000000 \
+ 4 * 4
STR R11, [R0]
; Включить усилитель часового кварца, LSEON = 1
; Для включения используем метод BitBand
MOV32 R0, (RCC_BDCR & 0x00FFFFFF) * 0x20 \
+ 0x42000000 \
+ 0 * 4
;^^^ здесь 0 - номер бита, который нужно включить
STR R11, [R0]
; Ждём готовности часового кварца
; Внимание! Если с кварцем будут проблемы
; Такой цикл рискует стать бесконечным!
MOV32 R0, RCC_BDCR
wait_lserdy
LDR R1, [R0]
TST R1, RCC_BDCR_LSERDY
BEQ wait_lserdy
; Выбираем внешний часовой кварц
; В качестве источника тактовых импульсов для часов
; RTCSEL = 01
MOV32 R0, (RCC_BDCR & 0x00FFFFFF) * 0x20 \
+ 0x42000000 \
+ 8 * 4
STR R11, [R0]
; Установить делитель часового кварца на 32.768 - 1 Гц
MOV32 R0, RTC_PRLH
STRH R10, [R0], 4
MOV R1, 0x7FFF
STRH R1, [R0]
; А теперь запустим наши часики, пущяй тикают
; RTCEN = 1
MOV32 R0, (RCC_BDCR & 0x00FFFFFF) * 0x20 \
+ 0x42000000 \
+ 15 * 4
STR R11, [R0]
; Теперь можно изменять значения часовых регистров.
; Внимание! Что бы регистры изменились, часы должны тикать!
; Установить какое-нибудь начальное время
; Обычно время задаётся в секундах с начала эпохи
MOV32 R0, RTC_CNTL
MOV32 R1, 1000000000
STRH R1, [R0], -4
ROR R1, R1, #16
STRH R1, [R0]
; Задать время для будильника
; Очевидно, оно должно быть больше текущего времени
MOV32 R0, RTC_ALRL
MOV32 R1, 1000000000+100
STRH R1, [R0], -4
ROR R1, R1, #16
STRH R1, [R0]
; Сбросить флаг CNF, что бы изменения часовых регистров вступили в силу
MOV32 R0, (RTC_CRL & 0x00FFFFFF) * 0x20 \
+ 0x42000000 \
+ 4 * 4
STR R10, [R0]
; Дождаться обновления регистров
; Не забудьте предварительно запустить часы (код выше)
; Иначе этот цикл станет бесконечным
MOV32 R0, RTC_CRL
wait_cnf2
LDR R1, [R0]
TST R1, RTC_CRL_RTOFF
BEQ wait_cnf2
; Теперь можно заблокировать доступ к backup domain
; Установкой бита DBP = 0
MOV32 R0, (PWR_CR & 0x00FFFFFF) * 0x20 \
+ 0x42000000 \
+ 8 * 4
STR R10, [R0]
Вот собственно и всё. Смотрите, не опоздайте! Вовремя заводите будильник!!