Ярлыки

_GetPixelIndex (1) _SetPixelIndex (1) 3-phase (1) 800x480 (1) АЦП (1) генератор (1) синхронный усилитель (2) структура (1) учебный курс (1) шаговый двигатель (1) ШИМ (2) accert (1) AD7608 (1) AD8429 (1) ADC (5) amplifer (1) arccos (1) arcsin (1) arctang (2) arctg (3) ARM (2) arm_sqrt_q15 (2) assembler (6) ASSERT (1) atan (2) bit (1) Bitband (1) boot (3) bootlloader (1) BUTTON (1) C (5) C# (1) CAN (2) CC2530 (5) CMSIS (4) command (1) Cordic (1) Core746I (1) CubeMX (4) DBGMCU (2) debug (2) debug.ini (1) delegate (1) Digital Potentiometers (1) DigitalPOT (1) Discovery (1) DMA (9) DMA2D (1) DSP (1) DSP library (1) DWT (1) EFM32 (5) EmWin (9) EXTI (1) FATFS (1) FMC (2) FreeRTOS (2) gl868-dual cmux (1) GPIO (4) GUI (2) GUIBuilder (1) GUIDRV_CompactColor_16 (1) HAL (3) HappyGecko (1) Hard Fault (2) heap (1) I2C (1) ID (1) ILI9320 (1) ILI9325 (1) Initialisation (1) InitLTDC (1) Instrumentithion (1) Interrupt (4) ITR (1) JTAG (1) Keil (5) LCDConf (2) lock-in (1) LTCD (1) LTDC (3) main (1) memory (1) MINI_STM32 Revision 01 (1) nBoot0 (1) NVIC (1) OnePulse (2) OSAL (4) pack (1) phase (1) printf (3) Pulse (1) PWM (12) RCC (2) RCR (1) Register (1) RESET (2) RS232 (3) RSS (1) RTC (3) RTOS-RTX (1) RTT (1) RTX-RTOS (1) SDCard (1) SDRAM (6) Segger (2) SPI (3) sqrt (3) SSD1298 (1) SSD1963 (1) Standart Peripherial Library (3) STANDBAY (1) startup (1) STemWin (8) stepper motor (1) STlink (2) STM32 (17) STM32429ZI (1) STM32Cube (1) STM32DBG.IN (1) STM32F (28) STM32F0 (4) STM32F1 (13) STM32F4 (10) STM32F4 Discovery (1) STM32F407ZG (1) STM32F429 (2) STM32F746 (1) STOP (1) string (1) struct (1) SWD (1) SWD JTAG (1) Synhronization (1) system_stm32f4xx.c (1) SystemInit (1) SysTick (1) task (4) telit (1) TIM (27) typedef (1) UART (1) USART (9) viewer (2) WM_PAINT (1) Z-stack (5) ZigBee (5)

понедельник, 16 февраля 2015 г.

RCC STM32F1

Контроллеры STM32 обладают достаточно развитой системой тактирования, включающей кучу различных делителей, умножителей и селекторов, которые позволяют "разогнать" до 72 МГц частоту ядра и системной шины, а также организовать тактирование на различных частотах всех входящих в состав контроллера модулей (USB, I/O, I2C, SPI...).

При этом стартует контроллер всегда от внутреннего генератора на 8 МГц, а дальнейший "разгон" и настройка тактирования различных модулей выполняется программно.

Все регистры, отвечающие за настройку системы тактирования сгруппированы в так называемый блок RCC (reset and clock control). Это десять 32-х битных регистров, доступных в памяти начиная с адреса 0x40021000, названия которых начинаются с "RCC_".

Настройку системы тактирования можно разделить на два этапа. На первом этапе настраивается системная тактовая частота. На втором этапе - частота системной шины AHB и подключенные к шине AHB модули. Отдельно от этих двух этапов можно настроить низкоскоростные генераторы для часов реального времени и независимого "собачьего таймера".



Тут важно запомнить и понять вот что: 1) все модули контроллера "сидят" на каких-нибудь шинах, 2) после включения контроллера тактирование большинства модулей, а также тактирование периферийных шин - выключены. Соответственно, до тех пор, пока вы не затактируете выключенные шины и модули - вам не будут доступны регистры настройки модулей. Из этих регистров будут читаться одни нули, а запись в них не будет иметь никакого эффекта.

Структурной схему, показывающую какие в контроллере есть шины и модули, какие модули к какой шине подключены и какие регистры используются для настройки всей этой системы, можно найти в документации. Тут самый главный документ - это Reference Manual RM0008 (CD00171190.pdf).

На рисунке ниже изображена древовидная структура, показывающая компоненты, используемые для настройки системной тактовой частоты, часов реального времени и независимого "собачьего таймера", с указанием регистров и битов, необходимых для настройки. Название регистров написано в прямоугольниках на заднем плане, а название битов - в прямоугольниках на переднем плане, в квадратных скобках.


Серыми прямоугольниками в левом ряду обозначены 4 первичных источника тактовых сигналов: HSI - высокоскоростной встроенный RC-генератор, HSE - усилитель внешнего высокоскоростного кварцевого резонатора, LSE OSC - усилитель часового кваца (внешний низкоскоростной резонатор), LSI RC - низкоскоростной RC-генератор.

Настройка приведённого на рисунке выше "дерева" происходит слева-направо, начиная с выбора первичных источников тактового сигнала. При этом общая методика такая: настраиваем модуль, включаем модуль, ждём сигнала готовности. После получения сигнала готовности переходим к настройке компонента, находящегося правее.

Сигнал готовности означает, что выходная частота соответствующего компонента стабилизировалась и её можно использовать дальше. В качестве сигнала готовности используются специальные биты в специальных регистрах (индивидуальные для каждого модуля). На схеме эти регистры и биты не отражены, но их можно найти в документации. Например, о готовности PLL сигнализируется установкой бита PLLRDY в регистре RCC_CR, о готовности усилителя внешнего кварца - установкой бита HSERDY в регистре RCC_CR и так далее.

Интересной фишкой является наличие в процессоре Cortex-M3 модуля CSS (clock security system). Этот модуль включается программно и после включения начинает анализировать работу внешнего кварца (HSE). При обнаружении ошибки, он автоматически отключает внешний кварц и переключает селектор выбора системной частоты на внутренний высокоскоростной генератор (HSI). Если HSE использовался не напрямую, а через PLL, то PLL тоже выключается. Кроме того, при срабатывании модуля CSS генерируется прерывание NMI И посылаются сигналы ошибки таймерам TIM1, TIM8.

После того, как первый этап закончен - можно приступать ко второму. Настраиваемые на этом этапе компоненты и последовательность их настройки также изображены в виде древовидной структуры (рисунок ниже).



Если мы работаем с flash-памятью, а не перегружаем программу в оперативку, то для оптимальной работы нашего камня должны быть настроены ещё кое-какие опции.

Во-первых, нужно задать параметр, называемый Latency. Это количество циклов задержки для операций чтения из flash. Оно задаётся исходя из следующих правил:
=0, если 0 ≤ SYSCLK ≤ 24 MHz;
=1, если 24 MHz ≤ SYSCLK ≤ 48 MHz;
=2, если 48 MHz ≤ SYSCLK ≤ 72 MHz.

Во-вторых, для ускорения работы процессора, должен быть включен буфер предварительной выборки (prefetch buffer), который позволяет вычитывать инструкции из flash двумя 64-х битными блоками. Включить или выключить этот буфер можно только когда SYSCLK < 24 MHz и делитель шины AHB=1. После сброса он автоматически включается, поэтому нам ничего делать не нужно. Но обычно если его хотят выключить, то делают это в самом начале программы, при инициализации, когда контроллер ещё работает от внутреннего генератора 8 MHz.

Обе перечисленные выше настройки flash-памяти доступны в регистре FLASH_ACR.

Для контроля полученных в итоге частот можно использовать специальную ногу (PA8), одна из функций которой - работа в качестве MCO (microcontroller clock output). На эту ногу можно настроить вывод одной из следующих частот: SYSCLK, HSI, HSE, PLL/2. Выбор осуществляется программированием битов MCO[2:0] в регистре RCC_CFGR. Кроме программирования этих битов нужно затактировать шину APB2 (на которой находится GPIO) и настроить ногу PA8 на функционирование в качестве MCO. Кроме того, при использовании PA8 в качестве MCO необходимо учитывать, что частота GPIO не должна превышать 50 МГц (а SYSCLK как мы помним можно разогнать до 72-х).

Ну вот пожалуй и всё. А в заключении давайте напишем небольшой пример - разгоним наш камень до заветных 72-х МГц и выведем частоту PLL/2 через MCO:

;---------------------------------------------------------
; blocks addresses
SAR         EQU 0x42000000 ; Start Alias Region
FLASH       EQU 0x40022000
RCC         EQU 0x40021000
PORTA       EQU 0x40010800
; registers addresses
FLASH_ACR   EQU FLASH+0x0
RCC_CR      EQU RCC+0x0
RCC_CFGR    EQU RCC+0x4
RCC_APB2ENR EQU RCC+0x18
GPIOA_CRH   EQU PORTA+0x4
; bits numbers
LAT1        EQU 1
HSEON       EQU 16
HSERDY      EQU 17
PLLSRC      EQU 16
PLLMUL      EQU 18
PPRE2       EQU 11
PLLON       EQU 24
PLLRDY      EQU 25
SW1         EQU 1
AFIOEN      EQU 0
IOPAEN      EQU 2
MCO         EQU 24
MODE8       EQU 0
CNF8        EQU 2

AREA STACK, NOINIT, READWRITE
SPACE 0x400
Stack_top

AREA RESET, DATA, READONLY
dcd Stack_top
dcd Program_start

AREA PROGRAM, CODE, READONLY
ENTRY
Program_start
InitClock
mov r9, #1
   ; устанавливаем Latency = 2
ldr r0, =SAR+(FLASH_ACR&0x00FFFFFF)*0x20+LAT1*4
str r9,[r0]
   ; включаем HSE
ldr r0, =SAR+(RCC_CR&0x00FFFFFF)*0x20+HSEON*4
str r9,[r0]
   ; ждём появления флага HSERDY
ldr r0, =RCC_CR      ; загружаем в r0 адрес регистра RCC_CR
wait_hserdy
ldr r10,[r0]         ; читаем регистр RCC_CR
   ; проверяем, равен ли бит HSERDY единице (&0x20000)
tst r10,#(1<<HSERDY)
beq wait_hserdy
   ; выбираем HSE источником для PLL, устанавливаем множитель=9,
   ; предделитель для APB2 (/2), выбираем источник для MCO
ldr r0,=RCC_CFGR     ; загружаем адрес регистра RCC_CFGR
ldr r10,=(1<<PLLSRC)+(7<<PLLMUL)+(4<<PPRE2)+(7<<MCO)
str r10,[r0]
   ; включаем PLL
ldr r0,=SAR+(RCC_CR&0x00FFFFFF)*0x20+PLLON*4
str r9,[r0]
   ; ждём появления флага PLLRDY
ldr r0, =RCC_CR      ; загружаем адрес регистра RCC_CR
wait_pllrdy
ldr r10,[r0]         ; читаем RCC_CR
   ; проверяем, равен ли бит PLLRDY единице (&0x2000000)
tst r10, #(1<<PLLRDY)
beq wait_pllrdy
   ; выбираем PLL в качестве SYSCLK
ldr r0,=SAR+(RCC_CFGR&0x00FFFFFF)*0x20+SW1*4
str r9,[r0]
   ; включаем тактирование PORTA
ldr r0,=SAR+(RCC_APB2ENR&0x00FFFFFF)*0x20+IOPAEN*4
str r9,[r0]
   ; конфигурим PORTA для MCO
ldr r0,=GPIOA_CRH
ldr r10,[r0]         ; читаем регистр GPIOA_CRH
   ; устанавливаем для PA8 MODE=11 (output max speed 50MHz),
   ; CNF=10  (alternate function output push-pull)
ldr r11,=(3<<MODE8)+(2<<CNF8)
bfi r10, r11, #0, #4 ; копируем 4 младших бита r11 в r10
str r10,[r0]         ; записываем r10 в GPIOA_CRH
;------------------
   ; ничего не делаем
Work
b Work
END
;---------------------------------------------------------

Естественно, в реальности никто в заголовке имена и адреса регистров и битов не описывает, вместо этого берут готовый файл, в котором все эти имена описаны и добавляют его в свой код директивой GET. В примере я их специально описал, чтобы было понятно, откуда что берётся (сопоставьте их с картой памяти, которую мы рассматривали в третьей части).

Ну да ладно, пусть этот код и не самый оптимальный, зато, надеюсь, предельно понятный. Для установки отдельных битов в примере используется метод bit-banding, если требуется изменить сразу кучу битов - классические "чтение-модификация-запись".


1 комментарий: