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]


Вот собственно и всё. Смотрите, не опоздайте! Вовремя заводите будильник!!