sobota, 26 marca 2011

ARM: LPC11xx - Moduły IOCONFIG i GPIO, czyli programowanie portów.


Autor: Deucalion
Redakcja: Dondu

Artykuł jest częścią cyklu: Kurs ARM: Spis treści


IOCONFIG i GPIO są to dwa moduły, które pozwalają na konfigurację i sterowanie portami w LPC1114. Każdemu pinowi przyporządkowany jest jeden rejestr w module IOCONFIG, odpowiedzialny za jego konfigurację.

Definicje tych rejestrów znajdują się w pliku LPC11xx.h:

typedef struct
{
  __IO uint32_t PIO2_6;       // 0x000 PIO2_6 (R/W) 
       uint32_t RESERVED0[1];
  __IO uint32_t PIO2_0;       // 0x008 PIO2_0/DTR/SSEL1 (R/W) 
  __IO uint32_t RESET_PIO0_0; // 0x00C RESET/PIO0_0  (R/W) 
  __IO uint32_t PIO0_1;       // 0x010 PIO0_1/CLKOUT/CT32B0_MAT2 (R/W) 
  __IO uint32_t PIO1_8;       // 0x014 PIO1_8/CT16B1_CAP0 (R/W) 
       uint32_t RESERVED1[1];
  __IO uint32_t PIO0_2;       // 0x01C PIO0_2/SSEL0/CT16B0_CAP0 (R/W) 

  __IO uint32_t PIO2_7;       // 0x020 PIO2_7 (R/W) 
  __IO uint32_t PIO2_8;       // 0x024 PIO2_8 (R/W) 
  __IO uint32_t PIO2_1;       // 0x028 PIO2_1/nDSR/SCK1 (R/W) 
  __IO uint32_t PIO0_3;       // 0x02C PIO0_3 (R/W) 
  __IO uint32_t PIO0_4;       // 0x030 PIO0_4/SCL (R/W) 
  __IO uint32_t PIO0_5;       // 0x034 PIO0_5/SDA (R/W) 
  __IO uint32_t PIO1_9;       // 0x038 PIO1_9/CT16B1_MAT0 (R/W) 
  __IO uint32_t PIO3_4;       // 0x03C PIO3_4 (R/W) 

  __IO uint32_t PIO2_4;       // 0x040 PIO2_4 (R/W) 
  __IO uint32_t PIO2_5;       // 0x044 PIO2_5 (R/W) 
  __IO uint32_t PIO3_5;       // 0x048 PIO3_5 (R/W) 
  __IO uint32_t PIO0_6;       // 0x04C PIO0_6/SCK0 (R/W) 
  __IO uint32_t PIO0_7;       // 0x050 PIO0_7/nCTS (R/W) 
  __IO uint32_t PIO2_9;       // 0x054 PIO2_9 (R/W) 
  __IO uint32_t PIO2_10;      // 0x058 PIO2_10 (R/W) 
  __IO uint32_t PIO2_2;       // 0x05C PIO2_2/DCD/MISO1 (R/W) 

  __IO uint32_t PIO0_8;       // 0x060 PIO0_8/MISO0/CT16B0_MAT0 (R/W) 
  __IO uint32_t PIO0_9;       // 0x064 PIO0_9/MOSI0/CT16B0_MAT1 (R/W) 
  __IO uint32_t SWCLK_PIO0_10;// 0x068 SWCLK/PIO0_10/SCK0/CT16B0_MAT2 (R/W) 
  __IO uint32_t PIO1_10;      // 0x06C PIO1_10/AD6/CT16B1_MAT1 (R/W) 
  __IO uint32_t PIO2_11;      // 0x070 PIO2_11/SCK0 (R/W) 
  __IO uint32_t R_PIO0_11;    // 0x074 TDI/PIO0_11/AD0/CT32B0_MAT3 (R/W) 
  __IO uint32_t R_PIO1_0;     // 0x078 TMS/PIO1_0/AD1/CT32B1_CAP0 (R/W) 
  __IO uint32_t R_PIO1_1;     // 0x07C TDO/PIO1_1/AD2/CT32B1_MAT0 (R/W) 

  __IO uint32_t R_PIO1_2;     // 0x080 nTRST/PIO1_2/AD3/CT32B1_MAT1 (R/W) 
  __IO uint32_t PIO3_0;       // 0x084 PIO3_0/nDTR (R/W) 
  __IO uint32_t PIO3_1;       // 0x088 PIO3_1/nDSR (R/W) 
  __IO uint32_t PIO2_3;       // 0x08C PIO2_3/RI/MOSI1 (R/W) 
  __IO uint32_t SWDIO_PIO1_3; // 0x090 SWDIO/PIO1_3/AD4/CT32B1_MAT2 (R/W) 
  __IO uint32_t PIO1_4;       // 0x094 PIO1_4/AD5/CT32B1_MAT3 (R/W) 
  __IO uint32_t PIO1_11;      // 0x098 PIO1_11/AD7 (R/W) 
  __IO uint32_t PIO3_2;       // 0x09C PIO3_2/nDCD (R/W) 

  __IO uint32_t PIO1_5;       // 0x0A0 PIO1_5/nRTS/CT32B0_CAP0 (R/W) 
  __IO uint32_t PIO1_6;       // 0x0A4 PIO1_6/RXD/CT32B0_MAT0 (R/W) 
  __IO uint32_t PIO1_7;       // 0x0A8 PIO1_7/TXD/CT32B0_MAT1 (R/W) 
  __IO uint32_t PIO3_3;       // 0x0AC PIO3_3/nRI (R/W) 
  __IO uint32_t SCK_LOC;      // 0x0B0 SCK pin location select Register (R/W) 
  __IO uint32_t DSR_LOC;      // 0x0B4 DSR pin location select Register (R/W) 
  __IO uint32_t DCD_LOC;      // 0x0B8 DCD pin location select Register (R/W) 
  __IO uint32_t RI_LOC;       // 0x0BC RI  pin location select Register (R/W) 
} LPC_IOCON_TypeDef;


#define LPC_IOCON_BASE        (LPC_APB0_BASE + 0x44000)
#define LPC_IOCON             ((LPC_IOCON_TypeDef  *) LPC_IOCON_BASE )



Budowa rejestru konfigurującego pin I/O


ARM LPC11xx - Budowa rejestru konfigurującego pin I/O.


Opis pól bitowych:

FUNC – funkcja pinu I/O
Znaczna część pinów oprócz standardowej funkcji czyli zwykłego wejścia/wyjścia ma też funkcje alternatywne, tzn. piny mogą być dołączone do wewnętrznych peryferii i spełniać ściśle określone zadania, np. pin P1.6 ma przyporządkowane następujące funkcje:

  • 000b - GPIO - Standardowe wejście/wyjście I/O
  • 001b – RXD – Wejście odbiornika transmisji szeregowej
  • 010b – CT32B0_MAT0 - Pierwsze wyjście układu porównującego 32b licznika B0

Za pomocą pola bitowego FUNC ustawiamy funkcję jaką dany pin ma spełniać. Większość pinów po resecie przyjmuje funkcję GPIO, kilka ma standardowo ustawione funkcje alternatywne.

Definicje związane z bitami FUNC w pliku syscon.h:

#define  IOCON_PIO_FUNC0       (0 << 0)
#define  IOCON_PIO_FUNC1       (1 << 0)
#define  IOCON_PIO_FUNC2       (2 << 0)
#define  IOCON_PIO_FUNC3       (3 << 0)
#define  IOCON_PIO_FUNC4       (4 << 0)
#define  IOCON_PIO_FUNC5       (5 << 0)
#define  IOCON_PIO_FUNC6       (6 << 0)
#define  IOCON_PIO_FUNC7       (7 << 0)
#define  IOCON_PIO_FUNC_M      (7 << 0) // Mask


MODE - Pull-up i pull-down

Bity te pozwalają sterować wewnętrznymi tranzystorami podciągającymi dla pinów skonfigurowanych jako wejścia. Oprócz standardowych opcji podciągania do zasilania i ściągania do masy jest tryb repetera. Przydatny tryb pozwalający na zapamiętanie ostatniego stanu jaki był podany na pin.

Może przydarzyć się sytuacja, gdy do wejścia podłączony jest inny układ, który na wyjściu generuje trzy stany - niski, wysoki i wysokiej impedancji. Tryb ten zapobiega przed przypadkowymi przełączeniami generowanymi np. przez zakłócenia, a przy normalnej pracy, gdy na wejście podawane są stany niskie i wysokie, obniża zużycie prądu poprzez samoczynne dostosowanie rezystora podciągającego.

Możliwe tryby:
  • 00b – tranzystory podciągające wyłączone
  • 01b – włączony tranzystor ściągający do masy
  • 10b – włączony tranzystor podciągający do zasilania ( lub 2,6V dla układów LPC111x/xx1)
  • 11b – włączony tryb repetera


Definicje związane z bitami MODE w pliku syscon.h:

#define  IOCON_PIO_MODE0          (0 << 3)
#define  IOCON_PIO_MODE_OFF       (0 << 3)
#define  IOCON_PIO_MODE1          (1 << 3)
#define  IOCON_PIO_MODE_PD        (1 << 3)
#define  IOCON_PIO_MODE2          (2 << 3)
#define  IOCON_PIO_MODE_PU        (2 << 3)
#define  IOCON_PIO_MODE3          (3 << 3)
#define  IOCON_PIO_MODE_REPEATER  (3 << 3)
#define  IOCON_PIO_MODE_M         (3 << 3) // Mask



HYS - Histereza

Bit służy do włączenia histerezy buforom wejściowym. Opcja może być wykorzystywana tylko przy napięciach zasilających od 2,5V do 3,6V. Przy niższych napięciach powinna być zablokowana.

Definicje związane z bitem HYS w pliku syscon.h:

#define  IOCON_PIO_HYS      (1 << 4)



OD - Pseudo otwarty dren

Opcja dostępna tylko w układach LPC111x/xx2. Pozwala na przełączenie pinu pracującego jako wyjście w tryb otwartego drenu. Pseudo oznacza, że sterowany jest tylko tranzystor sterujący do masy, a tranzystor sterujący do zasilania jest cały czas zamknięty, ale nadal tam jest i stwarza jakieś tam ograniczenia, np. nie wolno podać napięcia większego niż napięcie zasilania procesora.

Definicje związane z bitem OD w pliku syscon.h:

#define  IOCON_PIO_OD      (1 << 10)



ADMODE - Wejście analogowe

Opcja dostępna tylko dla pinów, które posiadają funkcję wejścia analogowego. Pole bitu zostało zaznaczone na czerwono, aby wyszczególnić jego odwrotną logikę, tzn. wyzerowanie bitu powoduje przełączenie pinu w tryb analogowy.

Z tego względu należ zwrócić uwagę, aby przez przypadek ustawiając inne bity w rejestrze, nie wyzerować tego bitu jeśli nie chcemy korzystać z funkcji analogowej danego pinu. Dodatkowo, alternatywna funkcja pinu również powinna być ustawiona na tryb analogowy. Po odpowiednim ustawieniu bitów FUNC i ADMODE, pozostałe bity nie mają znaczenia.

Definicje związane z bitem ADMODE w pliku syscon.h:

#define  IOCON_PIO_ANALOG      (0 << 7)
#define  IOCON_PIO_DIGITAL     (1 << 7)



SCK, DSR, DCD, RI

Cztery ostatnie rejestry z wyżej zaprezentowanej struktury uzupełniają funkcje kontrolne pinów SCK, DSR, DCD, RI, ponieważ te funkcje alternatywne są zaimplementowane na więcej niż jednym pinie I/O. Za pomocą tych rejestrów dołączamy daną funkcję do odpowiedniego pinu , np. SCK może być dołączony do P0.6, P0.10, P2.11.

Definicje związane z w/w rejestrami w pliku syscon.h:

#define  IOCON_SCKLOC_P0_10       (0 << 0)
#define  IOCON_SCKLOC_P2_11       (1 << 0)
#define  IOCON_SCKLOC_P0_6        (2 << 0)

#define  IOCON_DSRLOC_P2_1        (0 << 0)
#define  IOCON_DSRLOC_P3_1        (1 << 0)

#define  IOCON_DCDLOC_P2_2        (0 << 0)
#define  IOCON_DCDLOC_P3_2        (1 << 0)

#define  IOCON_RILOC_P2_3         (0 << 0)
#define  IOCON_RILOC_P3_3         (1 << 0)


Uwaga!!!

Wiele już osób poległo na próbie konfiguracji portów za pomocą modułu IOCONFIG spędzając godziny, a może i całe dni na znalezieniu przyczyny, która objawiała się tym, że np. dioda nie chciała mrugać, nie wiedząc o tym, że porty nie przełączały się w tryb wyjścia. W kodzie programu wszystko zgadzało się, ale rzeczywistość była inna.

Problem jest trywialny, ale jego źródło znajduje się w innej części procesora, a mianowicie w bloku SYSCON, a konkretnie w rejestrze SYSAHBCLKCTRL i jego 16-tym bicie o nazwie IOCON.

Jakiekolwiek operacje na bloku IOCONFIG możliwe są dopiero po jego ustawieniu.

Ustawienie tego bitu powoduje włączenie sygnału taktującego blok IOCONFIG.

Włączenie taktowania bloku IOCONFIG:

SYSAHBCLKCTRL |= (1 << 16);

Przykładowe konfiguracje pinów I/O:

LPC_IOCON->PIO0_8 =  IOCON_PIO_DIGITAL | IOCON_PIO_FUNC0 | IOCON_PIO_MODE_PU;
LPC_IOCON->PIO1_8 =  IOCON_PIO_DIGITAL | IOCON_PIO_FUNC1 |
                     IOCON_PIO_MODE_REPEATER | IOCON_PIO_HYS;
LPC_IOCON->PIO1_10 = IOCON_PIO_ANALOG | IOCON_PIO_FUNC1;

1 komentarz:

  1. Witam,
    przestrzegam wszystkich przed beztroskim wyborem pinów nawet pod trywialne zadanie, jakim jest zapalanie i gaszenie diody led. Chciałem wypróbować działanie portów i wybrałem sobie piny P1.0, P1.1 i P1.2. Ustawiłem pracę pinów jako wyjście, w pętli głównej cyklicznie ustawiałem i zerowałem wyjścia - ale to tylko teoretycznie, na wyjściach cały czas wisiał potencjał zasilania.
    Szybka zmiana programu i wybór tych samych pinów portu P2 - zaskoczenie, bo program działa prawidłowo.
    Powrót do wcześniejszej wersji - nie działa :-(
    Internet, strona "mikrokontrolery.blogspot", zakładka o LPC1114, chwila lektury i wiadomo, że wyjścia, które beztrosko wybrałem domyślnie nie są ustawione jako porty we/wy, ale mają funkcję alternatywną - sprawa rozwiązana.
    Inna zagadka, to kolejność pinów wyprowadzonych w układzie - właściwie nie wiem, czemu łudziłem się, że będzie po kolei, jak np. w Atmega - a miała to być miła przesiadka z ośmiobitowca :-)
    Pozdrawiam,
    Rumcajs

    OdpowiedzUsuń