STM32 Porty GPIO — dla opornych 2

STM32 Porty GPIO — dla opornych 2
Razem głosów: 23 co stanowi: 93.91% całości.

 

Już wiecie że zawsze gdy zmieniamy sprzęt musimy zrewidować naszą wiedzę o podstawach np GPIO, i nic z tym nie zrobimy. Dziś pobawimy się dalej GPIO a naszym celem będzie generowanie  przebiegu prostokątnego na GPIO , a dokładnie

 

port D pin 0 …   Czyli reasumując ograniczymy się do podstawowych funkcji GPIO:

  •  ustawimy na porcie jeden pin  jako wyjście sygnału cyfrowego
  •  spowodujemy miganie diody

Łatwo nie będzie …  oczywiście możemy zrobić to przez łatwy sposób używając bibliotek CMSIS ale postaramy się  zejść do niższego poziomu co nam powinno ułatwić dokładne zapoznanie się z tym co właściwie się dzieje …

W przypadku ARM porty GPIO mają po 16 pinów które są kontrolowane przez szereg rejestrów. Opis ich można łatwo znaleźć w dokumentacji dostępnej na stronie STM i warto go przeglądnąć, ale postaram się je opisać …

—->> REJESTRY GPIO

W mikrokontrolerach STM32 mamy kilka portów , każdy ma 16 pinów, każdy  z tych pinów posiada szereg funkcji, a najbardziej podstawowa to cyfrowe wejście/wyjście, ponadto Funkcje dostępne na GPIO i stan każdego pinu kontroluje sporo rejestrów o tak mamy ich tu wiele …

  • 4 rejestry konfiguracyjne
  • 2 rejestry danych
  • 1 rejestr set/reset
  • 1 rejestr locking
  • 2 rejestry funkcji alternatywnych

——–>> Rejestry konfiguracyjne …

Jak wspomniałem jest ich aż 4 …

  1. GPIOx_MODER  — opisujący tryb portu
  2. GPIOx_OTYPER — opisujący typ portu
  3. GPIOx_OSPEEDR — opisujący szybkość/taktowanie portu
  4. GPIOx_PUPDR — odpowiadający za rezystory Pull-UP/Pull-Down

sporo… ale ponadto każdy z nich ma 32bity szerokości, choć nie wszystkie są używane w każdym z rejestrów.

Wygląda to strasznie prawda ?? ale postarajmy się z nimi lepiej poznać i zaprzyjaźnić.

Gwoli wyjaśnienia jeszcze napomnę że odnosić się będę do rejestrów w sposób w jaki jest to robione w Reference Manual co jednoznacznie określa sposób opisu  w stylu:

GPIOx_Nazwa_Funkcji

X  zastępuje nazwę portu która ma być użyta  np: GPIOD_OSPEEDR odnosi się do portu D. Tm samym X może przyjmować wartość od A do I zależnie od używanego mikrokontrolera.


 

GPIOx_MODER  …:>>

To 32-bitowy rejestr który posiada 2 wartości bitowe określające tryb pracy. Można tu ustawić tryby:

Wartości bitowe Opis
00 Wejście
01 Wyjście ogólnego przeznaczenia
10 Funkcja alternatywna
11 Analogowy

Standardowo domyślna wartość dla tego rejestru to 0. Tym samym wszystkie piny to wejścia po resecie , ale niektóre są przywracane do wartości niezerowych jak np. piny odpowiedzialne za debugowanie. Dlatego też tak wygląda podział ustawień portów po resecie w stm32:

Port wartość po resecie
A 0 x A800 0000
B 0 × 0000 0280
Wszystkie inne 0 × 0000 0000

Bity w tym rejestrze są typu R/W i zgrupowane w parach. tak więc:

  • bity 0 i 1  – określają tryb pinu 0
  • bity 2 i 3  – określają tryb dla pinu 1   ..itd.

GPIOx_OTYPER ->>

Ten 32 bitowy rejestr  używa tylko dolnych 16 bitów , zaś 16 bitów górnych jest zarezerwowane i nie powinny być stosowane. Rejestr ten wykorzystuje  jeden bit dla każdego pinu dzięki czemu możemy zdefiniować typ wyjścia pinu na porcie. Czyli:

  • bit 0 – określa typ pinu 0
  • bit 1 – określa typ pinu 1
  • itd….

Każdy z bitów w porcie może przyjąć  2 wartości 0 i 1 , która ustala jakiego typu jest wyjście pinu czyli :

Wartość BITu Opis
0 Push / Pull
1 Open Drain


W przypadku tego rejestru wartość domyślna wszystkich rejestrów GPIOx_OTYPER jest zawsze  ustawiona na 0x 0000 000 co oznacza że wszystkie piny są ustawione na Push/Pull  .


 

GPIOx_OSPEEDR –>>

Tu są używane wszystkie 32 bity.  Są pogrupowane parami podobnie jak w rejestrze portów, a określa się tu szybkość wyjścia portu. Możemy ustawić następujące wartości:

Wartości bitowe Opis
00   2 MHz
01 25 MHz
10 50 MHz
11 100 MHz, pojemność 30pF *
80 MHz , pojemność 15 pF *


* zależy od konkretnego modelu mikrokontrolera.

Wartości domyslne po resecie jakie przyjmuje ten rejestr to:

  • 0 x 0000 00C0 dla portu B
  • 0 x 0000 0000  dla wszystkich pozostałych portów

 

GPIOx_PUPDR ->>

Tutaj też są używane wszystkie 32bity dostępne dla rejestru i podobnie są pogrupowane w pary. Bity te określają czy załączony dla pinu jest rezystor  Pull-UP czy Pull-Down. Poniżej mamy wartości dla rejestru:

Wartości bitowe Opis
00 Bez rezystorów
01 Rezystor pull-up
10 Rezystor pull-down
11 Zastrzeżone

Wartości domyślne po resecie to:

  • dla portu A  — 0x 6400 0000
  • dla portu B  — 0x 0000 0100
  • wszystkie inne  — 0x 0000 0000

 

Uff przebrnęliśmy przez rejestry konfiguracyjne STM32   tak więc teraz pora na rejestry danych , których jak już wiemy mamy 2  to co gotowi ??

— no to jedziemy.


Dwa rejestry danych dla każdego z portów to lekka rozpusta zwłaszcza że wskazują one tylko stan wejścia /wyjścia z portu. Pomimo ze każdy z tych 2ch rejestrów jest 32 bitowy używane jest tylko dolne 16bitów. Górne są zarezerwowane i nie używane. Czas zatem przedstawic te 2 rejestry a są to:

  • GPIOx_IDR  –  rejestr danych wejściowych
  • GPIOx_ODR – rejestr danych wyjściowych

To co poznajemy je bliżej ?? no pewnie że tak  :)

GPIOx_IDR –>>

Jest to rejestr danych wejściowych który wskazuje czy pin znajduje się w stanie niskim czy wysokim :)  Rejestr ten jest tylko do odczytu i zawsze czyta się pełne słowo. Dostępne wartości to:

Wartość Opis
0 Niska wartość logiczna  (LOW)
1 Wysoka wartość logiczna (HIGH)

W tym rejestrze podobnie jak w rejestrze GPIOx_OTYPER kolejne bity wskazują kolejny pin na porcie , czyli można przyjąć mapę :   bit 0  — pin 0 , bit 1 — pin 1 itd…

Po resecie wartość domyślna dla wszystkich rejestrów _IDR  to 0x 0000 xxxx gdzie X oznacza że wartość bitów jest nie znana i zostanie określona przez sygnały wejściowe na pinach.

GPIO_ODR –>> 

Rejestr danych wyjściowych umożliwia naszemu programowi zmianę stanu danego pinu. Do dyspozycji mamy 16 dolnych bitów które może przyjąć wartości :

wartość Opis
0 Niska wartość logiczna (LOW)
1 HIGH wartość logiczna (HIGH)

Mapa bitów jest identyczna z IDR z tą tylko różnicą że tym razem dolne 16 bitów rejestru _ODR jest typu R/W  czyli możemy czytać i zapisywać wartości.

Po resecie domyślnie wszystkie rejestry _ODR przyjmują wartość 0x 0000 0000

Ustawianie wartości w rejestrze _ODR jest trochę nie wygodne , ale tu z pomocą przychodzi nam kolejny rejestr  GPIOx_BSSR :)

GPIOx_BSSR –>

Ten rejestr to w sumie taki zestaw set /reset , który pozwala na ustawienie lub zresetowanie pojedynczego bitu w rejestrze danych wyjściowych _ODR.

Rejestr ten ma 32bity szerokości i jest podzielony na 2 części po 16 bitów. Dolne 16 bitów służy do ustawienia bitu , a górne do zresetowania bitu w rejestrze _ODR. Podczas odczytu _BSSR zawsze zwraca 0x 0000, Gdyż służy on głównie do zapisu danych.

Jeśli ustawimy bit w dolnych 16 bitach _BSSR  to zostanie ustawiony odpowiedni bit w rejestrze _ODR na 1 , natomiast ustawienie bitu w górnych 16bitach spowoduje wykasowanie odpowiedniego bitu w rejestrze _ODR czyli ustawienie na 0.

Na dolnych 16 bitach jest prosto …. i mapowanie jest następujące:

  • bit 0 w _BSSR  = Bit 0 w _ODR  itd..

natomiast w górnych 16 bitach musimy się przyzwyczaić że:

  • bit 16 w _BSSR  = Bit 0 w _ODR
  • bit 17 w _BSSR  = Bit 1 w _ODR
  • itd…

Dzięki czemu rejestr _BSSR pozwala na dostęp na poziomie metody atomowej do pinów w portach GPIO mikrokontrolera. Pozwalając błyskawicznie zmienić / ustawić stan wybranych pinów lub je zresetować . Trzeba pamiętać że podczas tradycyjnego ustawiania pinów wyjściowych kompilator generuje dużo różnych oświadczeń i komend dostepowych w celu ustawienia lub zresetowania wybranego pinu, co może uniemożliwić np wykonanie przerwania jeśli w tym czasie wykonywana jest operacja na rejestrze _ODR , tymczasem  przy pomocy _BSSR niema takiego problemu i działanie programu nie napotyka na zakłócenia.  Tylko dlatego że dokonujemy operacji za pomocą pojedynczej instrukcji, a nie ich ciągu. Co oznacza że zmiana stanu zostanie wykonana przed przerwaniem i tym samym zostanie wykonana jego obsługa. Dlatego warto korzystać z rejestru _BSSR.


Rejestry dodatkowe :

GPIOx_LCKR –>>

Ten rejestr jest tzw rejestrem blokowania konfiguracji do następnego RESETU układu.

Rejestr jest 32bitowy  w prawdzie , ale używane jest tylko  17 bitów. Dolne 16 bitów jest zablokowane, ale używany jest 16 bit w rejestrze zwany KEY LOCK (LCKK) ten bit określa stan blokady portu, a więc:

  • 0 oznacza brak blokady
  • 1 oznacza zablokowaną konfigurację

By dokonać blokady konfiguracji portu musimy przestrzegać sekwencji zapisu konfiguracji przez co unikniemy przypadkowego zablokowania. Sekwencja jest następująca:

  1. Przygotowanie zestawu bitów 0-15 wskazujący które piny powinny mieć zablokowaną konfigurację
  2. Ustawiamy LCKK na 1 i zapisujemy wartość do rejestru
  3. Ustawiamy LCKK na 0 i zapisujemy wartośc do rejestru
  4. Ustawiamy LCKK na 1 i zapisujemy do rejestru
  5. Odczytujemy wartość blokady portu.

Ważne jest by pamiętać że wartości bitów 0-15 nie powinny być  zmieniane podczas wykonywania kolejnej sekwencji. Jakikolwiek błąd spowoduje przerwanie blokady.

Ostatni krok czyli odczytanie bitu blokady potwierdza sukces lub niepowodzenie operacji.  Blokada zostaje zniesiona po RESECIE mikrokontrolera.


 

Ostatnim jest rejestr funkcji alternatywnych , pozwala on na ustawienie portu na funkcje alternatywne np nasze proste GPIO może zmienić się w  SPI.  Omówimy go później bowiem teraz nie jest nam on potrzebny ….

Tym samym na tym kończymy cześć drugą  wywodu o GPIO w STM32

Podziel się na:
  • Print
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google Bookmarks
  • Blogplay