czwartek, 19 maja 2016

[2] STM32F4 - Rejestry - Konfiguracja zegarów HSI oraz HSE

Ten post chciałbym poświęcić konfiguracji zegarów HSI oraz HSE za pomocą rejestrów, bez wykorzystania biblioteki API. 

Rodzaje zegarów


Możliwe źródła sygnałów zostały już przeze mnie opisane w innych postach, w związku z tym wymienię tylko ich rodzaje:

  • HSE - (ang. High Speed External) - zewnętrzne źródło sygnału. W STM32F4 - Discovery jest to kwarc o częstotliwości 8 MHz.
  • HSI - (ang. High Speed Internal) - wewnętrzny generator częstotliwości. Częstotliwość wynosi 16 MHz.
  • PLL - (ang. Phase Locked Loop) - zewnętrzna pętla powielacza częstotliwości
  • LSE - (ang. Low Speed External) - kwarc zegarowy. jego częstotliwość wynosi 32.768kHz
  • LSI - (ang. Low Speed Internal) - częstotliwość wynosi od 17 do 37 kHz.


Oprócz źródeł sygnałów występują następujące rodzaje sygnałów zegarowych:

  • SYSCLK jest to zegar systemowy, którego maksymalna częstotliwość taktowania wynosi 168 MHz, bez podkręcania, 
  • AHB działa z częstotliwością 168MHz, 
  • APB2 działa z maksymalną częstotliwością 84 MHz, sterowana z AHB
  • APB1 działa z maksymalną częstotliwością 42 MHz, sterowana z AHB

Dodatkowo sygnały zegarowe można wyprowadzić z dwóch pinów:

  • PA8 - pozwala na wyprowadzenie sygnałów HSI, LSE, HSE, PLL
  • PC9 - pozwala na wyprowadzenie sygnałów HSE, PLL, SYSCLK, PLLI2S (bardzo dokładna linia sygnałowa przeznaczona do sygnałów audio z interfejsów I2S oraz SAI1.

Rejestry


Teraz przedstawię listę rejestrów wraz z dostępnymi parametrami:

RCC_CR - RCC Clock control register - pozwala on na wybranie źródła taktującego, włączenie sygnału, ustawiania flag gotowości,

Rys. 1. RCC_CR
  • Bit 29 - PLLSAIRDY - flaga gotowości dla PLLSAI. Ustawiana gry PLLSAI jest gotowe. Dla wartości 0 jest odblokowany dla 0 zablokowany.
  • Bit 28 - PLLSAION - włączenie PLLSAI. Dla 0 wyłączony dla 1 włączony.
  • Bit 27 - PLLI2SRDY - flaga gotowości dla PLLI2S. Dla 0 wyłączona dla 1 włączona. Czyszczona przez układ w momencie wejścia w tryb stopu lub czuwania.
  • Bit 26 - PLLISON - włączenie PLLI2S. Dla 0 wyłączone dla 1 włączone.
  • Bit 25 - PLLRDY - ustawienie flagi gotowości głównej pętli PLL. Dla 0 odblokowane dla 1 zablokowane.
  • Bit 24 - PLLON - włączenie głównej pętli PLL. Nie można zresetować tego bitu gdy PLL jest wykorzystywane przez zegar systemowy. Dla 0 wyłączony, 1 włączony.
  • Bit 19 CSSON - Włączenie zabezpieczenia sygnału zegarowego. Jeśli jest ustawiony, wtedy wykrywane jest poprawne bądź niepoprawne włączenie sygnału z HSE. Dla 0 system ochrony wyłączony, dla 1 włączony.
  • Bit 18 - HSEBYP - tzw. clock bypass. Służy to łączenia oscylatora z zewnętrznym zegarem. Działa tylko gdy HSEON jest ustawiony na 1. Do tego rejestru można wpisać wartość tylko i wyłącznie gdy HSE jest wyłączony. Dla wartości 0 nie łączy oscylatora z HSE, 1 natomiast włącza takie połaczenie.
  • Bit 17 - HSERDY - flaga gotowości dla HSE. Zostaje ustawiona gdy HSE działa stabilnie. Po wyczyszczeniu bitu dla HSEON, HSERDY przechodzi w stan niski po 6 cyklach HSE.
  • Bit 16 - HSEON - włączenie zegara dla HSE. Ustawiana i czyszczona przez system. Ten bit nie może zostać zresetowany gdy HSE działa. 0 wyłącza HSE, 1 natomiast włącza.
  • Bit 15:8 - HSICAL[7:0] - Kalibracja HSI. ity ustawiane automatycznie przy starcie.
  • Bit 7:3 - HSITIM [4:0] - Pozawala na podłączenie dodatkowych ustawień dla HSI. Dzięki nim można programowo dobrać ustawienia dla napięcia czy temperatury, które wpływają na częstotliwość HSI.
  • Bit 1 - HSIRDY - flaga gotowości dla HSI. Ustawiana gdy oscylator działa stabilnie. Przechodzi w stan niski po 6 cyklach HSI. 0 gdy HSI nie jest gotowy do działania, gdy działa poprawnie ustawiana jest 1.
  • Bit 0 - HSION - Włączenie sygnału HSI. Wartość 0 wyłączony, 1 włączony.

RCC_PLLCFGR - RCC PLL configuration register - ten rejestr służy do ustawienia wartości zegara PLL.

Rys. 2. RCC_PLLCFGR

Częstotliwość obliczana jest na podstawie następujących wzorów:
  • f (Zegar VCO) = f(Wejście sygnału PLL) x (PLLN/PLLM)
  • f (PLL wyjście sygnału) = f(zegar VCO) / PLLP
  • f(USB OTG FS, SDIO, wyjście sygnału RNG) = f(zegar VCO) / PLLQ
Rejestr składa się z następujących części:
  • Bit 27:24 - PLLQ - Główny dzielnik dla częstotliwości dla układów USB OTG FS, SDIO itp. Bity do tego rejestru są wprowadzane tylko gdy PLL jest wyłączone. Należy pamiętać że USB OTG FS potrzebuje 48 MHz, natomiast SDIO oraz generator liczb losowych wymaga do pracy niższej częstotliwości taktowania. Do rejestrów należy wpradzać wartości od dwóch do 15 włącznie. Wartość 1 i 2 nie będą poprawne.
  • Bit 22 - PLLSRC - Wybranie źródła taktowania dla główej pętli PLL i PLLI2S. Dane mogą zostać wprowadzone tylko gdy PLL zostanie wyłączony. Do rejestru można wprowadzić dwie wartości 0 i 1, odpowiednio dla sygnałów HSI oraz HSE.
  • Bit 17:16 - PLLP - Ustawienie dzielnika dla zegara systemowego. Do wybrania są wartości 2, 4, 6 oraz 8. 
  • Bit 14:6  - PLLN - Wartość mnożnika dla sygnału PLL. Podczas ustawiania należy się upewnić, że częstotliwość po ustawieniu bitów znajduje się w zakresie od 100 do 432 MHz. Wartość wprowadzona do rejestru musi sie znajdować w zakresie od 50 do 432 włącznie.
  • Bit 5:0 - PLLM - Dzielnik dla PLL oraz PLLI2S. Częstotliwość wejściowa VCO powinna być z zakresu od 1 do 2 MHz. Powinno się ustawić 2 MHz w celu ograniczenia wahań PLL. Wartość dla rejestru musi znajdować się w zakresie od 2 do 63 włącznie.


RCC_CFGR - RCC clock configuration register - Rejestr wykorzystywany do konfiguracji dzielnika dla sygnałów oraz wybrania źródła sygnału.

Rys. 3. RCC_CFGR

  • Bit 31:30 - MCO2 - Ustawienie źródła sygnału wyjściowego na pin GPIO.  Należy je ustawić po resecie przed włączeniem zewnętrznego źródła sygnału taktującego. Można w nim ustawić następujące konfiguracje:
    • 00 - wybranie zegara systemowego SYSCLK
    • 01 - PLLI2S
    • 10 - HSE
    • 11 - PLL
  • Bit 29:27 - MCO2PRE - dzielnik częstotliwości wyjściowej dla MCO2. Dopuszczalnymi parametrami do ustawienia będą:
    • 100 - dzielnik 2
    • 101 - 3
    • 110 - 4
    • 111 - 5
  • Bit 26:24 - MCO1PRE - dzielnik częstotliwości wyjściowej dla MCO1. Parametry takie same jak dla MCO2PRE.
  • Bit 23 - I2SSRC - wybranie zegara dla I2S. Musi być ustawiony przed włączeniem I2S. Dla wartości 0 PLLI2S będzie źródłem sygnału, Wartość 1 natomiast pozwala na wybranie zewnętrznego źródła taktowania przemapowanego na I2S_CKIN.
  • Bit 22:21 - MCO1 - Ustawienie źródła sygnału taktującego. Następujące parametry pozwalają na ustawienie takich wartości jak:
    • 00 - HSI
    • 01 - LSE
    • 10 - HSE
    • 11 - PLL
  • Bit 20:16 - RTCPRE - Dzielnik sygnału HSE dla RTC. Do wybrania wartości od 2 do 31 włącznie.
  • Bit 15:13 - PPRE2 - dzielnik dla linii sygnału APB2. Do ustawienia wartość z przedziału od 2 do 16. 
  • Bit 12:10 - PPRE1 - dzielnik dla APB1. Parametry te same co dla PPRE2. 
  • Bit 7:4 - HPRE - dzielnik dla AHB. Jeśli ethernet jest wykorzystywany, należy wykorzystywać zegar o wartości minimum 25 MHz. Do ustawienia możliwe są następujące parametry:
    • 1000 - 2
    • 1001 - 4
    • 1010 - 8
    • 1011 - 16
    • 1100 - 64
    • 1101 - 128
    • 1110 - 256
    • 1111 - 512
  • Bit 3:2 - SWS - informacja o rodzaju wybranego źródła zegara systemowego. Możliwe następujące parametry:
    • 00 - HSI
    • 01 - HSE
    • 10 - PLL
    • 11 - nie wybrano
  • Bit 1:0 - SW - wybranie zegara systemowego. Parametry takie same jak dla SWS.


RCC_CIR - RCC clock interrupt register - ustawianie flag dla poszczególnych źródeł sygnału.

Rys. 4. RCC_CIR

Wymieniłem tutaj tylko kilka najważniejszych z rejestrów. Pozostałe można doczytać w nocie katalogowej opublikowanej przez firmę STM [1]. 

Programy

Poniżej przedstawię cztery programy przedstawiające w jaki sposób należy przeprowadzić ustawianie zegarów dla HSE, HSI oraz sposób włączenie maksymalnej częstotliwości taktowania poprzez pętle PLL. Ostatni program będzie przedstawiał sposób włączenia sygnałów na pinach PA8 oraz PC9. 

W celu włączenie zegara HSE należy do rejestrów wprowadzić następujące dane:

  1. #include "stm32f4xx.h"
  2. int main()
  3. {
  4.     //Wlaczenie HSI, wpisanie wartosci 1
  5.     RCC->CR |= (uint32_t)0x00000001;
  6.     //czekanie na ustabilizowanie sie sygnalu HSI
  7.     //do momentu az flaga zostanie ustawiona
  8.     while(!(RCC->CR & (uint32_t)0x00000002));
  9.     //Zresetetowanie ustawien w rejestrze CR
  10.     RCC->CR = (uint32_t)0x00000083;
  11.    
  12.     //Wlaczenie HSE
  13.     RCC->CR |= 0x00010000;
  14.    
  15.     //Petla oczekujaca na wlaczenie HSE
  16.     while(!(RCC->CR & 0x00020000));
  17.     //Wybranie HSE jako zegara systemowego
  18.     RCC->CFGR |= 0x00000001;
  19.    
  20.     //Czekanie az HSE bedzie uzywane jako zegar systemowy
  21.     while(!(RCC->CFGR & 0x00000004));
  22.     while(1);
  23. }

Aby uruchomić HSI należy postępować w następujący sposób:

  1. #include "stm32f4xx.h"
  2. int main()
  3. {
  4.     //Wlaczenie HSI, wpisanie wartosci 1
  5.     RCC->CR |= (uint32_t)0x00000001;
  6.     //czekanie na ustabilizowanie sie sygnalu HSI
  7.     //do momentu az flaga zostanie ustawiona
  8.     while(!(RCC->CR & (uint32_t)0x00000002));
  9.     //Zresetowanie wartosci rejestru RCC_CFGR
  10.     //automatycznie zostaje wybrany zegar systemowy jako HSI
  11.     RCC->CFGR = (uint32_t)0x00000000;
  12.     //Zresetowanie ustawien dla rejestru RCC_PLLCFGR
  13.     RCC->PLLCFGR = (uint32_t)0x24003010;
  14.    
  15.     //Wylaczenie wszystkich przerwan
  16.     RCC->CIR = 0x00000000;
  17. }

Włączenie zegara PLL:

  1. #include "stm32f4xx.h"
  2. int main()
  3. {
  4.     //Wlaczenie HSI, wpisanie wartosci 1
  5.     RCC->CR |= (uint32_t)0x00000001;
  6.     //czekanie na ustabilizowanie sie sygnalu HSI
  7.     //do momentu az flaga zostanie ustawiona
  8.     while(!(RCC->CR & (uint32_t)0x00000002));
  9.    
  10.        
  11.     //Zresetetowanie ustawien w rejestrze CR
  12.     RCC->CR = (uint32_t)0x00000083;
  13.    
  14.     //Zresetowanie wartosci rejestru RCC_CFGR
  15.     //automatycznie zostaje wybrany zegar systemowy jako HSI
  16.     RCC->CFGR = (uint32_t)0x00000000;
  17.     //Zresetowanie ustawien dla rejestru RCC_PLLCFGR
  18.     RCC->PLLCFGR = (uint32_t)0x24003010;
  19.    
  20.     //Wylaczenie wszystkich przerwan
  21.     RCC->CIR = 0x00000000;
  22.    
  23.     //Wlaczenie HSE
  24.     RCC->CR |= 0x00010000;
  25.    
  26.     //Petla oczekujaca na wlaczenie HSE
  27.     while(!(RCC->CR & 0x00020000));    
  28.            
  29.     //Ustawienie zegara PLL
  30.     //Reset wartosci PLLM
  31.     RCC->PLLCFGR &= ~0x0000003F;
  32.     //Wybranie wartosci PLLM na 8
  33.     RCC->PLLCFGR |= 0x00000008;
  34.     //Reset wartosci PLLN
  35.     RCC->PLLCFGR &= ~0x00007FC0;
  36.     //Wybranie wartosci PLLN jako 336
  37.     RCC->PLLCFGR |= 0x00005400;
  38.     //Reset wartosci PLLP
  39.     //Po resecie domyslnie ustawiona wartosc 2
  40.     RCC->PLLCFGR &= ~0x00030000;
  41.     //Wybranie zrodlo taktowania jako HSE
  42.     RCC->PLLCFGR |= 0x00400000;
  43.     //Reset PLLQ
  44.     RCC->PLLCFGR &= ~0x0F000000;
  45.     //PLLQ ustawione jako wartosc 4
  46.     RCC->PLLCFGR |= 0x040000000;
  47.     //Wlaczenie PLL
  48.     RCC->CR |= 0x01000000;
  49.     //Oczekiwanie na gotowosc PLL
  50.     while(!(RCC->CR & 0x02000000))
  51.         __NOP();
  52.                
  53.     //Ustawienie bitów w rejestrze FLASH_ACR
  54.     //Reset pierwszych trzech bitów w rejestrze
  55.     FLASH->ACR &= ~0x00000007;
  56.     //Ustawienie bitów w rejestrze ACR
  57.     //Wartosc stosunku okresu sygnalu z CPU do dostepu
  58.     //do pamieci FLASH
  59.     FLASH->ACR |= 0x00000005;
  60.     //Wybranie PLL jako zegar systemowy
  61.     RCC->CFGR |= 0x00000002;
  62.     //Oczekiwanie az PLL zostanie wlaczony jako zegar systemowy
  63.     while(!(RCC->CFGR & 0x00000008))
  64.         __NOP();
  65.    
  66.     while(1);
  67. }

Sygnały wyprowadzane na piny zewnętrzne wykonuje się tak jak w linijkach poniżej:

Główne ustawienia dla MCO 1 i 2:

  1. //Reset MCO1      
  2. RCC->CFGR &= ~0x00600000;
  3. //Przypisanie do MCO1 zegara PLL
  4. RCC->CFGR |= 0x00600000;
  5. //Reset MCO2, domyślinie wybrany SYSCLK
  6. RCC->CFGR &= ~0xC0000000;
  7. //Reset dzielnika dla MCO1
  8. RCC->CFGR &= ~0x07000000;
  9. //Ustawienie prescalera dla MCO1
  10. RCC->CFGR |= 0x06000000; //MCO1 prescaler = 4
  11. //Reset dzilnika dla MCO2
  12. RCC->CFGR &= ~0x38000000;
  13. //Ustawienie dzilnika dla MCO2
  14. RCC->CFGR |= 0x30000000;

Ustawienie pinów jako wyjściowe, na które będzie wyprowadzony zdefiniowany sygnał:

  1. //Wlaczenie zegara dla GPIOA oraz GPIOC
  2. RCC->AHB1ENR |= 0x00000005;
  3. //PA9 jako funkcja alternatywna
  4. GPIOA->MODER |= 0x00080000;
  5. //PC9 jako funkcja alternatywna
  6. GPIOC->MODER |= 0x00080000;
  7. //AF0 dla PA9
  8. GPIOA->AFR[1] &= ~0x0000000F;
  9. //AF1 dla PC9
  10. GPIOC->AFR[1] &= ~0x000000F0;
  11. //Ustawienie maksymalnej czestotliwosci na liniach
  12. GPIOA->OSPEEDR = 0xFFFFFFFF;
  13. GPIOC->OSPEEDR = 0xFFFFFFFF;

Bibliografia

[1] STM32F4 - DM00031020 - Reference manual