Все что нам нужно знать для написания программ на языке ассемблера для stm32f4 я уже написал, ссылки на прошлые публикации:
STM32F4: GNU AS: Программирование на ассемблере (Часть 1)
STM32F4: GNU AS: Мигаем светодиодом (Оживление) (Часть 2)
STM32F4: GNU AS: Мигаем светодиодом (Версия для STM32F4 Discovery, Оптимизация) (Часть 3)
STM32F4: GNU AS: Настраиваем среду компиляции (Часть 4)
Если вы читали публикации не как увлекательное чтиво, а разбираясь в прочитанном (и находя ошибки! спасибо тем кто мне о них написал!), то к вам уже пришло понимание того, что программирование на ассемблере это не какой-то архисложный и малопонятный, а простой, понятный и эффективный процесс 🙂
Теперь нужно наработать библиотеку модулей которые бы помогали использовать ту или иную функциональность периферии микроконтроллера, и плюс ко всему упростить настройку этой периферии.
Для начала, запустим микроконтроллер на его штатной частоте: 168 мгц, от внешнего кварцевого генератора, с использованием PLL.
В этом модуле нужно будет заложить возможность настройки системы тактирования без вмешательства в сам текст модуля. Во первых так намного проще использовать модуль — нам не придется смотреть по коду «где еще какая настройка находится», а во вторых — не придется спустя полгода — год разбираться в зависимостях внутри программы (пусть даже хорошо откомментированной).
Для этого я вынес все настройки в начало файла:
@ *************************************************************************** @ * НАСТРОЙКИ МОДУЛЯ * @ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * @ * значения делителей и множителей * @ * * @ * Формула расчета частоты PLL * @ * * @ * PLL_VCO = ([HSE_VALUE or HSI_VALUE] / PLL_M) * PLL_N * @ * * @ * Упрощенно: делитель PLL_M должен делить частоту кварца таким образом * @ * чтобы на выходе получить 2 МГц. Для кварца 8 МГц: PLL_M = 4, для кварца * @ * 16 МГц: PLL_M=8, и так далее. (стр.227 RM0090 Reference manual) * @ .equ PLL_M , 4 .equ PLL_N , 168 @ * Формула расчета частоты тактирования процессора (стандарт: 168 мгц): * @ * * @ * SYSCLK = PLL_VCO / PLL_P * @ .equ PLL_P , 2 @ * Формула расчета тактовой частоты для USB (стандарт: 48 мгц): * @ * * @ * USB OTG FS, SDIO and RNG Clock = PLL_VCO / PLLQ * @ .equ PLL_Q , 7 @ * - - - - - - - - - - - - - - - - - - - - - - - - * @ * значение таймаута при операциях ожидания готовности (степень двойки) * @ * Этот параметр менять не обязательно, в случае критической ошибки при * @ * запуске тактирования - ошибка будет сгенерирована и возвращена в R0 * @ * по умолчанию стоит значение: 12 * .equ timeout, 12 @ ***************************************************************************
далее, для упрощения использования модуля в проектах — все константные значения которые в нем использованы я внес в сам модуль — теперь, для того чтобы его использовать нужно только положить .asm файл в папку проекта, никаких дополнительных включений файла определений stm32f40_def.inc делать не нужно (таким образом вы можете использовать модуль даже со своим файлом определений который вы форматируете и формируете под себя, без всяких оговорок, о том что есть значения которые должны называться «так как принято, иначе сторонние модули работать не будут»:
.syntax unified @ синтаксис исходного кода .thumb @ тип используемых инструкций Thumb .cpu cortex-m4 @ процессор .fpu fpv4-sp-d16 @ сопроцессор @ константы используемые модулем .equ PERIPH_BASE ,0x40000000 .equ APB1PERIPH_BASE ,0x00000000 .equ AHB1PERIPH_BASE ,0x00020000 .equ RCC_BASE ,(AHB1PERIPH_BASE + 0x3800) .equ RCC_CR ,0x00000000 .equ RCC_CR_HSEON ,0x00010000 .equ RCC_CR_HSERDY ,0x00020000 .equ RCC_CR_PLLON ,0x01000000 .equ RCC_CR_PLLRDY ,0x02000000 .equ RCC_APB1ENR ,0x40 .equ RCC_APB1ENR_PWREN ,0x10000000 .equ PWR_BASE ,(APB1PERIPH_BASE + 0x7000) .equ PWR_CR ,0x00000000 .equ PWR_CR_VOS ,0x4000 .equ RCC_CFGR ,0x08 .equ RCC_CFGR_HPRE_DIV1 ,0x00000000 .equ RCC_CFGR_PPRE2_DIV2 ,0x00008000 .equ RCC_CFGR_PPRE1_DIV4 ,0x00001400 .equ RCC_CFGR_SW ,0x00000003 .equ RCC_CFGR_SW_PLL ,0x00000002 .equ RCC_CFGR_SWS_PLL ,0x00000008 .equ RCC_PLLCFGR_PLLSRC_HSE,0x00400000 .equ RCC_PLLCFGR ,0x04 .equ FLASH_R_BASE ,(AHB1PERIPH_BASE + 0x3C00) .equ FLASH_ACR ,0x00000000 .equ FLASH_ACR_ICEN ,0x00000200 .equ FLASH_ACR_DCEN ,0x00000400 .equ FLASH_ACR_LATENCY_5WS ,0x00000005 .equ FLASH_ACR_PRFTEN ,0x00000100
Текст программы модуля, по нашим договоренностям из четвертой части публикации размещаем в секции .asmcode, имя процедуры делаем глобальным для возможности вызова из других файлов проекта:
.section .asmcode .global SYSCLK168_START SYSCLK168_START: PUSH { LR } LDR R7, =(PERIPH_BASE + RCC_BASE) @ Включаем HSE LDR R1, [R7, RCC_CR] ORR R1, R1, RCC_CR_HSEON STR R1, [R7, RCC_CR] @ Ожидаем стабилизации частоты кварца MOV R0, 1 @ код ошибки при выходе по timeout ADD R6, R7, RCC_CR @ регистр для проверки LDR R2, =RCC_CR_HSERDY @ бит для проверки BL TST_BIT @ Включаем POWER control LDR R1, [R7, RCC_APB1ENR] ORR R1, R1, RCC_APB1ENR_PWREN STR R1, [R7, RCC_APB1ENR] @ Вн. регулятор в режим "нагрузкa" (выходим из энергосбережения) LDR R1, =(PERIPH_BASE + PWR_BASE + PWR_CR) LDR R2, [R1] ORR R2, R2, PWR_CR_VOS STR R2, [R1] @ Установим делители шин LDR R1, [R7, RCC_CFGR] @ делитель шины AHB ORR R1, R1, RCC_CFGR_HPRE_DIV1 @ HCLK=SYSCLK STR R1, [R7, RCC_CFGR] LDR R1, [R7, RCC_CFGR] @ делитель шины APB2 ORR R1, R1, RCC_CFGR_PPRE2_DIV2 @ PCLK2=HCLK / 2 STR R1, [R7, RCC_CFGR] LDR R1, [R7, RCC_CFGR] @ делитель шины APB1 ORR R1, R1, RCC_CFGR_PPRE1_DIV4 @ PCLK1=HCLK / 4 STR R1, [R7, RCC_CFGR] @ Настройка PLL коэффициентами PLL_M, PLL_N, PLL_Q, PLL_P LDR R1, =RCC_PLLCFGR_val @ расчитанное значение STR R1, [R7, RCC_PLLCFGR] @ Включаем питание PLL LDR R1, [R7, RCC_CR] ORR R1, R1, RCC_CR_PLLON STR R1, [R7, RCC_CR] @ Ожидаем готовности PLL ADD R0, R0, 1 LDR R2, =RCC_CR_PLLRDY BL TST_BIT @ Настройка Flash prefetch, instruction cache, data cache и wait state LDR R2, =(PERIPH_BASE + FLASH_R_BASE + FLASH_ACR) LDR R1, [R2] LDR R1, =(FLASH_ACR_ICEN + FLASH_ACR_DCEN + FLASH_ACR_LATENCY_5WS + FLASH_ACR_PRFTEN) STR R1, [R2] @ Выбираем PLL источником такта LDR R1, [R7, RCC_CFGR] BIC R1, R1, RCC_CFGR_SW ORR R1, R1, RCC_CFGR_SW_PLL STR R1, [R7, RCC_CFGR] @ Ожидаем переключения на PLL ADD R0, R0, 1 ADD R6, R7, RCC_CFGR LDR R2, =RCC_CFGR_SWS_PLL BL TST_BIT MOV R0, 0 @ признак успешности выполнения B exit @ Подпрограмма проверки готовности: ------------------------------------------ @ R0 - статус на выход @ R1 - адрес для чтения @ R2 - бит-карта для сравнения @ R3 портиться ! @ R4 портиться ! TST_BIT: ADD R3, R0, R0, lsl timeout @ значение timeout TST_ready: @ проверка на таймаут SUBS R3, R3, 1 BEQ exit @ timeout истек, выходим ! @ проверка готовности HSE LDR R4, [R6, 0] TST R4, R2 BEQ TST_ready BX LR @ выход из процедуры exit: POP { PC }
Ну и после проверки работы модуля, сделаем ему небольшое описание которое поместим в начало файла:
@GNU AS @ *************************************************************************** @ * МОДУЛЬ НАСТРОЙКИ ТАКТИРОВАНИЯ STM32F4 * @ *************************************************************************** @ * Модуль настраивает систему тактирования микроконтроллера на внешний * @ * кварцевый генератор, с использованием PLL и установкой необходимых де- * @ * лителей для шин и интерфейсов, ошибки при исполнении фиксируются * @ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * @ * Модуль вызывать без параметров, регистры не сохраняются * @ * команда вызова: * @ * BL SYSCLK168_START * @ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * @ * Используемые регистры: R0, R1, R2, R3, R4, R6, R7 (не сохраняются) * @ * На входе: нет * @ * На выходе: R0 - статус результата настройки тактирования * @ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * @ * Статус результата: * @ * 0: Частота установлена * @ * 1: Не удалось запустить HSE * @ * 2: Не удалось запустить PLL * @ * 3: Не удалось переключиться на PLL *
У вас не должно возникнуть вопросов по использованию модуля, но если вдруг.., то наша программа мигалка (в секции .asmcode) должна начинаться с вызова модуля тактирования:
@ основная программа Start: .extern SYSCLK168_START BL SYSCLK168_START @ настройка тактирования MOV R0, 0 @ Значение 0, будет использоваться для bitband MOV R1, 1 @ значение 1, будет использоваться для bitband @ включим тактирование GPIO LDR R2, =(PERIPH_BB_BASE + (RCC_BASE + RCC_AHB1ENR) * 32 + RCC_GPIO_EN * 4) STR R1, [R2] @ запись R1 ("1") по адресу бита указанному в R2 . . .
поскольку частота тактирования микроконтроллера изменилась, возможно, потребуется увеличение значения счетчика в подпрограмме DELAY
Файл модуля можно скачать по ссылке sysclk.asm
ссылка на оригинал статьи https://habrahabr.ru/post/275653/
Добавить комментарий