poniedziałek, 26 października 2015

[1] STM32F4 - Rejestry GPIO

Mikrokontroler posiada szereg portów, które składają się z 16 oddzielnych linii. Można wyróżnić następujące typy rejestrów:
  • Cztery rejestry konfiguracyjne;
  • Dwa rejestry danych;
  • Jeden rejestr ustawiania/resetowania;
  • Jeden rejestr zamykający;
  • Dwa rejestry posiadające różne funkcje;
Z rejestrów konfiguracyjnych można wyróżnić:
GPIOx_MODER - sposób wykorzystania portu (np. port wejścia/wyjścia),
GPIOx_OTYPER - typ konfiguracji portu (Open drain, Push/pull),
GPIOx_OSPEEDR - rejestr szybkości taktowania,
GPIOx_PUPDR - rejestr odpowiedzialny za rezystor podciągający (Pull-up/Pull-down).

W miejsce x wprowadza się nazwę portu np. A, B, D itp.


GPIOx_MODER umożliwia ustawienie następujących parametrów:

  • 00 - Wejście (ang. Input),
  • 01 - Ustawienie ogólne - wyjście (ang. General purpose output)
  • 10 - Funkcje alternatywne (ang. Alternate function)
  • 11 - Analogowy (ang. Analog)
Wartość 0 jest wartością resetującą ustawienia na danych pinach. Niektóre z nich są resetowane poprzez wprowadzenie innej wartości. Dotyczy to portów A i B (odpowiednio 0xA800 0000, 0x0000 0280)

GPIOx_OTYPER jest to rejestr 32 bitowy. Wykorzystywane jest dolnych 16 bitów. Pozostałe są zarezerwowane. 
Do zdefiniowania typu pinu stosuje się pojedynczy bit.
  • 0 - Wyjście typu push pull,
  • 1 - Wyjście typu otwarty dren
Wartością resetującą jest wartość 0. Domyślnie pin ustawiony jak wyjście typu push-pull.

GPIOx-OSPEEDR pozwala na ustawienie szybkości działania portu. 
  • 00 - 2 MHz,
  • 01 - 25 MHz,
  • 10 - 50 MHz,
  • 11 - 100 MHz. 
Wartością resetującą jest 0x0000 0C00 dla portu B. Dla reszty jest to wartość 0.

GPIOx_PUPDR jest rejestrem 32 bitowym. Pozwala na ustawienie rezystora podciągającego.
  • 00 - Bez rezystora,
  • 01 - Rezystor podciągający do zasilania (ang. Pull-up),
  • 10 - Rezystor podciągający do masy (ang. Pull-down),
  • 11 - Zastrzeżone (ang. Reserved)
Dla większości portów reset następuje poprzez wprowadzenie wartości 0. Natomiast dla portów A i B należy wprowadzić inne wartości (A - 0x6400 0000, B-0x0000 0100)

GPIOx_IDR rejestr danych przychodzących. Zostaje włączony gdy zostanie podany na pin sygnał niski lub wysoki. Rejestr pozwala tylko na odczyt danych.
  • 0 - Stan logiczny wysoki,
  • 1 - Stan logiczny niski.
GPIOx_ODR jest to rejestr danych wychodzących. Stany na danym pinie są identyczne jak w rejestrze IDR. 

GPIO_BSSR rejestr ustawiania, resetowania. (ang. Bit Set/Reset register). BSSR jest rejestrem 32 bitowym. Został on podzielony na dwie 16 bitowe części. Bity od 31 do 16 są odpowiedzialne za resetowanie wartości., natomiast bity od 15:0 odpowiadają za ustawianie pinu. Do tego rejestru możliwe jest tylko wprowadzenie danych. Wpisanie jakiejś wartości spowoduje zwrócenie 0x0000.
Resetowanie przebiega poprzez podanie wartości 0x0000 0000. 
Rejestr ten został podzielony na dwie części odpowiadające bitom wyższym BSSRH oraz niższym BSSRL. 


GPIO_LCKR służy do blokowania ustawionych parametrów portów. Poprawna wartość danych podawana jest do bitu 16 LCKK. Bity od 15 do 0 są używane do blokowania wartości portów. W czasie wprowadzania ustawień wartość bitów, od 0 do 15, nie może ulec zmianie. Po wprowadzeniu i zablokowaniu danych wartość portu nie może być modyfikowana. 

Rejestr resetuje się poprzez podanie wartości 0x0000 0000.

Blokowanie konfiguracji przeprowadza się w następujący sposób:
  • Na początku należy wybrać pin dla którego konfiguracja zostanie zablokowana poprzez ustawienie bitów od 0 do 15. 
  • Ustawienie wartości LCKK na wartość 1, następnie wpisanie wartości do rejestru.
  • Podanie wartości 0 do LCKK, wpisanie wartości do rejestru.
  • Ustawienie wartości 1 na LCKK, wpisanie danych rejestru.

Na rysunku 1.1. przedstawiłem dokładną specyfikację tego rejestru zaczerpniętą z danych katalogowych firmy STM [1]. 

Rys. 1.1. Rejestr LCKR

GPIO_AFRL pozwala na ustawienie funkcji alternatywnych na pinie. Z tego rejestru należy korzystać jeśli wykorzystuje się interfejsy komunikacyjne takie jak SPI.

Program 1


W tym programie przedstawię sposób ustawiania oraz mrugania diodą podłączoną do pinu PA0.

  1. #include "stm32f4xx_rcc.h"
  2. #include "stm32f4xx_gpio.h"
  3.  
  4. void DelayMain(void);
  5.  
  6. int main()
  7. {
  8.  //Włączenie zegara dla portu A
  9.  //Wykorzystano rejestr AHB1 enable register
  10.  RCC->AHB1ENR |= RCC_AHB1Periph_GPIOA;
  11.  _DSB();
  12.  //Inicjalizacja GPIO
  13.  GPIOA->MODER |= GPIO_Mode_OUT;
  14.  GPIOA->OSPEEDR |= GPIO_Speed_25MHz;
  15.  GPIOA->OTYPER |= GPIO_OType_PP;
  16.  GPIOA->PUPDR |= GPIO_PuPd_NOPULL;
  17.  
  18.  //Zapalenie i zgaszenie diody
  19.  while (1)
  20.  {
  21.   GPIOA->BSRRL = GPIO_Pin_0;
  22.   DelayMain();
  23.   GPIOA->BSRRH = GPIO_Pin_0;
  24.   DelayMain();
  25.  }
  26. }
  27.  
  28. //Funckja opozniająca
  29. void DelayMain(void)
  30. {
  31.  volatile uint32_t i;
  32.  for (= 0; i != 0xFFFFF; i++);
  33. }

Po włączeniu zegara należy odczekać pewien okres czasu aby zegary zostały poprawnie uruchomione, można tego dokonać za pomocą komendy _DSB(), Zadaniem tej komendy jest wstrzymanie wykonywania operacji do czasu zakończeniu przeprowadzania operacji w pamięci.

Zamiast nazwy pinu można wprowadzić poprzez wpisanie następującej komendy:

  1.  while (1)
  2.  {
  3.   GPIOA->BSRRL = (1<<0);
  4.   DelayMain();
  5.   GPIOA->BSRRH = (1<<0);
  6.   DelayMain();
  7.  }

Wpisuje ona w rejestrze wartość 1 w miejsce odpowiadające numerowi pinu,

W celu inicjalizacji pinów innych niz Px0 należy zmienić sposób deklaracji portów na następujący:

  1.  GPIOA->MODER |= GPIO_Mode_OUT << (pin * 2);
  2.  GPIOA->OSPEEDR |= GPIO_Speed_25MHz << (pin * 2);
  3.  GPIOA->OTYPER |= GPIO_OType_PP << pin;
  4.  GPIOA->PUPDR |= GPIO_PuPd_NOPULL << (pin * 2);

W miejsce pin podajemy numer wykorzystywanego wyprowadzenia.

Program ustawiający wszystkie cztery diody na płytce Discovery:

  1. #include "stm32f4xx.h"
  2. #include "stm32f4xx_rcc.h"
  3. #include "stm32f4xx_gpio.h"
  4.  
  5. /*
  6. #define GPIO_Pin_0                 ((uint16_t)0x0001)  
  7. #define GPIO_Pin_1                 ((uint16_t)0x0002)  
  8. #define GPIO_Pin_2                 ((uint16_t)0x0004)  
  9. #define GPIO_Pin_3                 ((uint16_t)0x0008)  
  10. #define GPIO_Pin_4                 ((uint16_t)0x0010)  
  11. #define GPIO_Pin_5                 ((uint16_t)0x0020)  
  12. #define GPIO_Pin_6                 ((uint16_t)0x0040)
  13. #define GPIO_Pin_7                 ((uint16_t)0x0080)  
  14. #define GPIO_Pin_8                 ((uint16_t)0x0100)
  15. #define GPIO_Pin_9                 ((uint16_t)0x0200)
  16. #define GPIO_Pin_10                ((uint16_t)0x0400)
  17. #define GPIO_Pin_11                ((uint16_t)0x0800)  
  18. #define GPIO_Pin_12                ((uint16_t)0x1000)  
  19. #define GPIO_Pin_13                ((uint16_t)0x2000)  
  20. #define GPIO_Pin_14                ((uint16_t)0x4000)
  21. #define GPIO_Pin_15                ((uint16_t)0x8000)
  22. #define GPIO_Pin_All               ((uint16_t)0xFFFF)
  23. */
  24.  
  25. /*
  26.  LED_GREEN   on PD12
  27.  LED_ORANGE  on PD13
  28.  LED_RED     on PD14
  29.  LED_BLUE    on PD15
  30. */
  31.  
  32. #define setPinHigh(GPIOx, pin)                          GPIOx->BSRRL = pin
  33. #define setPinLow(GPIOx, pin)                               GPIOx->BSRRH = pin
  34.  
  35. void DelayMain(void);
  36. void setPinAsOutput(GPIO_TypeDef* GPIOx, uint8_t pinNumber)
  37. {
  38.     GPIOx->MODER |= GPIO_Mode_OUT << (pinNumber * 2);
  39.     GPIOx->OSPEEDR |= GPIO_Speed_25MHz << (pinNumber * 2);
  40.     GPIOx->OTYPER |= GPIO_OType_PP << pinNumber;
  41.     GPIOx->PUPDR |= GPIO_PuPd_NOPULL << (pinNumber * 2);
  42. }
  43.  
  44. int main()
  45. {
  46.      RCC->AHB1ENR |= RCC_AHB1Periph_GPIOD;
  47.      __DSB();
  48.    
  49.      setPinAsOutput(GPIOD, 12);
  50.      setPinAsOutput(GPIOD, 13);
  51.      setPinAsOutput(GPIOD, 14);
  52.      setPinAsOutput(GPIOD, 15);
  53.  
  54.      //Zapalenie i zgaszenie diody
  55.      while (1)
  56.      {
  57.          setPinHigh(GPIOD, GPIO_Pin_12);
  58.          setPinHigh(GPIOD, GPIO_Pin_13);
  59.          setPinHigh(GPIOD, GPIO_Pin_14);
  60.          setPinHigh(GPIOD, GPIO_Pin_15);
  61.          DelayMain();
  62.          setPinLow(GPIOD, GPIO_Pin_12);
  63.          setPinLow(GPIOD, GPIO_Pin_13);
  64.          setPinLow(GPIOD, GPIO_Pin_14);
  65.          setPinLow(GPIOD, GPIO_Pin_15);
  66.          DelayMain();
  67.      }
  68. }

BIBLIOGRAFIA


[1]              STM32F4 rejestry GPIO