piątek, 11 września 2015

LPC1114 - timery CT16B0, CT16B1 oraz CT32B0 i CT32B1

Mikrokontroler LPC1114 posiada 4 timery (liczniki) ogólnego przeznaczenia, dwa timery  32 bitowe oraz kolejne dwa 16 bitowe. Oczywiście są jeszcze specjalne jak SysTick czy WDT, lecz nie będę ich w tym poście opisywał.
Na rysunku Fig. 80 przedstawiono budowę timera 32 bitowego, budowa timera 16 bitowego jest identyczna poza rozmiarami rejestrów liczących, których wielkość to 16 bitów w związku z czym mogą maksymalnie zliczyć do wartości 65535.
Fig. 80. Budowa timera

Timery 16 bitowe nazywają się CT16B0 i CT16B1,  oprócz zwykłego odliczania czasu pozwalają na generację sygnału PWM wytwarzanego przez blok timera całkowicie sprzętowo. Poza tym mogą być sterowane poprzez wejście przechwytujące (CAP) np. do bardzo precyzyjnego odmierzania czasu trwania impulsów.

Rejestry timera 16 bitowego

Wszystkie rejestry 16 bitowego timera CT16B0 przedstawia tabelka powyżej, podobne rejestry są także w przypadku timera CT16B1 (oczywiście jest inny adres bazowy - więcej w UM). Dla timera CT16B1 nazwy rejestrów są analogiczne, np. TMR16B0IR nazywa się TMR16B1IR.

Rejestr IR - flagi przerwania
Rejestr IR informuję, że nastąpiło przerwanie poprzez ustawienie bitu na konkretnej pozycji, odpowiednio zapalony:
  • bit 0 - przerwanie od rejestru porównywającego MR0
  • bit 1- przerwanie od rejestru porównywającego MR1
  • bit 2 - przerwanie od rejestru porównywającego MR2
  • bit 3 - przerwanie od rejestru porównywającego MR3
  • bit 4 - przerwanie od rejestru przechwytującego CR0
W obsłudze przerwania należy skasować flagę przerwania, ponieważ brak jej skasowania spowoduje ponowne wejście do obsługi przerwania i tak w nieskończoność, zatem mikrokontroler poświęci się tylko obsłudze tego przerwania zamiast wykonywać dalsza cześć programu. Kasując ją informujemy mikrokontroler, że przerwanie został już obsłużone i może powrócić do wykonywania innych instrukcji programu.
Kasowanie flagi następuje poprzez wpisanie 1 na odpowiednim bicie, dlatego należy mieć na uwadze że kasowanie flagi przerwania nie następuje po wpisaniu 0.
LPC_TMR16B0->IR = 2;  // kasuje flage przerwania od rejestru porywnywującego MR1
LPC_TMR16B0->IR = 8  // kasuje flage przerwania od rejestru porywnywującego MR3

Rejestr TCR - strat / stop timera
Rejestr TCR służy do startowania i zatrzymywania timera oraz resetu, czyli zerowania rejestru zliczającego TC.
  • bit 0 - wartość 0 stop timera, wartość 1 start timera
  • bit 1 - ustawienie spowoduje wyzerowanie rejestru TC przy następnym rosnącym zboczu PCLK
  • bity 31:2 - nie należy wpisywać wartości 1 !


Rejestr TC - licznik timera
Rejestr TC, czyli licznik timera jest inkrementowany za każdym cyklem PCLK z uwzględniem preskalera PR + 1. Licznik jest kontrolowany (start/stop) poprze rejestr TCR. 


Rejestr PR - preskaler
Rejestr PR jest odpowiedzialny za podział zegara, który dociera do licznika TC i odpowiada za inkrementacje licznika TC.  Po resecie jego wartość wynosi 0, zatem jak wyżej wspomniałem inkrementacja TC następuje z każdym cyklem PCLK. Dla PR=1 inkrementacja będzię następowała co 2 cykle PCLK, dla PR=2 co 3 cykle, itd.


Rejestr MCR
Rejestr MCR służy do konfiguracji rekacji uC kiedy licznik TC zliczy do wartości wpisanej w danym rejestrze MRx, np. wygenerowania przerwania kiedy wartość licznika TC będzie taka sama co wpisana do rejestru porównującego MR3.
  • bit 0 - ustwienie bitu spowoduje wyzerowanie licznika kiedy TC = MCR0
  • bit 1 - ustawienie powoduje zatrzymanie licznika kiedy TC = MCR0
  • bit 2 - ustawienie powoduje wygenerowanie przerwania kiedy licznik TC = MR0
  • bit 3 - ustwienie bitu spowoduje wyzerowanie licznika kiedy TC = MR1
  • bit 4 - ustawienie powoduje zatrzymanie licznika kiedy TC = MR1
  • bit 5 - ustawienie powoduje wygenerowanie przerwania kiedy licznik TC = MR1
  • bit 6 - ustwienie bitu spowoduje wyzerowanie licznika kiedy TC = MR2
  • bit 7 - ustawienie powoduje zatrzymanie licznika kiedy TC = MR2
  • bit 8 - ustawienie powoduje wygenerowanie przerwania kiedy licznik TC = MR2
  • bit 9 - ustwienie bitu spowoduje wyzerowanie licznika kiedy TC = MR3
  • bit 10 - ustawienie powoduje zatrzymanie licznika kiedy TC = MR3
  • bit 11 - ustawienie powoduje wygenerowanie przerwania kiedy licznik TC = MR3
  • bity 31:12 - nie należy wpisywać wartości 1 !

Rejestry porównujący MR0 - MR3
W przypadku timera 16 bitowego tak jak na powyższym obrazku można wpisać do rejestru porównującego maksymalnie liczbę 16 bitową czyli wartość 65535, natomiast przy timerze 32 bitową wartość 32 bitową.


Poniżej przykład generujący przerwanie co 20 ms,  które zmienia stan pinu P0.5 na przeciwny.

1:  #include "LPC11xx.h"  
2:    
3:  #define PRESCALER (SystemCoreClock / 1000)  
4:    
5:  // obsluga przerwania od CT16B0  
6:  void TIMER16_0_IRQHandler(void)  
7:  {  
8:       LPC_TMR16B0->IR = 2;         // kasowanie flagi przerwania od rejestru porównującego MR1  
9:       LPC_GPIO0->DATA ^= 1<<5;     // zmienia stan na przeciwny na P0.5  
10:  }  
11:    
12:  int main(void) {  
13:       LPC_GPIO0->DIR |= 1<<5;                // ustawia P0.5 jako wyjsciowy  
14:    
15:       LPC_SYSCON->SYSAHBCLKCTRL |= 1<<7;     // wlaczenie zegara dla bloku timera CT16B0  
16:    
17:       // konfiguracja CT16B0  
18:       LPC_TMR16B0->PR = PRESCALER - 1;         // PCLK / 1000 czyli na 1 ms  
19:       LPC_TMR16B0->MR1 = 20;                   // wpisanie do MR1 20 czyli 20 ms  
20:       LPC_TMR16B0->TC = 0;                    // wpisanie do licznika 0, nie jest konieczne bo po resecie i tak TC=0  
21:       LPC_TMR16B0->MCR = (1<<3) | (1<<4);     // wygeneruj perzerwanie i wyzeruj TC kiedy TC=MR1 
22:       LPC_TMR16B0->TCR = 1;                   // start timera CT16B0  
23:    
24:    while(1) {};  
25:    return 0 ;  
26:  }  
 
Należy pamiętać by włączyć taktowanie dla danego bloku timera ponieważ bez niego dany blok nie działa, w przykładzie realizuje to linia nr 15. Linie nr 20 można pominąć ponieważ po restarcie / uruchomieniu mikrokontrolera licznik TC jest zawsze wyzerowany. Zastanawiać może zmienna SystemCoreClock która jest potrzebna do wyliczenia wartości dla preskalera. Zmienna ta jest ustawiana przez funkcję SystemInit jeszcze przed wywołaniem zawartości w głównej funkcjii main. Kiedy nie piszemy programu w środowisku LPCXpresso lub nie korzystamy z szablonu generowanego prze to środowisko należy znać taktowanie uC, jeśli taktujemy częstotliwością 48 MHz zapisać można jak niżej
#define PRESCALER (48000000 / LPC_SYSCON->SYSAHBCLKDIV / 1000)

Wielu początkujący programistów szuka sposobu na realizację opóźnienia



niedziela, 23 sierpnia 2015

printf - przekierowanie w LPCXpresso

Idealnym rozwiązaniem komunikacji mikrokontrolera ze światem zewnętrznym jest funkcja printf i jej podobne. Wystarczy odpowiednio przekierować wyście / wejście na odpowiednie urządzenie i korzystać z jej dobrodziejstw. To ona będzie się "martwić" za odpowiednie wyświetlenie tekstu, liczb całkowitych jak również zmiennoprzecinkowych.
W środowisku programistycznym LPCXpresso istnej możliwość utworzenia projektu z Semihosting, wtedy funkcja printf automatycznie będzie przekazywała rezultat swojego działania do LPCXpresso i jej wynik będzie widoczny podczas debuggowania w IDE. Jednak ta możliwość nie jest tematem postu, więcej nt. można przeczytać na stronie www.lpcware.com/content/faq/lpcxpresso/semihosting

Pierwszym krokiem jaki należy wykonać jest przełączenie projektu żeby korzystał z biblioteki Redlib (nohost), wg. kroków pokazanych na rysunku poniżej


Po przełączeniu biblioteki kod podany poniżej bez problemu powinien się skompilować

#include "LPC11xx.h"

int main(void) {

    printf( "Hello World\r\n" );

    while(1)  {}

    return 0 ;
}


Drugim krokiem jest napisanie własnych funkcji __sys_write, która odpowiada za wysyłanie danych do urządzenia oraz __sys_readc odpowiedzialnej za pobieranie danych z urządzenia. Ponieważ printf zamierzamy przekierować do UART'u należy napisać także funkcje incjalizującą UART.
Ponieważ kod źródłowy inicjalizujący UART zbędnie zajmowałaby zawartość postu przykładowy projekt wraz z funkcjami znajduje się tutaj.

Oto przykładowe ciało funkcji __sys_write
int _sys_write(int iFileHandle, char *pcBuffer, int iLength)
{
    unsigned int i;

    for (i = 0; i < iLength; i++)
    {
        UART_Sendchar(pcBuffer[i]); // wysyla znak na UART
    }
    return iLength;
}

 

Oto przykładowe ciało funkcji __sys_readc
int __sys_readc(void)
{
    char c = UART_Getchar();
    return (int)c;

 

Przykład wykorzystania przekierowania:
#include "LPC11xx.h"
#include <stdio.h>
#include "uart.h"

int main(void) {
    volatile static int i = 0 ;

    UART_Init( 115200 );    // ustawia UART na predkosc 115200

    printf( "Hello World\r\n" );

    while(1) {
        printf( "I=%d\r\n", i++ );
    }
    return 0 ;
}


Jak widać w kodzie powyżej programista musi pamiętać aby  użyć funkcji Uart_Init przed korzystaniem z printf. Elastyczność funkcji printf wiąże się z rozmiarem kodu generowanego przez kompilator, dla kodu przedstawionego powyżej generuje 12336 bajtów, aby zmniejszyć  rozmiar kodu wynikowego można użyć symbolu CR_INTEGER_PRINTF przekazanego do kompilacji który spowoduje, że funkcja printf nie będzie potrafiła wyświetlić liczb zmiennoprzecinkowych (float / double). Dodając do kompilacji symbol CR_INTEGER_PRINTF kod wynikowy zmniejszył się do 7416 bajtów. Jak powiadają prawdziwi programiści embedded "float nie jest potrzebny do życia" :) zawsze można napisać program w ten sposób by uniknąć stosowania liczb zmiennoprzecinkowych.

 

środa, 31 grudnia 2014

LPC1768-MiniDK-2 jednolita nazwa interfejsu USB w sytemie Linuks

Podłączając LPC1768-MiniDK-2 do portu USB komputera w celu zaprogramowania ISP w systemie Linuks często pojawiał się w systemie jako urządzenie o rożnych nazwach. Czasami /dev/ttyUSB0, innym razem /dev/ttyUSB1, kolejnym razem kiedy wczesnej był podpięty modem LTE jako /dev/ttyUSB4.
Taki chaos nie mógł dalej panować, dlatego, cdn...

czwartek, 11 grudnia 2014

Programowanie mikrokontrolerów LPC poprzez ISP programami Flash Magic i lpc21isp

Mikrokontrolery LPC pozwalają programować wbudowaną w swoją strukturę pamięć flash poprzez In-System Programming w skrócie ISP, zwykle przez interfejs UART co na początku pozwala zaoszczędzić trochę grosza, nie jest konieczny zakup programatora / debuggera JTAG, którego koszt często przekracza 100 zł.
Zaraz po resecie albo po włączeniu zasilania mikrokontrolera sprawdzany jest stan pewnego pinu, jeżeli występuje na nim stan niski wtedy uruchamiany jest ze specjalnego obszaru pamięci nie dostępnego dla użytkownika tzw. bootloader, który to komunikuje się z urządzeniem zewnętrznym (np. program Flash Magic na komputerze PC) zwykle poprzez port UART poprzez odpowiedni protokół.
Jeśli chodzi o pin na, który należy podać przy "rozruchu" stan niski zależne jest to od mikrokontrolera, i tak dla LPC1114  jest to P0.1, dla LPC1768 P2.10. Dokładnie jest to opisane w podręczniku użytkownika, czyli tzw. User Manual (UM) zawarty też tam jest opis protokołu podczas programowania ISP - być może ktoś sam napiszę nowy program do na komputer :)
Tak na marginesie UM to podręcznik, z którym musisz się zapoznać jeśli chcesz poważnie programować dany mikrokontroler LPC, zawarto w nim opis rejestrów i poszczególnych interfejsów mikrokontrolera.
Ponieważ w Internecie można znaleźć wiele opisów programowania ISP przy użyciu programu Flash Magic w pierwszej kolejności opiszę program lpc21isp dla systemu operacyjnego Linuks, choć bez problemu można skompilować dla systemu Windows.
Program lpc21isp mimo mylącej nazwy programuje większość mikrokontrolerów LPC.
Program należy pobrać ze strony http://lpc21isp.sourceforge.net aktualnie najnowsza wersja 197 przy próbie kompilacji krzyczy następującym błędem:

/usr/bin/ld: cannot find -lc
collect2: ld returned 1 exit status
make: *** [lpc21isp] Błąd 1


Aby poprawnie skompilować należy w pliku Makefile odnaleźć następującą linie:


lpc21isp: lpc21isp.c adprog.o lpcprog.o lpcterm.o $(GLOBAL_DEP)
    $(CC) $(CDEBUG)  $(CFLAGS) -o lpc21isp lpc21isp.c adprog.o lpcprog.o lpcterm.o 


na następującą:

lpc21isp: lpc21isp.c adprog.o lpcprog.o lpcterm.o $(GLOBAL_DEP)
    $(CC) $(CDEBUG)  -o lpc21isp lpc21isp.c adprog.o lpcprog.o lpcterm.o


Następnie wydać polecenie make, które wykona skrypt kompilacji zawarty w Makefile.
Chcąc zaprogramować mikrokontroler wydaj polecenie:

lpc21isp plik_z_programem.hex /dev/ttyS0 115200 12000

do mikrokontrolera zostanie załadowany wsad zawarty w pliku plik_z_programem.hex przez port /dev/ttyS0 z prędkością 115200. Ostatnia wartość to taktowanie oscylatora podpiętego pod mikrokontroler w kHz.
Aby wgrać plik binarny należy dodać przełącznik -bin

lpc21isp -bin plik_z_programem.bin /dev/ttyS0 115200 12000

Chcąc zaprogramować mikrokontroler rodziny LPC pod systemem operacyjnym Windows zwykle używa się programu Flash Magic, choć istnieje wersja programu lpc21isp skompilowanego dla Windows. Ponieważ program Flash Magic głównie używany jest w wersji okienkowej, dlatego częściej jest wybierany niż lpc21isp.


Kroki, które należy  wykonać by zaprogramować mikrokontroler:
  1. Wybierz odpowiedni rodzaj mikrokontrolera, który zamierzasz zaprogramować
  2. Wybierz odpowiedni port COM, na którym będzie odbywać się komunikacja z mikrokontrolerem
  3. Ustaw prędkość portu (komunikacji), zacznij od 115200 jeśli będą występować błędy przy programowaniu zmniejsz prędkość
  4. Rodzaj interfejsu wybierz None (ISP)
  5. W polu Oscilator podaj częstotliwość taktowania zewnętrznego oscylatora wyrazonego MHz
  6. Zaznacz odpowiednią opcję Erase block used by Hex File. Opcja ta wymusza wyczyszczenie pamięci flash mikrokontrolera o rozmiarze takim jakim zajmuje plik HEX
Następnie wciśnij przycisk Browse po czym wskaż plik hex, którym chcesz zaprogramować mikrokontroler. Ostatnim krokiem jest wciśniecie przycisku Start co spowoduje rozpoczęcie procesu programowania mikrokontrolera.

LPC1768-MiniDK-2

Ostatnio wpadł mi w ręce moduł LPC1768-MiniDK-2 z kolorowym wyświetlaczem dotykowym 2,8". Za stosunkowo niewielką cenę (do 150 zł) można nabyć w kilku polskich sklepach internetowych LPC1768-MiniDK-2, kupując bezpośrednio u "chińczyka" jeszcze taniej. W zestawie był kabel USB, kabel ethernetowy, przejściówka mini USB na gniazdo USB (np. do podłączenia pendrive), oraz płyta z przykładami, dokumentacją oraz sterownikami. 

Pakując moduł w odpowiednią obudowę można stworzyć elegancki sterownik wszelakich zastosowań.
Moduł zbudowany jest w oparciu o mikrokontroler LPC1768 taktowany maksymalnie do 100 MHz, z 512 KB pamięci flash firmy NXP, więcej informacji o samym mikrokontrolerze znajduje się na stronie http://www.nxp.com/documents/data_sheet/LPC1769_68_67_66_65_64_63.pdf


Mikrokontroler LPC1768 należy do rodziny mikrokontrolerów ARM Cortex-M3, na każdy 1 MHz przypada 1,25 MIPS, co przy 100 MHz daje 125 MIPS, a taka prędkość bez problemu pozwala na odgrywanie plików dźwiękowych w formaci MP3. Najważniejsze cechy mikrokontrolera LPC1768 to:
  • częstotliwość pracy do 100 MHz
  • pamięć flash 512 KB
  • pamięć ram 64 KB
  • Ethernet MAC
  • kontroler USB w trybach DEVICE, HOST, OTG
  • 8 kanałowe DMA ogólnego przeznaczenia
  • 4 porty UART
  • 2 porty CAN
  • 3 porty SSP/SPI
  • 4 timery ogólnego przeznaczenia
  • 3 porty I2C, I2S
  • 8 kanałowy 12 bitowy przetwornik ADC
  • 10 bitowy DAC
  • 2 kanałowy enkoder inkrementalny
  • 6 wyjściowy PWM ogólnego przeznaczenia
  • specjalny blok PWM do zastosowania regulacji silników
  • zegar czasu rzeczywistego o ultra niskim poborze energii
Dołączony kolorowy wyświetlacz dotykowy LCD o rozmiarze 2,8" oparty jest na sterowniku SPFD5408B, który komunikuje się z "płytą główną" 16 bitowym interfejsem dzięki czemu transmisja danych do wyświetlacza przebiega szybko, natomiast dane z panela dotykowego transmitowane są poprzez interfejs SPI.
Jest także dostępna wersja wyświetlacza, gdzie wymiana danych do wyświetlacza odbywa się poprzez interfejs SPI jednak "odświeżanie" ekranu będzie o wiele wolniejsze niż na magistrali 16 bitowej.

Pokazana na zdjęciu płyta zawiera:
  1. Mikrokontroler LPC1768
  2. Gniazdo ethernet do podłączenia z siecią ethernetową
  3. Gniazdo programatora/debuggera JTAG
  4. Gniazdo mini-USB, które można wykorzystać do programowania albo port UART
  5. Gniazdo mini-USB, wykorzystanie np. jako USB HOST
  6. Gniazdo na baterię w celu podtrzymania zegara czasu rzeczywistego
  7. Kwarc zegarkowy
  8. Gniazdo do podłączenia zewnętrznego zasilacza wraz ze stabilizatorem
  9. Diody LED, w tym dwie do dowolnego wykorzystania
  10. Diody sygnalizacyjne prace portu USB
  11. Przyciski, w tym do dowolnego wykorzystywania
  12. Gniazda do podłączenia wyświetlacza
Można do płyty przylutować 2 rzędowe tzw. goldpiny o rastrze 2,54 mm dzięki czemu będzie nieskrepowany dostęp do pinów mikrokontrolera.

Ponieważ producent pomyślał o konwerterze USB-UART (oparty na scalaku CP2102) do zaprogramowania modułu nie jest konieczny programator/debugger JTAG (np. LPC-Link2), w zupełności wystarczy dołączony do zestawu kabel USB oraz aplikacja Flash Magic dla Windows, natomiast jeżeli pracujesz pod Linuksem użyj aplikacji lpc21isp.

Na dołączonej płycie znajdują się przykłady dla środowiska programistycznego Keil'a jednak ja preferuję środowisko LPCXpresso celowo przeznaczone dla mikrokontrolerów LPC. Z przeportowaniem przykładów dla LPCXpresso nie ma najmniejszych problemów. Postaram się gdzieś umieścić przykłady dla LPCXpresso w najbliższym czasie.

poniedziałek, 25 listopada 2013

LPC1114 z wyświetlaczem LCD HD44780

Wyświetlacze oparte na poczciwym kontrolerze HD44780 bez problemu współpracują z mikrokontrolerem LPC1114 pomimo, że większość wyświetlaczy pracuję na napięci 5 V, są także specjalnie produkowane na na pięcie 3,3 V jednak są zwykle drozsze niz "standardowe" 5 V.
Ponieważ mikrokontroler LPC1114 ma porty wejścia/wyjścia tolerujące 5 V bez problemu obsługuje wyświetlacze oparte na HD44780 dla 5 V.

wtorek, 24 września 2013

Interfejs SPI w LPC 1114

Mikrokontroler LPC 1114 posiada dwa sprzętowe kontrolery SPI nazwane następująco SSP0 i SSP1. Nazwa SSP to skrót od Synchronous Serial Port, czyli Szeregowy Synchroniczny Port. Posiada 8 bitowy bufor FIFO dla wysyłanych i odbieranych danych, rozmiar ramki danych można definiować od 4 do 16 bitów. Maksymalna częstotliwość taktowania zegara 25 MHz przy założeniu taktowania rdzenia 50 MHz. Należy pamiętać, że po resecie zegar taktujący kontroler jest włączony tylko dla SSP0, chcąc korzystać z SSP1 należy ustawić bit 18 w rejestrze SYSAHBCLKCTRL !

Procedura inicjalizacyjna i konfiguracyjna kontrolera SSP wygląda następująco:
1. Pierwszym etapem jest konfiguracja wyprowadzeń odpowiedzialnych za komunikację SPI, ponieważ standardowo te piny są zwykłymi portami wejścia / wyjścia. Należy ustawić odpowiednie wartości w rejestrze IOCON_LOC pamiętając, aby włączyć zegar dla tego bloku konfiguracyjnego:
    LPC_SYSCON->SYSAHBCLKCTRL |=  (0x1<<16) ; // włącza zegar taktujący dla IOCON_LOC
dla interfejsu SSP0 piny SPI:
  • P0.8 - MISIO
  • P0.9 - MOSI
  • P0.2 - SSEL sprzętowy wybór urządzenia (CS), oczywiście można nie konfigurować tego pinu, wtedy wybieranie musi być obsługiwane programowo dowolnym pinem
  • natomiast SCK, czyli zegar zależy od ustawień w rejestrze IOCON_SCK_LOC, domyślnie jest na P0.10, może być również na P0.6 i P2.11
dla interfejsu SSP1 piny SPI:
  • P2.2 - MISIO
  • P2.3 - MOSI
  • P2.0 - SSEL sprzętowy wybór urządzenia (CS), analogicznie jak SSP0 można obsługiwać programowo
  • P2.1 - SCK

2. Jak wcześniej wspomniałem należy włączyć zegar taktujący kontrolery SSP:
    LPC_SYSCON->SYSAHBCLKCTRL |=  (0x1<<11) ; // włącza zegar taktujący SSP0
    LPC_SYSCON->SYSAHBCLKCTRL |=  (0x1<<18) ; // włącza zegar taktujący SSP1
3. Następnie należy ustawić podzielnik zegara odpowiednio dla kontrolera SSP0 lub SSP1. Spójrz na rysunek



Jak widać na obrazku Fig.8 sygnał taktujący main clock dociera m.in. do dzielnika zegara SPIO PERIPHERAL CLOCK DIVIDER oraz SPI1 PERIPHERAL CLOCK DIVIDER. Odpowiednią wartość wpisuje się do rejestru SSP0CLKDIV oraz SSP1CLKDIV. Wartościami poprawnymi są wartości od 0 do 255, przy czym wpisanie 0 (po resecie przyjmuję wartość 0) spowoduje wyłączenie taktowania kontrolera SPI.

LPC_SYSCON->SSP0CLKDIV = 0x1;   // bez podzielnika zegara main clock

LPC_SYSCON->SSP0CLKDIV = 0xFF;   // 255 podzielenie main clock

LPC_SYSCON->SSP0CLKDIV = 0;   // zegar taktujący przestaje docierać do  kontrolera SSP0

4. Przed rozpoczęciem konfiguracji parametrów pracy kontrolerów SSP0/SSP1 należy wyłączyć "reset" przez odpowiednio ustawienie bitu 0 dla SPP0, ustawienie bitu 1 dla SSP1 w rejestrze PRESETCTRL:

LPC_SYSCON->PRESETCTRL |= (0x1<<0); // wylaczenie resetu SPP0

LPC_SYSCON->PRESETCTRL |= (0x1<<1); // wylaczenie resetu SPP1


5. Konfiuguracja kontrolera SSP
Rejestry odpowiedzialne za konfigurację parametrów pracy oraz przerwań związanych z kontrolerami SSP przedstawia poniższa tabelka:



Głównych ustawień dokonuje się w rejestrze SSP0CR0 lub SSP1CR0 w zależności, który kontroler SSP ustawiamy


Przedstawione w tabelce bity rejestru  SSP0CR0 / SPP1CR0 odpowiadają kolejno
  • DDS - bity 3:0 konfigurują rozmiar ramki (4-16 bit)
  • FRF - bity 5:4 format ramki - domyślnie po resecie są wyzerowane więc format transmisja SPI
  • CPOL -  bit 6 odpowiada za polaryzację zegara
  • CPHA -  bit 7 wyjście fazy zegara
  • SCR -  bity 15:8 biorą udział przy taktowaniu zegara transmisji SPI
Wzór na częstotliwość transmisji ma postać PCLK / (CPSDVSR * [SCR+1]).

Należy pamiętać, że wartość zapisywana na bitach CPSDVSR w rejestrach SSP0CPSR lub SSP1CPRS musi być liczbą parzystą i zawierać się w przedziale 2 - 254.
Czyli maksymalna częstotliwość transmisji interfejsu SSP jaką można osiągnąć w LPC1114 wyraża się PCLK / 2 dla najmniejszych wartości jakie można zapisać w CPSDVSR=2 i SCR=0, ich zwiększanie odpowiednio będzie powodować zmniejszenie częstotliwości transmisji.

6. Ostatnim etapem jest włączenie kontrolera SSP wraz z ustawieniem trybu MASTER / SLAVE zgodnie z poniższa tabelką

  • LBM - bit 0 po resecie zerowany (zwykle powinien być wyzerowany), jego ustawienie  włącza tryb Loop Back. Służy on do testowania oprogramowania, włączenie spowoduje że dane wysłane na MOSI pojawią się MISO
  • SSE - bit 1także po resecie zerowany, ustawiając go załącza się kontroler SSP0/1 a tym samy można rozpocząć transmisje
  • MS - bit 2, który po resecie ma wartość 0 co oznacza że interfejs pracuje w trybie MASTER, natomiast ustawienie bitu powoduje przejście w tryb SLAVE
Poniżej przykładowy kod inicjalizujący kontroler SSP1 wraz z odpowiednim ustawieniem pinów komunikacyjnych SPI i wysyłający tekst Test SPI
 
  1. #include "LPC11xx.h"
  2.  
  3. // rozmiar bufora FIFO
  4. #define FIFOSIZE 8
  5.  
  6. // definicje na potrzeby badnia statusu SSP
  7. #define SSPSR_TFE (0x1<<0)
  8. #define SSPSR_TNF (0x1<<1)
  9. #define SSPSR_RNE (0x1<<2)
  10. #define SSPSR_RFF (0x1<<3)
  11. #define SSPSR_BSY (0x1<<4)
  12.  
  13. // funkcja wysylajaca
  14. void Send_SSP(uint8_t data) {
  15. // czeka dopoki kontroler jest zajety i kolejko FIFO TX nie jest pelna
  16. while ( (LPC_SSP1->SR & (SSPSR_TNF|SSPSR_BSY)) != SSPSR_TNF );
  17. LPC_SSP1->DR = data; // wysyla dane przez SSP1
  18. }
  19.  
  20. // funkcja odbierajaca
  21. void Recive_SSP(uint8_t *data) {
  22. while ( LPC_SSP0->SR & (1<<2) ) { // dopoki bufor odbiorczy nie jest pusty
  23. *data = LPC_SSP0->DR; // pobranie bajtu
  24. data++;
  25. }
  26. }
  27.  
  28. int main(void) {
  29.  
  30. uint8_t i, tmp;
  31. uint8_t bufor[]="Test SPI" ;
  32.  
  33. // konfiguracja pinow odpowiedzialnych za komunikacjie SPI
  34. LPC_SYSCON->SYSAHBCLKCTRL |= 1<<16; //wlaczenie zegara dla bloku IOCON_LOC //
  35. LPC_IOCON->PIO2_0 |= 0x2; // P2.0 SEL1 - sprzetowy CS dla SSP1
  36. LPC_IOCON->PIO2_1 |= 0x2; // P2.1 SCK - zegar
  37. LPC_IOCON->PIO2_2 |= 0x2; // P2.2 MISO dla SSP1
  38. LPC_IOCON->PIO2_3 |= 0x2; // P2.3 MOSI dla SSP1
  39.  
  40. LPC_SYSCON->SYSAHBCLKCTRL |= 1<<18; // wlacza zegar taktujacy SSP1
  41. LPC_SYSCON->SSP1CLKDIV = 0x1; // bez podzielnika zegara, do SSP1 dociera main clock
  42. LPC_SYSCON->PRESETCTRL |= 1<<2; // wylaczenie resetu SSP1
  43. LPC_SSP1->CR0 = 0x0507; // dana 8 bitowa, ramka SPI, CPOL=0, CPHA=0, SCR=5
  44. LPC_SSP1->CPSR = 2; // CPSDVSR=2, zatem taktowanie SSP0 jest rowne 4 MHz bo PCLK / (CPSDVSR*(SCR+1). 48 / (2*(5+1) = 4
  45.  
  46. for ( i = 0; i < FIFOSIZE; i++ )
  47. tmp = LPC_SSP0->DR; // czytanie FIFO, a tym samym wyczyszczenie bufora FIFO ze smieci
  48.  
  49. LPC_SSP1->CR1 = (1<<1) ; // wlaczenie kontolera SSP/SPI w trybie MASTER
  50.  
  51.  
  52. while(1)
  53. {
  54. i = 0;
  55.  
  56. while( tmp = bufor[i++] )
  57. Send_SSP( tmp ); // wysyla kolejny znak
  58. }
  59.  
  60. return 0 ;
  61. }