Artykuł jest częścią cyklu:
Kurs ARM: Spis treści
Ta część kursu i następne będą już o samym
LPC1114 i o jego programowaniu. Od czasu do czasu podłączymy jakieś peryferia, bo przecież ten mikrokontroler musi czymś sterować, a opisywanie peryferii
LPC1114 na sucho bez kodu większego pożytku nie przyniesie.
LPC1114 niczym puzzle
Mikrokontroler składa się z bloków niczym układanka z puzzli , które spełniają określone funkcje. Przyjrzyjmy się schematowi blokowemu.
Z grubsza widać co znajduje się w mikrokontrolerze, jest rdzeń Cortex-M0, pamięci FLASH, RAM i ROM, timery, interfejsy szeregowe, porty, przetwornik ADC... Co niektórych, niepokój mogą wzbudzić dwa bloki -
AHB-LITE BUS i
AHB TO APB BRIDGE oraz nieoznaczona na tym schemacie magistrala
APB (lub
PPB).
AHB to szybka magistrala zaprojektowana pod kątem dużej przepustowości , która łączy rdzeń z pamięciami i szybkimi peryferiami.
Peryferia które nie potrzebują dużej przepustowości transferu danych są dołączone do magistrali
APB. Magistrala
APB jest mniej skomplikowana od magistrali
AHB kosztem szybkości transferu danych. Obie magistrale połączone są mostem
AHB TO APB BRIDGE i każda może być taktowana zegarem o różnej prędkości. Rolą mostu oprócz połączenia magistral
AHB i
APB jest uaktywnienie odpowiedniego peryferia w zależności od adresu oraz wstrzymanie magistrali
AHB na czas potrzebny do dokonania transakcji na
APB.
W przypadku tego procesora możemy regulować częstotliwość taktowania tylko magistrali
AHB,
APB pracuje z tą samą częstotliwością. Istnieją procesory, które mają regulowaną częstotliwości taktowania także magistrali
APB. Regulowana częstotliwość zegara również pozwala na redukcję poboru energii przez procesor. Słowo
LITE w nazwie
AHB-LITE oznacz, że do magistrali może być przyłączony tylko jeden master, w tym przypadku rdzeń jest takim masterem. W praktyce podczas programowania procesora nie będziemy wiedzieć o ich istnieniu poza konfiguracją wspomnianego sygnału taktującego te magistrale.
Pierwsze takty…
Po podaniu zasilania, mikroprocesor wykonuje kilka czynności zanim uruchomi główny program. Na tym rysunku najlepiej to widać:
Z powyższego rysunku widać, że warunkiem poprawnego startu
LPC1114 jest osiągnięcie odpowiedniego poziomu napięcia przez źródło zasilania. Jeśli tylko zasilanie przekroczy próg 1.8V, w ciągu 80us zostaje uruchomiony wewnętrzny oscylator 12MHz , z którego będzie taktowany procesor. Po kolejnych około 100us zostaje zwolniony wewnętrzny sygnał RESET i mikroprocesor przechodzi do wykonywania programu bootloadera. Bootloader na uruchomienie głównego programu potrzebuje 55us.
W czasie tych 55us sprawdza kilka warunków, które muszą być spełnione, aby móc uruchomić główny program, oraz wstępnie konfiguruje procesor. Projektując urządzenie należy pamiętać o tym opóźnieniu, i wziąć pod uwagę, że przez kilkaset mikrosekund wyjścia są wejściami.
Co dalej?
Procesor po wstępnym skonfigurowaniu przez bootloader zaczyna wykonywać program użytkownika zawarty w pamięci FLASH. Na początku pamięci FLASH znajduje się tablica wektorów. Wektor to nic innego jak adres wskazujący na jakąś komórkę w pamięci. Prawie wszystkie wektory to adresy funkcji obsługujących przerwania lub wyjątki. Pierwszy wektor w tej tablicy znajdujący się pod adresem 0x00000000 jest adresem wierzchołka stosu i podczas resetu jest ładowany do głównego wskaźnika stosu (są dwa). Drugi wektor spod adresu 0x00000004 ( każdy wektor jest 32 bitowy więc zajmuje 4 bajty) zawiera adres funkcji, od której procesor zaczyna wykonywanie programu i nie chodzi tutaj o funkcję main(). ARM traktuje reset jako wyjątek.
Przerwania i wyjątki.
Między przerwaniami i wyjątkami wielkiej różnicy nie ma, gdyż przerwania też zaliczają się do wyjątków. Wyjątki pochodzą od rdzenia, a przerwania od peryferii. Niektórych wyjątków nie da się wyłączyć i nie są konfigurowalne. Więcej o przerwaniach w kolejnych częściach.
Inicjalizacja
Inicjalizacja mikrokontrolera jest pierwszą czynnością jaką powinien wykonać program. Nie jest to czynność standardowa i zależy od tego z jakich funkcji mikrokontrolera będzie korzystało urządzenie. W niektórych mikrokontrolerach inicjalizację przeprowadza się już na etapie programowania za pomocą tak zwanych FUSE bitów np. w AVR.
W przypadku LPC11xx czegoś takiego nie ma! Wszystko możemy skonfigurować z poziomu programu i w każdej chwili zmienić, dzięki czemu nie ma możliwości zablokowania sobie mikrokontrolera, jak to zdarza się czasami np. w AVR.
Mikrokontroler składa się z bloków, które spełniają określone funkcje i każdy taki blok ma swoją procedurę inicjalizacyjną. Kolejność inicjalizacji w przypadku jednych bloków jest ważna, a w przypadku innych dowolna. Wynika to głównie z zależności pomiędzy blokami i układu, w którym pracuje mikrokontroler, np. przed inicjalizacją interfejsów szeregowych trzeba skonfigurować blok generacji sygnałów zegarowych
CGU i porty
GPIO.
Teoretycznie inicjalizację mikrokontrolera powinno zacząć się od inicjalizacji
watchdoga, jeśli ma być używany w programie, ale tak się składa, że watchdog również korzysta z
CGU więc na inicjalizacji tego bloku się teraz skupimy.
CGU – Clock Generation Unit
Blok generacji sygnału zegarowego odpowiedzialny jest za sterowanie źródłami tego sygnału oraz za rozdzielenie go do poszczególnych peryferii. Selektywne sterowanie sygnałem zegarowym doprowadzanym do peryferii pozwala na obniżenie poboru mocy przez mikrokontroler.
Rejestry do sterownia blokiem
CGU znajdują się w bloku rejestrów o nazwie
System Control, który znajduje się w przestrzeni peryferii, czyli dołączony jest do opisywanej wcześniej magistrali
APB. W bibliotece
CMSIS, wskaźnik na blok
System Control ma nazwę
LPC_SYSCON i za pomocą tego wskaźnika będziemy odwoływać się do jego rejestrów.
Przyład:
LPC_SYSCON->PDRUNCFG &= ~SYSOSC_PD; // Włączenie oscylatora kwarcowego
CGU może być taktowany z trzech źródeł sygnału zegarowego:
- IRC oscillator - wewnętrzny oscylator RC o częstotliwości 12MHz
- System oscillator – oscylator kwarcowy do którego można podłączyć rezonatory kwarcowe od 1MHz do 25MHz
- Watchdog oscillator – wewnętrzny oscylator RC, którego częstotliwość można regulować w zakresie od 7,8kHz do 1,7MHz.
Jako czwarte źródło sygnału zegarowego można uznać pętlę fazową
PLL. Pętla
PLL do działania wymaga referencyjnego sygnału zegarowego (minimum 10MHz), którym może być
IRC oscillator lub
System oscillator. Zadaniem
PLL jest zwielokrotnienie referencyjnego sygnału zegarowego.
Konfigurując
PLL należy pamiętać, aby częstotliwość generowanego sygnału zegarowego nie przekroczyła 50MHz.
Rejestry związane z konfiguracją
CGU
SYSPLLCTRL – konfiguracja pętli
PLL
SYSPLLSTAT – status pracy pętli
PLL
SYSOSCCTRL – konfiguracja oscylatora
systemowego
WDTOSCCTRL – konfiguracja oscylatora
watchdoga
IRCCTRL – dostrajanie
wewnętrznego oscylatora 12MHz
SYSPLLCLKSEL – selekcja źródła zegara dla
PLL
SYSPLLCLKUEN – potwierdzenie zmiany źródła zegara dla
PLL
MAINCLKSEL – selekcja źródła
zegara systemowego
MAINCLKUEN – potwierdzenie zmiany źródła
zegara systemowego
SYSAHBCLKDIV – dzielnik zegara taktującego magistralę
AHB
SYSAHBCLKCTRL – włączanie taktowania
peryferiów
SPI0CLKDIV – dzielnik sygnału taktującego interfejs szeregowy
SPI0
SPI1CLKDIV – dzielnik sygnału taktującego interfejs szeregowy
SPI1
UARTDIVCLK – dzielnik sygnału taktującego interfejs szeregowy
UART
WDTCLKSEL – wybór źródła sygnału taktującego
watchdoga
WDTCLKUEN – potwierdzenie zmiany źródła sygnału taktującego
watchdoga
WDTCLKDIV – dzielnik sygnału taktującego
watchdoga
CLKOUTCLKSEL – selekcja źródła sygnału taktującego wyjście
CLKOUT
CLKOUTUEN – potwierdzenie zmiany źródła sygnału taktującego wyjście
CLKOUT
CLKOUTCLKDIV – dzielnik sygnału taktującego wyjście
CLKOUT
Jest to całkiem pokaźna grupa rejestrów sterująca tylko sygnałem zegarowym, ale nie należy się przejmować tą ilością, ponieważ niektóre rejestry zawierają jeden lub kilka bitów, a poza tym, zazwyczaj używa się ich tylko podczas inicjalizacji procesora i często nie wszystkie są używane.
OK, teraz do sprawy podejdziemy bardziej praktycznie, bo opis rejestrów jest w
User Manualu procesora więc nie ma sensu go przepisywać. Postawimy sobie dwa zadania. Obydwa zadania będą dotyczyć inicjalizacji zegara systemowego w procesorze. Celem pierwszego zadania będzie wygenerowanie na porcie P0.2 przebiegu o częstotliwości 1Hz na razie bez użycia pętli
PLL, ale z wykorzystaniem oscylatora systemowego.
Krok po kroku…
Po włączeniu zasilania procesor jest taktowany z wewnętrznego oscylatora 12MHz. Musimy przełączyć procesor na oscylator systemowy, ale przed przełączeniem trzeba ten oscylator włączyć. Oscylator włączamy poprzez wyzerowanie bitu
SYSOSC_PD (5 bit – 0x20) w rejestrze
PDRUNCFG.
LPC_SYSCON->PDRUNCFG &= ~SYSOSC_PD;
Po włączeniu oscylatora trzeba chwilę poczekać w celu ustabilizowania się jego pracy. Można to zrealizować poprzez pętle odczytującą jakiś rejestr.
Zostanie odczytany 1000 razy rejestr
PDRUNCFG
for( int i = 0; i < 1000; i++)
{
LPC_SYSCON->PDRUNCFG;
}
Zegar systemowy nie może być dołączony bezpośrednio do oscylatora systemowego. Po drodze jest jeszcze jeden multiplekser, którego zadaniem jest przełączanie źródła zegara referencyjnego dla
PLL między wewnętrznym oscylatorem
IRC i oscylatorem systemowym. Do wyjścia tego multipleksera można dołączyć również zegar systemowy. Tym sposobem mamy dwie możliwości dołączenia wewnętrznego oscylatora
IRC do zegara systemowego.
Przełączenie tego multipleksera na oscylator systemowy przebiega dwuetapowo. W pierwszej kolejności należy przełączyć multiplekser na oscylator systemowy, a w drugiej potwierdzić tą operację.
Przełączenie na oscylator systemowy realizujemy poprzez ustawienie rejestru
SYSPLLCLKSEL na 1. W dołączonym do projektów pliku syscon.h znajdują się deklaracje bitów rejestrów należących do bloku
System Control. Deklaracji
SYSPLLCLKSEL_SYSOSC przypisania jest wartość 1.
LPC_SYSCON->SYSPLLCLKSEL = SYSPLLCLKSEL_SYSOSC;
Potwierdzenie przełączenia wymaga przestawienia bitu
ENA (bit 0 => 0x01) w rejestrze
SYSPLLCLKUEN z wartości 0 na 1. Dla pewności bit ten należy wcześniej wyzerować
LPC_SYSCON->SYSPLLCLKUEN = 0;
LPC_SYSCON->SYSPLLCLKUEN = SYSPLLCLKUEN_ENA;
Teraz możemy się przełączyć na oscylator systemowy ( w tym przypadku 10MHz) i wyłączyć wewnętrzny oscylator.
Przełączenie źródła taktowania na zewnętrzny oscylator również przebiega dwuetapowo. W pierwszej kolejności należy ustawić rejestr
MAINCLKSEL na 1
LPC_SYSCON->MAINCLKSEL = MAINCLKSEL_PLLIN;
i potwierdzić zmianą bitu
ENA (bit 0 => 0x01) w rejestrze
MAINCLKUEN z 0 na 1
LPC_SYSCON->MAINCLKUEN = 0;
LPC_SYSCON->MAINCLKUEN = MAINCLKUEN_ENA;
Teraz nasz procesor pracuje już z oscylatora systemowego i możemy wyłączyć wewnętrzny oscylator. Wyłączamy go w rejestrze
PDRUNCFG poprzez ustawienie bitu
IRC_PD (bit 1 => 0x02)
LPC_SYSCON->PDRUNCFG |= IRC_PD;
Teoretycznie na tym kończy się te zadanie, ale dla sprawdzenia wygenerujemy 1Hz na porcie P0.2. Kod programu realizujący to sprawdzenie wykracza poza tę część kursu więc pozostanie bez opisu.
Cały kod realizujący to zadanie:
#include "LPC11xx.h"
#include "syscon.h"
//***************************************************************************
// Funkcja inicjalizująca procesor
//***************************************************************************
void
LPC_Init( void )
{
// Włączenie oscylatora systemowego
LPC_SYSCON->PDRUNCFG &= ~PDRUNCFG_SYSOSC_PD;
// Zwłoka na ustabilizowanie oscylatora poprzez wielokrotny odczyt rejestru
for( int i = 0; i < 1000; i++)
{
LPC_SYSCON->PDRUNCFG;
}
// Przełączenie źródła sygnału taktującego PLL na oscylator systemowy
LPC_SYSCON->SYSPLLCLKSEL = SYSPLLCLKSEL_SYSOSC;
// Potwierdzenie przełączenia źródła taktowania
LPC_SYSCON->SYSPLLCLKUEN = 0;
LPC_SYSCON->SYSPLLCLKUEN = SYSPLLCLKUEN_ENA;
// Przełączenie źródła zegara systemowego
LPC_SYSCON->MAINCLKSEL = MAINCLKSEL_PLLIN;
// Potwierdzenie przełączenia źródła taktowania
LPC_SYSCON->MAINCLKUEN = 0;
LPC_SYSCON->MAINCLKUEN = MAINCLKUEN_ENA;
// Wyłączenie wewnętrznego oscylatora
LPC_SYSCON->PDRUNCFG |= PDRUNCFG_IRC_PD;
//~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-//
// Dodatkowe inicjalizacje nie związane z zadaniem //
//~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-//
#define LED_PIN (1<<2)
// Włączenie taktowania portów i bloku konfiguracji portów
LPC_SYSCON->SYSAHBCLKCTRL |= AHBCLKCTRL_IOCON | AHBCLKCTRL_GPIO;
// Port P0.2 jako wyjście
LPC_GPIO0->DIR |= LED_PIN;
// Konfiguracja timera systemowego SysTick
// Przerwanie co 500ms (dla 10MHz)
SysTick->LOAD = 5000000UL;
// Włączenie timera
SysTick->CTRL = 7;
// Odblokowanie przerwań od timera SysTick
NVIC_EnableIRQ(SysTick_IRQn);
}
//***************************************************************************
// Funkcja obsługi przerwania od timera SysTick
//***************************************************************************
void
SysTick_Handler( void )
{
// Zmiana stanu portu P0.2 na przeciwny
LPC_GPIO0->DATA ^= LED_PIN;
}
//***************************************************************************
// Funkcja pętli głównej
//***************************************************************************
int
main( void )
{
LPC_Init();
while( 1 )
{
// Kod pętli głównej
}
}
Plik z projektem zadania:
projekt_zad1.zip
Zadanie drugie będzie rozszerzeniem pierwszego zadania. W tym zadaniu skonfigurujemy PLL na 50MHz i przełączymy procesor na te źródło sygnału zegarowego.
Różnica w stosunku do pierwszego zadania polega na tym, że przed dołączeniem zegara systemowego należ PLL skonfigurować, włączyć i poczekać na synchronizację pętli. Dodatkowo należy ustawić czas dostępu do pamięci FLASH, gdyż pamięć ta może być odczytywana z maksymalną prędkością 20MHz. Zanim to wszystko zrobimy, kilka słów o samej pętli PLL.
Pętla PLL
Pętla PLL jest generatorem VCO (generator sterowany napięciem), którego częstotliwość może zmieniać się w granicach od 156MHz do 320MHz. Częstotliwość ta za pomocą dzielnika jest zmniejszana od 2 do 16 razy i dopiero wtedy może być wykorzystana jako zegar systemowy, dla przykładu, gdy częstotliwość generatora wynosi 200MHz musi ona zostać podzielona przez co najmniej 4 co da nam w efekcie 50MHz, czyli maksimum dla tego procesora.
No dobrze, ale jak ustawić częstotliwość generatora właśnie na te przykładowe 200MHz? Bezpośrednio nie mamy na to wpływu, generator przestrajany jest napięciem, a my nie mamy możliwości regulacji tego napięcia. To pętla PLL sama ustala to napięcie. Napięcie regulowane jest w układzie, który porównuje fazy dwóch sygnałów zegarowych. Jeden sygnał zegarowy jest sygnałem referencyjnym, który musi być bardzo stabilny i mieścić się w pewnym zakresie częstotliwości. Dla tego procesora ten zakres wynosi od 10MHz do 25MHz.
Drugi sygnał zegarowy jest zwrotnym sygnałem pochodzącym z tego generatora podzielonym przez dzielnik, czyli dokładnie ten sam, który wykorzystywany jest do taktowania procesora. Jeśli fazy tych dwóch sygnałów nie zgadzają się ze sobą, pętla PLL reguluje napięcie powodując zmiany częstotliwości generatora, a tym samym częstotliwości i fazy sygnału zwrotnego.
Gdy częstotliwości i fazy sygnałów zegarowych zrównają się, wtedy pętla PLL jest zsynchronizowana i ustawiany jest bit
LOCK (bit 0) w rejestrze statusu pętli PLL -
SYSPLLSTAT . Dopiero po zsynchronizowaniu się pętli można z niej taktować procesor.
Zadanie 2.
W pierwszej kolejności należy skonfigurować pętlę PLL w rejestrze
SYSPLLCTRL. Cała konfiguracja polega na odpowiednim ustawieniu dwóch dzielników. Należy zacząć od obliczenia dzielnika
M, czyli tego, który dzieli zegar z którego taktowany jest procesor, a w drugiej kolejności dobrać wartość dzielnika P tak, aby częstotliwość VCO nie wychodziła poza dozwolony zakres. Dzielnik
M może dzielić przez wartości z zakresu od 1 do 32, a dzielnik P przez 2, 4, 8 lub 16. Wpisywane wartości do rejestru
SYSPLLCTRL nie odpowiadają rzeczywistym wartościom, z tego powodu w pliku
syscon.h dostępne są deklaracje, które ułatwiają konfigurację rejestru
SYSPLLCTRL. Dla dzielnika
M należy posługiwać się deklaracjami
PLL_M_DIV_x, gdzie
x przyjmuje wartości od 1 do 32, a dla dzielnika P deklaracjami
PLL_P_DIV_y, gdzie
y przyjmuje jedną z czterech wartości - 2, 4, 8, 16 (
PLL_M_DIV_5, PLL_P_DIV_4).
Wartości dzielników zaczynamy od ustalenia dzielnika M. Wartość dzielnika M ustalamy poprzez podzielnie częstotliwości jaką chcemy taktować procesor (np. 50MHz) przez częstotliwość referencyjną dostarczaną do pętli PLL (np kwarc 10MHz).
Z powyższego wyliczenia wynika, że do dzielnika
M należy wpisać
PLL_M_DIV_5. Nie można wpisać bezpośrednio liczby 5, ponieważ rzeczywistą liczbą wpisywaną do tego dzielnika jest wartość
x-1, czyli 4.
Ustalając wartość dzielnika M należy pamiętać o tym, że częstotliwość taktowania procesora może być tylko wielokrotnością częstotliwości referencyjnej oraz, że częstotliwość taktowania procesora nie może przekraczać maksymalnej częstotliwości z jaką może pracować procesor deklarowanej przez producenta (50MHz).
Wartość dzielnika
P ustalamy poprzez znalezienie takiej liczby z czterech możliwych ( 2, 4, 8, 16), która po pomnożeniu przez oczekiwaną częstotliwość pracy procesora ( np. 50MHz) da nam wartość z przedziału od 156MHz do 320MHz. Na przykład dla częstotliwości 50MHz jedyną taką liczba jest 4, więc do dzielnika P należy wpisać
PLL_P_DIV_4. W rzeczywistości do dzielnika
P wpisywane są liczby z zakresu od 0 do 3. Jeśli zdarzy się sytuacja, że żadne wartości dzielników nie pozwalają na uzyskanie oczekiwanej częstotliwości, należ spróbować dobrać inny rezonator kwarcowy.
Wartości obu dzielników wpisujemy do rejestru
SYSPLLCTRL:
LPC_SYSCON->SYSPLLCTRL = PLL_M_DIV_5 | PLL_P_DIV_4;
Następnie uruchamiamy pętlę PLL w rejestrze
PDRUNCFG poprzez wyzerowanie bitu
SYSPLL_PD (7 bit = 0x80)
LPC_SYSCON->PDRUNCFG &= ~SYSPLL_PD;
i czekamy aż się zsynchronizuje co będzie zasygnalizowane ustawieniem bitu LOCK (bit 0) w rejestrze SYSPLLSTAT
while (!(LPC_SYSCON->SYSPLLSTAT & SYSPLLSTAT_LOCK));
Po zsynchronizowaniu się pętli nie można jeszcze przełączyć źródła taktowania procesora, trzeba zmienić czas dostępu do pamięci FLASH. Czas dostępu zmieniamy poprzez konfigurację bitów FLASHTIM[1:0] w rejestrze LPC_FLASHCFG w zależności od częstotliwości zegara systemowego według poniższej zasady:
[00] - SYSCLK do 20MHz (1 cykl zegarowy)
[01] – SYSCLK do 40MHz (2 cykle zegarowe)
[10] – SYSCLK powyżej 40MHz (3 cykle zegarowe)
Uwaga!
Pozostałe bity w rejestrze LPC_FLASHCFG mimo, że są niewykorzystane nie mogą być zmieniane, tzn. trzeba je zapisać z powrotem bez zmian.
Deklaracje i definicje dotyczące rejestru FLASHCFG znajdują się pliku flashcon.h
Do konfiguracji czasu dostępu należy używać poniższych deklaracji:
#define FLASHTIM_20MHz 0
#define FLASHTIM_40MHz 1
#define FLASHTIM_50MHz 2
Rejestr LPC_FLASHCFG należy do bloku kontrolera pamięci FLASH i ze względu, że jest jedynym rejestrem z tej grupy dostęp do niego jest bezpośredni.
LPC_FLASHCFG = (LPC_FLASHCFG & ~FLASHTIM_MASK) | FLASHTIM_50MHz; // >40MHz
Dopiero po skonfigurowaniu czasu dostępu do pamięci FLASH można przełączyć źródło taktowania procesora na pętlę PLL ustawiając rejestr
MAINCLKSEL i potwierdzając w rejestrze
MAINCLKUEN.
LPC_SYSCON->MAINCLKSEL = MAINCLKSEL_PLLOUT;
LPC_SYSCON->MAINCLKUEN = 0;
LPC_SYSCON->MAINCLKUEN = MAINCLKUEN_ENA;
Cały kod inicjalizacji pętli PLL i czasu dostępu do pamięci FLASH.
#include "LPC11xx.h"
#include "syscon.h"
#include "flashcon.h"
//***************************************************************************
// Funkcja inicjalizacja procesora
//***************************************************************************
void
LPC_Init( void )
{
// Włączenie oscylatora systemowego
LPC_SYSCON->PDRUNCFG &= ~PDRUNCFG_SYSOSC_PD;
// Zwłoka na ustabilizowanie oscylatora poprzez wieleokrotny
// odczyt rejestru
for( int i = 0; i < 1000; i++)
{
LPC_SYSCON->PDRUNCFG;
}
// Przełaczenie źródła sygnału taktującego PLL na zew. oscylator
LPC_SYSCON->SYSPLLCLKSEL = SYSPLLCLKSEL_SYSOSC;
// Potwierdzenie przełączenia źródła taktowania poprzez wygenerowania
// zmiany bitu z 0 na 1
LPC_SYSCON->SYSPLLCLKUEN = 0;
LPC_SYSCON->SYSPLLCLKUEN = SYSPLLCLKUEN_ENA;
// Konfiguracja dzielników PLL
LPC_SYSCON->SYSPLLCTRL = PLL_M_DIV_5 | PLL_P_DIV_4;
// Uruchominie pętli PLL
LPC_SYSCON->PDRUNCFG &= ~PDRUNCFG_SYSPLL_PD;
// Oczekiwanie na synchronizacje pętli PLL
while(!(LPC_SYSCON->SYSPLLSTAT & SYSPLLSTAT_LOCK));
// Konfiguracja dostępu do pamięci FLASH (3 cykle)
LPC_FLASHCFG = (LPC_FLASHCFG & ~FLASHTIM_MASK) |FLASHTIM_50MHz;
// Przełączenie źródła zegara systemowego na PLL
LPC_SYSCON->MAINCLKSEL = MAINCLKSEL_PLLOUT;
// Potwierdzenie przełączenia źródła taktowania poprzez wygenerowania
// zmiany bitu z 0 na 1
LPC_SYSCON->MAINCLKUEN = 0;
LPC_SYSCON->MAINCLKUEN = MAINCLKUEN_ENA;
// Wyłączenie wewnętrznego oscylatora
LPC_SYSCON->PDRUNCFG |= PDRUNCFG_IRC_PD;
//~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-//
// Dodatkowe inicjalizacje nie związane z zadaniem //
//~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-//
#define LED_PIN (1<<2)
// Włączenie taktowania portów i bloku konfiguracji portów
LPC_SYSCON->SYSAHBCLKCTRL |= AHBCLKCTRL_IOCON | AHBCLKCTRL_GPIO;
// Port P0.2 jako wyjście
LPC_GPIO0->DIR |= LED_PIN;
// Konfiguracja timera systemowego SysTick
// Przerwanie co 250ms (dla PLL = 50MHz)
SysTick->LOAD = 12500000UL;
// Włączenie timera
SysTick->CTRL = 7;
// Odblokowanie przerwań od timera SysTick
NVIC_EnableIRQ(SysTick_IRQn);
}
//**************************************************************************
// Funkcja obsługi przerwania od timera SysTick
//**************************************************************************
void
SysTick_Handler( void )
{
static int cnt;
// Zmiana stanu portu P0.2 na przeciwny co 500ms
LPC_GPIO0->MASKED_ACCESS[LED_PIN] = ++cnt << 1;
}
//**************************************************************************
// Funkcja pętli głównej
//**************************************************************************
int
main( void )
{
LPC_Init();
while( 1 )
{
// Kod pętli głównej
}
}
Uwaga.
Pliki w projektach ewoluują więc rada taka, aby przy okazji każdej następnej części kursu nie posługiwać się projektami ze starszych części kursu.
Ćwiczenia:
1.
Mając dołączony kwarc 10MHz skonfiguruj częstotliwość taktowania procesora na 30MHz
2.
Skonfiguruj procesor do pracy na częstotliwości bliskiej 43MHz
3.
Skonfiguruj procesor do pray z oscylatora watchdoga ustawionego na 1,7kHz
Możecie przysyłać całe projekty z rozwiązanymi ćwiczeniami: adres email znajdziesz tutaj
Poprawne i najlepiej opracowane umieścimy na blogu.
Kurs ARM: Spis treści