Kurs STM32 LL cz. 21. Wprowadzenie do interfejsu SPI

SPI (Serial Peripheral Interface) to interfejs szeregowy powszechnie stosowany w mikrokontrolerach. Wykorzystywany jest do komunikacji z urządzeniami peryferyjnymi takimi, jak zewnętrzne konwertery ADC i DAC, pamięć FLASH, karta SD czy wyświetlacz. Dzisiaj postaram się przybliżyć działanie i budowę interfejsu SPI w STM32.

Protokół SPI

Magistrala SPI oferuje komunikację full-duplex, czyli jednoczesną komunikację w obu kierunkach. W SPI wyróżnia się dwa typy urządzeń – Master oraz Slave. Klasyczna struktura magistrali SPI zakłada istnienie jednego urządzenia Master z możliwością podłączenia wielu urządzeń Slave, chociaż STM32 mają możliwość pracy również w trybie multi master.

Komunikacja SPI realizowana jest za pomocą trzech linii:

  • SCK (lub SCLK) – linia zegarowa, sygnał generowany przez urządzenie master
  • MOSI – linia danych, która przesyła informacje z urządzenia Master do Slave (Master Output Slave Input)
  • MISO – linia danych, która przesyła informacje z urządzenia Slave do Master (Master Input Slave Output)

Dodatkowo linia CS (SS) służy jako linia wyboru urządzenia. Powinna być oddzielna dla każdego podłączonego Slave-a. Za jej pomocą Master aktywuje urządzenie, z którym chce się skomunikować. SPI nie wykorzystuje adresowania, jak to było w przypadku I2C.

Przyjrzyjmy się bliżej przebiegom transmisji na liniach magistrali SPI. Konfigurując pracę magistrali, jednym z ważniejszych parametrów jest ustawienie momentu, kiedy odczytywana jest wartość przesyłanego bitu. Odpowiadają za to dwa parametry: CPHA oraz CPOL.

CPOL (clock polarity) decyduje o tym, jaki stan przyjmuje linia zegarowa w przypadku braku transmisji. Jeżeli wartość CPOL wynosi “1”, linia zegarowa ma w stanie bezczynności poziom wysoki. Dla CPOL równemu “0”, przy braku transmisji na linii SCK jest stan niski.

Za pomocą CPHA (clock phase) decydujemy, czy bit powinien być odczytywany na pierwszym, czy na drugim zboczu.

W ten sposób można skonfigurować cztery tryby pracy. Każdy z nich został przedstawiony schematycznie na diagramach poniżej.

SPI pozwala na przesyłanie danych o długości od 4 bitów do 16 bitów. Zapewnia to dużą elastyczność. STM32 dodatkowo wykorzystuje bufory na liniach TX i RX  w postacji 32-bitowych kolejek, które zapewniają ciągłość transmisji.

Konfigurując SPI decydujemy również o tym, w jakiej kolejności mają być przesyłane dane. Do wyboru mamy transmisję zaczynając od najmniej znaczącego bitu (LSB) lub od najbardziej znaczącego bitu (MSB).

Skąd wiemy, jak skonfigurować SPI? To zależy od urządzenia Slave z którym się chcemy skomunikować. Sposób transmisji danych oraz ustawienia CPOL i CPHA znajdziemy w dokumentacji konkretnego układu (pamięci, wyświetlacza), który podłączamy do mikrokontrolera.

Schemat blokowy SPI w STM32

SPI umożliwia synchroniczną, szeregową komunikację pomiędzy MCU a urządzeniami zewnętrznymi. Aplikacja może zarządzać komunikacją poprzez flagi stanu w trybie polling lub wykorzystując dedykowane przerwania SPI.

Linie MOSI, MISO i SCK już omówiliśmy. Linia NSS to linia służąca do wyboru urządzenia (CS, SS). Może być ona wykorzystywana do aktywacji podłączonego Slave lub do wykrywania konfliktu komunikacji w przypadku trybu multi master.

Linie MOSI i MISO wykorzystują oddzielne rejestry przesuwne. Pojawienie się bitu na linii MOSI powoduje jednocześnie “wypchnięcie” bitu na linię MISO (i odwrotnie). Oznacza to, że zawsze dane na obu liniach są przesyłane jednocześnie. Zrozumienie tego mechanizmu jest ważne ze względu na obsługę komunikacji SPI – aby urządzenie Master odebrało jakieś dane, musi jednocześnie je wysyłać. Może to być tzw. pusty bajt (dummy byte), ale coś na linii MOSI musi się pojawić, aby odebrać dane z urządzenia Slave na linii MISO. Przechowywanie danych wspierają dwie kolejki FIFO. Dzięki temu przepływ danych jest płynniejszy.

Tryby komunikacji SPI

Magistrala SPI umożliwia komunikację pomiędzy jednym urządzeniem master a jednym lub kilkoma urządzeniami slave. SPI umożliwia komunikację przy użyciu różnych konfiguracji, w zależności od docelowego urządzenia i wymagań aplikacji. Konfiguracje te wykorzystują 2 lub 3 przewody (z programowym zarządzaniem NSS) albo 3 lub 4 przewody (ze sprzętowym zarządzaniem NSS). Komunikacja jest zawsze inicjowana przez master.

Tryb full-duplex

Domyślnie SPI jest skonfigurowany do komunikacji full-duplex. W tej konfiguracji rejestry przesuwające master i slave są połączone za pomocą dwóch jednokierunkowych linii pomiędzy pinami MOSI i MISO. Podczas komunikacji SPI dane są przesuwane synchronicznie zgodnie z sygnałem na linii zegarowej SCK. Master przekazuje dane, które mają być wysłane do slave przez linię MOSI i odbiera dane od slave przez linię MISO. Gdy transfer ramki danych zostanie zakończony (wszystkie bity są przesunięte), nastąpiła wymiana informacji pomiędzy masterem i slave.

Tryb half-duplex

SPI może komunikować się w także w trybie half-duplex. Wybór tego trybu odbywa się poprzez ustawienie bitu BIDIMODE w rejestrze SPIx_CR1. W tej konfiguracji wykorzystywana jest jedna linia do połączenia rejestrów przesuwnych mastera i slave. Podczas tej komunikacji dane są synchronicznie przesuwane pomiędzy rejestrami przesuwającymi na zboczu zegara SCK w kierunku przesyłania wybranym wzajemnie przez master i slave za pomocą bitu BDIOE w rejestrach SPIx_CR1. W tej konfiguracji pin MISO urządzenia nadrzędnego i pin MOSI urządzenia podrzędnego są wolne i mogą być wykorzystane do innych zastosowań.

Tryb Simplex

SPI może komunikować się w trybie prostym (Simplex), ustawiając SPI w tryb nadawania (transmit-only) lub odbierania (receive-only) za pomocą bitu RXONLY w rejestrze SPIx_CR2. W tej konfiguracji tylko jedna linia jest wykorzystywana do transferu pomiędzy rejestrami przesuwającymi master i slave. Pozostała para pinów MISO lub MOSI nie jest wykorzystywana do komunikacji i może być użyta jako standardowe GPIO.

W trybie transmit-only (RXONLY=0) ustawienia konfiguracyjne są takie same jak dla trybu full-duplex. Aplikacja musi ignorować informacje przechwycone na nieużywanym pinie wejściowym.

W trybie receive-only (RXONLY=1) można wyłączyć funkcję wyjścia SPI przez ustawienie bitu RXONLY. W konfiguracji slave wyjście MISO jest wyłączone, a pin może być używany jako GPIO. Slave nadal odbiera dane z pinu MOSI gdy aktywny jest jego sygnał Slave Select. Sygnał odebrania danych pojawia się w zależności od ustawień bufora. W konfiguracji master wyjście MOSI jest wyłączone i pin może być używany jako GPIO. Sygnał zegarowy jest generowany w sposób ciągły, dopóki SPI jest włączone. Jedynym sposobem na zatrzymanie zegara jest wyzerowanie bitu RXONLY lub bitu SPE.

Komunikacja multi-slave

W konfiguracji z dwoma lub więcej niezależnymi urządzeniami slave, master wykorzystuje piny GPIO do zarządzania liniami chip select dla każdego urządzenia. Musi wybrać jedno z urządzeń podrzędnych indywidualnie poprzez stan niski na GPIO urządzenia podrzędnego. Jako wyjście CS może służyć dowolny pin GPIO, a wybór urządzenia Slave odbywa się w pełni programowo.

Komunikacja multi-master

Pomimo tego, że magistrala SPI nie jest przeznaczona do pracy w trybie multi-master, użytkownik może skorzystać z wbudowanej funkcji STM32, która wykrywa potencjalny konflikt pomiędzy dwoma węzłami master próbującymi sterować magistralą w tym samym czasie. Do tego wykrywania wykorzystywany jest pin NSS skonfigurowany w trybie wejścia sprzętowego.

Połączenie więcej niż dwóch węzłów SPI pracujących w tym trybie jest niemożliwe, ponieważ tylko jeden węzeł może podawać swoje wyjście na magistralę. Gdy węzły nie są aktywne, oba pozostają domyślnie w trybie slave. Gdy jeden z węzłów chce przejąć kontrolę nad magistralą, przełącza się w tryb master i podaje poziom aktywny na wejście Slave select drugiego węzła. Po zakończeniu sesji, aktywny sygnał slave select jest zwalniany, a węzeł sterujący magistralą tymczasowo wraca do pasywnego trybu slave, czekając na rozpoczęcie kolejnej sesji.

Jeśli obydwa urządzenia master zgłoszą swoje zapotrzebowanie na sterowanie w tym samym czasie, wówczas wystąpi konflikt. Wtedy użytkownik może zastosować jakiś prosty proces arbitrażu (np. odłożyć następną próbę o zdefiniowany wcześniej time-out różny dla obu urządzeń).

Protokół Motorola vs TI

Interfejs SPI zaimplementowany w STM32 ma możliwość konfiguracji zgodnie z protokołem Motoroli lub TI (Texas Instruments). Protokoły te różnią się ustawieniami polaryzacji (CPOL) oraz zbocza (CPHA) oraz sposobem zarządzania pinem NSS. Podstawowym i domyślnym protokołem jest Motorola i to tego protokołu będziemy używać w przykładach. Jeżeli chciałbyś uzyskać więcej informacji na temat różnic w obu protokołach, zachęcam do lektury dokumentacji.

Flagi w komunikacji SPI

W przypadku SPI możemy wyróżnić trzy podstawowe flagi odpowiadające za komunikację oraz flagi obsługi błędów. Wśród pierwszych znajdziemy flagę:

  • TXE (TX buffer empty) – określa możliwość zapisu danych do rejestru. Nie oznacza ona, że poprzednie dane zostały już wysłane. Pamiętajmy, że dane z rejestru DR przekazywane są do kolejki FIFO. Flaga ta oznacza zatem, że w kolejce jest jeszcze miejsce i możemy dopisać kolejne dane.
  • RXNE (RX buffer not empty) – określa możliwość odczytu danych z rejestru.
  • BSY (busy) – określa, że transfer danych jest w trakcie realizacji. Może być wykorzystana jako flaga informująca o zakończeniu transferu albo jako zabezpieczenie przed kolizją w przypadku komunikacji multi master.

W przypadku flagi TXE i RXNE, czyścimy ją odpowiednio wpisując lub odczytując dane z rejestru SPI_DR. Flaga BSY jest ustawiana i czyszczona w pełni sprzętowo.

Do obsługi błędów służą natomiast flagi:

  • OVR (overrun) – określa, że bufor danych (kolejka RXFIFO) jest pełna i nie może zapisać danych, które przyszły. Jeżeli flaga ta jest ustawiona to oznacza, że ostatnie dane przychodzące zostały utracone.
  • MODF (mode fault) – określa błąd pinu NSS. Występuje, gdy w trybie master urządzenie chce ustawić pin NSS, a on jest podciągnięty do stanu niskiego (np. przez inne urządzenie w trybie multimaster).
  • CRCERR (CRC error) – określa błąd sumy kontrolnej, jeżeli ta jest używana w komunikacji.
  • FRE (frame format error) – określa błąd w trakcie komunikacji w trybie TI.

Nam na ten moment będą potrzebne informacje o flagach komunikacji. Obsługą błędów zajmiemy się przy innej okazji.

Podstawowe rejestry SPI

 Rejestr SPI_CR1 – rejestr konfiguracyjny SPI

Bit BIMODE – wybór trybu komunikacji (jedno- lub dwuprzewodowa)

Bit RXONLY – wybór trybu komunikacji Full-duplex

Bit SSI – wybór sposobu sterowania urządzeniem Slave

Bit LSBFIRST – wybór kolejności przesyłania bitów (LSB lub MSB)

Bit SPE – włączenie magistrali SPI

Bity BR[2:0] – wybór prędkości komunikacji

Bit MSTR – tryb pracy urządzenia (master lub slave)

Bit CPOL – wybór polaryzacji

Bit CPHA – wybór fazy

Rejestr SPI_CR2 – rejestr konfiguracyjny SPI

Bit DS[3:0] – rozmiar danych

Bit FRF – format ramki

Bit FRXTH – próg generowania zdarzenia RXNE (8 bitów lub 16 bitów)

Rejestr SPI_SR – rejestr statusu SPI

Bity FTLVL i FRLVL – stan zajętości kolejek FIFO nadawania i odbierania

Bit BSY – flaga zajętości linii SPI

Bity TXE i RXNE – flagi pustego rejestru nadawczego i niepustego rejestru odbiorczego

Rejestr SPI_DR – rejestr danych SPI

Chciałbyś otrzymywać na bieżąco informacje o nowych artykułach z kursu? Zapisz się do newslettera!

TO NIE TYLKO MAIL Z INFORMACJĄ O NOWEJ LEKCJI, ALE TAKŻE DODATKOWE MATERIAŁY. NIE PRZEGAP NOWEJ TREŚCI I DODATKOWYCH BONUSÓW. PRZEJDŹ DO STRONY KURSU I PODAJ SWÓJ ADRES E-MAIL. NIE ZAPOMNIJ POTWIERDZIĆ CHĘCI DOŁĄCZENIA W PIERWSZEJ WIADOMOŚCI!

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *