piątek, 4 grudnia 2015

[10] STM32 M3 - Nucleo - F103RB - SPI opis oraz sposób programowania

Tym razem chciałbym zaprezentować sposób obsługi urządzeń za pomocą interfejsu SPI.

Wstęp


SPI (ang. Serial Peripheral Interface) jest to interfejs szeregowy stosowany do komunikacji pomiędzy różnymi układami. Obecnie jest jednym z częściej wykorzystywanych metod komunikacji pomiędzy urządzeniami.

Komunikacja odbywa się za pomocą trzech głównych linii:

  • MOSI (ang. Master Output Slave Input) - dane wysyłane z urządzenia sterującego (przeważnie mikrokontroler) do urządzenia peryferyjnego pod układ główny (np. czujnik wyświetlacz).
  • MISO (ang. Master Input Slave Output) - odwrotne działanie niż MOSI, z układu peryferyjnego do głównego,
  • SCKL, CLK, SPC (ang. Serial Clock) - jest to sygnał taktujący.
Dodatkowo często wykorzystywana jest linia SS, pozwala ona na wybranie układu podrzędnego, lub na wykonanie adresacji układów.

W czasie przesyłania danych jeden układ jest nadrzędny (master), drugi natomiast w tym czasie jest układem podrzędnym.

Rys. 1. Podłączenie modułów SPI [wikipedia]



Częstotliwość sygnału taktującego może być zmieniana w trakcie transmisji, nie musi być ona ustawiona na sztywno. Spowodowane jest to tym, że do synchronizacji operacji wykorzystuje się zbocza sygnału. Dodatkowo do zalet tego interfejsu można dodać brak adresów urządzeń, dzięki czemu komunikacja jest bardziej uproszczona. Kolejną zaletą jest jednokierunkowość wykorzystywanych linii. To także wpływa na minimalizację całego układu oraz jego uproszczenie.

Opis układu wbudowanego


W opisywanym mikrokontrolerze dostępne są dwa układy SPI. Mają one możliwość pracy w trybach 8 bądź 16 bitowych, dodatkowo każde z nich może być zarówno układem podrzędnym jak i nadrzędnym. Prędkość transmisji danych wynosi 18Mbit/s.Oba te układy mogą współpracować z DMA.

Maksymalna częstotliwość linii SCK wynosi 18 MHz. SPI taktowane jest poprzez APB2 (64 MHz) w związku z czym należy stosować odpowiednie dzielniki.

Dodatkowo każdy z SPI posiada dwa układy do wyznaczania sum kontrolnych. CRC. Jeden z nich obsługuje dane wysyłane, drugi odbierane.

Opisywany mikrokontroler posiada wyrowadzone piny do SPI na następujących wyjściach:

  • SPI1:
    • NSS(CS) - PA4,
    • MISO - PA6,
    • MOSI - PA7,
    • SCK - PA5,
  • SPI2:
    • NSS(CS) - PB12,
    • MISO - PB14,
    • MOSI - PB15,
    • SCK - PB13,
Układ SPI1 można przemapować na następujące wyprowadzenia:
  • SPI1:
    • NSS(CS) - PA15
    • MISO - PB4,
    • MOSI - PB5,
    • SCK - PB3,
Linia nSS pozwala na wybranie odpowiedniego układu podrzędnego.

Programowanie 


Jednym z podstawowych elementów jest określenie w jaki sposób działać będzie linia SCK. Pierwszym parametrem jest wybór stanu jaki wystąpi na linii w momencie nie przesyłania danych. Do wyboru są dwie możliwości wysoki oraz niski, wybiera się je poprzez wybranie odpowiedniej deklaracji. Będzie to odpowiednio SPI_CPOL_HIGH (stan 1) oraz SPI_CPOL_LOW (stan 0).

Kolejnym elementem jest wybranie kiedy kolejne bity mają być obsługiwane tzn, na pierwszym czy na drugim zboczu. Będą to odpowiednio deklaracje SPI_CPHA_1Edge (stan 0) oraz SPI_CPHA_2Edge (stan 1). 

Można dobrać 4 różne konfiguracje synchronizacji danych na podstawie zamieszczonych informacji. Najczęściej wykorzystywaną metodą synchronizacji jest SPI_CPOL_LOW oraz SPI_CPHA_1Edge. 

Jeśli wykorzystywane jest więcej urządzeń należy wtedy odpowiednio zainicjalizować linię NSS (CS). Do wyboru są dwa tryby sterowania, sprzętowy oraz programowy. W celu sterowania programowego należy linię skonfigurować jako wyjście push-pull. Stan tej linii jest ustawiany bezpośrednio w programie. Natomiast dla konfiguracji sprzętowej linia musi być ustawiona jako funkcja alternatywna. Stanem tej linii steruje SPI.

Konfiguracja w oparciu o biblioteki API polega na dobraniu odpowiednich parametrów poprzez wypełnienie struktury SPI_InitTypeDef. Można wypełniać następujące pola:

  • SPI_Direction - pozwala na określenie ilości linii komunikacyjnych oraz kierunku wymiany danych. Można wybrać następujące parametry.
    • SPI_Direction_1Line_Rx,
    • SPI_Direction_1Line_Tx,
    • SPI_Direction_2Lines_FullDuplex,
    • SPI_Direction_2Lines_RxOnly.
  • SPI_Mode - jaki będzie tryb pracy urządzenia czy nadrzędny czy podrzędny
    • SPI_Mode_Master,
    • SPI_Mode_Slave,
  • SPI_CPHA - zbocze sygnału SCK, które będzie wyzwalać przesyłanie danych
    • SPI_CPHA_1Edge,
    • SPI_CPHA_2Edge,
  • SPI_CPOL - jaki będzie stan linii, gdy dane nie będą przesyłane
    • SPI_CPOL_Low,
    • SPI_CPOL_High,
  • SPI_NSS - pozwala na określenie sposobu sterowania linią NSS
    • SPI_NSS_Hard,
    • SPI_NSS_Soft,
  • SPI_BaudRatePrescaler - określenie dzielnika częstotliwości zegara SPI
    • SPI_BaudRatePrescaler_2, SPI_BaudRatePrescaler_4, SPI_BaudRatePrescaler_6 aż do SPI_BaudRatePrescaler_256,
  • SPI_FirstBit - któy bit będzie wysyłany jako pierwszy czy starszy czy młodszy
    • SPI_FirstBit_MSB
    • SPI_FirstBit_LSB,
  • SPI_CRCPolynomial - określenie wielomianu do obliczania sumy kontrolnej CRC
Dodatkowymi elementami wykorzystywanymi do konfiguracji są:

  • SPI_StructInit - pozwala na inicjalizację parametrów struktury,
  • SPI_Init - inizjalizuje ustawiony układ,
  • SPI_Cmd - pozwala na włączenie bądź wyłączenie SPI,
  • SPI_I2S_ITConfig - konfiguracja przerwań dla SPI,
  • SPI_I2S_DMACmd - pozwala na włączenie bądź wyłączenie poszczególnych linii DMA,

Do sterowania pracą można wykorzystać następujące wbudowane komendy:

  • SPI_I2S_SendData - pozwala na umieszczenie danych w buforze wyjściowym,
  • SPI_I2S_ReceiveData - pozwala na odebranie danych z bufora wejściowego,
  • SPI_I2S_GetFlagStatus - sprawdzenie stanu flagi. Pozwala określić czy dane są już gotowe do odczytu.
  • SPI_I2S_ClearFlag - czyszczenie flagi.

W kolejnych postach postaram się zamieścić przykładowe programy pozwalające na obsługę modułów wykorzystujących SPI.