Logo STV tomto článku si řekneme něco o GPIO, tedy I/O portech. Ukážeme si, jaké všechny možnosti máme, a co všechno musíme nastavit. Nakonec si zablikáme diodou a zároveň pohrajeme s tlačítkem.

GPIO (General-purpose Input/Output) jsou vstupně výchozí porty vyvedené ven z pouzdra a jdou tedy tím prvním, čím prochází signály. STM32F40xx obsahuje hned 9 portů, každý s 16. piny (devátý jich má jedenáct). Jednotlivé porty jsou označeny písmeny AI (takže pokud se mluví o GPIOx, je myšleno obecně nějaký port a pokud o GPIOB, tak se mluví o portu B). U každého pinu pak lze nastavit velké množství vlastností:

  • Vstupní/výstupní
  • Digitální/Analogový
  • IO/Alternativní funkce (třeba vstup DA převodníku, výstup PWM modulu…)
  • Maximální frekvence
  • Dvojčinný nebo otevřený kolektor
  • Připojení pull-up nebo pull-down rezistorů

Všechny piny jsou 5V tolerantní. V příkladu si pak ukážeme blikání diody, jeden pin nastavíme jako digitální výstupní a využijeme i tlačítko na kitu, jeden pin nastavíme jako digitální vstupní. Pro jejich nastavení existuje hned několik registrů, které si popíšeme (všechny registry jsou 32bit, ale u některých není využito všech 32 bitů).

 

Registry

GPIOx_MODER (mode register)
Jedná se o 32bit registr, kde vždy dvěma sousedními bity nastavíme mód pinu. Tedy pokud bychom chtěli nastavit pin 2 portu B, upravíme 4. a 5. bit registru GPIOB->MODER. Pro nastavení pinu 12 portu D, upravíme 24. a 25. bit registru GPIOD->MODER.
(pozn.: čísla pinů i pozice bitů v registru se počítají od nuly, tedy nultá pozice, první pozice …) 

  • 00 – Input (pin bude vstupní)
  • 01 – Output (pin bude výstupní)
  • 11 – Analog (pin bude analogový vstup)
  • 10 – Alternate function (pin bude sloužit k alternativní funkci, například bude připojen k jiné periferii v procesoru)
     

GPIOx_OTYPER (output type register)
V podstatě je to 16bit registr (ve skutečnosti je to 32bit registr, ale je využito jen spodních 16 bitů). Každý bit tedy přísluší jednomu pinu daného portu. Pin 2 nastavíme pomocí bitu 2. Registrem určujeme, zda bude výstupní pin dvojčinný nebo s otevřeným kolektorem (pro pochopení je třeba mít trochu znalostí s číslicové elektroniky, začátečníci nejčastěji budou využívat dvojčinné zapojení).

  • 0 – Push-pull (dvojčinný)
  • 1 – Open-drain (otevřený kolektor)
     

GPIOx_OSPEEDR (output speed register)
Také 32bit registr. Opět dvojce bitů přísluší jednomu pinu. Pomocí toho registru lze nastavit maximální frekvenci výstupního signálu (samotný procesor je natolik rychlý, že by výstupní frekvence mohla být velmi vysoká, ovšem to je při delších vedeních nevyhovující a delším vedením lze pro vysoké frekvence považovat i vodič délky pár centimetrů). Ovšem snížení frekvence znamená i prodloužení doby náběžné a sestupné hrany. To ale také znamená menší dodávaný proud a tím i ušetřená energie.

  • 00 – Low speed (2MHz)
  • 01 – Medium speed (25MHz)
  • 10 – Fast speed (50MHz)
  • 11 – High speed (100MHz)
     

GPIOx_PUPDR (pull-up pull-down register)
Opět 32bit registr. Lze nastavit připojení pinu přes rezistor k HIGH nebo LOW úrovni. Tedy pro nás to znamená, jestli bude pin připojen přes rezistor k napájecímu napětí nebo k zemi.

  • 00 – Źádné rezistory
  • 01 – Pull-up (rezistor na napájecí napětí)
  • 10 – Pull-down (rezistor na zem)
  • 11 – nevyužitá kombinace
     

GPIOx_IDR (input data register)
16bit registr obsahující údaj o logické hodnotě na vstupních pinech daného portu. Pin musí být nastaven jako vstupní digitální. Tedy jaká logická úroveň se nachází například na pinu 3 portu E, zjistíme z třetího bitu registru GPIOE->IDR.

 

GPIOx_ODR (output data register)
Také 16bit registr. Naopak od IDR registru, do tohoto zapisujeme hodnoty, jaké chceme mít na výstupu daného pinu. Pin musí být nastaven jako digitální výstupní. Pokud chceme mít logickou úroveň HIGH na pinu 14 portu D, zapíšeme logickou jedničku na 14. bit registru GPIOD->ODR.

 

GPIOx_BSRR (bit set reset register)
32bit registr, sloužící také k nastavení logické hodnoty na výstupních pinech. Registr je rozdělen na dvě části. Dolních 16 bitů se nazývá BSR (S jako Set) a zapsáním logické jedničky na příslušnou pozici se nastaví příslušný pin na hodnotu HIGH. Horních 16 bitů se naopak nazývá BRR (R jako Reset) a zapsáním logické jedničky na příslušnou pozici se nastaví příslušný pin na hodnotu LOW.

 

GPIOx_LCKR (lock register)
17bit registr, kterým lze zabezpečit nastavení portů a jejich pinů. Prvních 16 bitů určuje, zda bude nebo nebude nastavení pinu uzamknuto a 17. bit pak aktivuje samotnou ochranu (je třeba dodržet výrobcem stanovenou sekvenci zápisů, více najdete v dokumentaci výrobce). Po uzamknutí již nelze měnit jakákoliv nastavení portů včetně samotného registru LCKR a to do doby resetu celého procesoru.

 

GPIOx_AFRL  a GPIOx_AFRH (alternate function low / high register)
32bit registr, kde každému pinu přísluší 4 bity. Proto je nutné toto nastavení rozdělit do dvou registrů. Tedy bity 0-3 nastavují nultý pin, bity 4-7 nastavují první pin … Pro uplatnění tohoto nastavení je třeba mít v registru MODER zvolenou alternativní funkci. Registr AFRL obsahuje nastavení portů 0 až 7 a registr AFRH nastavení portů 8 až 15. Alternativních funkcí je patnáct a každé odpovídá jedna kombinace čtyř bitů. Jaká alternativní funkce se skrývá pod danou kombinací najdete v dokumentaci.

  • 0000 – AF0
  • 0001 – AF1
  • 1110 – AF14
  • 1111 – AF15

     

První program

Nyní se už konečně podíváme na samotný kód programu, kde si nejdříve diodu rozsvítíme.

Dodávám, že pro úspěšné programování a pochopení je potřeba alespoň základní znalost jazyka C. Především štábní kultura, datové typy (pro práci s registry je třeba znát struktury), klíčová slova jazyka C, operátory, bitové operace a tvoření funkcí, cyklů, podmínek... Do dalších částí tutoriálu se určitě bude hodit znalost pointerů (ukazatelů), znalost binární (dvojkové) a hexadecimální (šestnáctkové soustavy). Už při práci s registry bude třeba vědět jak a který bit někam posunou či uložit, vyfiltrovat…

K napsání programu využijeme prázdný projekt, který jsme si vytvořili v předešlém článku. Napíši nejdříve celý kód a pak popíši co jednotlivé řádky znamenají. Podle schématu kitu Discovery je modrá dioda připojen na pin 15 portu D.
 

#include<stm32f4xx.h>

int main(void)
{
	/* Reset portu GPID */
	RCC->AHB1RSTR |= RCC_AHB1RSTR_GPIODRST;
	RCC->AHB1RSTR &= ~(RCC_AHB1RSTR_GPIODRST);
	/* Povoleni hodin pro GPIOD */
	RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN;
	
	/* Nastaveni modu */
	GPIOD->MODER |= GPIO_MODER_MODER15_0;	//nastavení pinu 15 jako výstupní
	/* Nastaveni max. frekvence */
	GPIOD->OSPEEDR = GPIO_OSPEEDER_OSPEEDR15;	//maximální frekvence 100MHz
	
	/* Rozsviti modrou LED */
	GPIOD->ODR = GPIO_ODR_ODR_15;
	
	while(1);
}


Na prvním řádku includujem hlavičkový soubor. Obsahuje všechny potřebné definice a deklarace struktur pro přístup k registrům. Na třetím řádku začíná samotná hlavní funkce main.

Na šestém až devátém řádku resetujeme periferii GPIOD a povolíme hodniny. V MCU s jádrem ARM jsou hodiny pro všechny periferie zakázány. Rozumí se tím, že hodinový signál do periferií není zaveden a dalo by se říct že periferie je vypnutá (je ve sleep modu). Má to tu výhodu, že nepotřebné periferie, bez zavedených hodin mají mnohonásobně menší spotřebu energie. O registrech nastavení hodin a taktování jádra si povíme v některém z dalších článků.

Dále pak nastavujeme mód na výstupní pomocí GPIO_MODER_MODER15_0. Pokud nahlédneme do souboru stm32f4xx.h (kde je definice) na řádek 4309, zjistíme, že se jedná o hodnotu 0x40000000. Binárně by se vyjádřila jako:

0b 0100 0000 0000 0000 0000 0000 0000 0000

Pinu 15 přísluší 30. a 31. Bit, poslední dva (čísla čteme zprava do leva). Takže pin 15 nastavujeme kombinací 01 což je nastavení pro výstupní pin.

Pak nastavujeme maximální frekvenci na 100MHz pomocí GPIO_OSPEEDER_OSPEEDR15_1. Opět v souboru stm32f4xx.h na řádku 4393 najdeme, že tomu odpovídá hodnota 0x80000000. Binárně vyjádřené:

0b 1100 0000 0000 0000 0000 0000 0000 0000

Tedy pro nastavení rychlosti pro pin 15 je použita kombinace 11 a ta odpovídá nastavení 100MHz.

Posledním zápisem do registru na řádku 17 je zapsání logické hodnoty 1 na patnáctou pozici registru ODR. Definici GPIO_ODR_ODR_15 najdeme v souboru stm32f4xx.h na řádku 4511 a zjistíme, že zapisovanou hodnotou je 0x8000. Binárně vyjádřené:

0b 1000 0000 0000 0000

Poslední patnáctý bit je nastaven na hodnotu 1, takže patnáctý pin portu D bude nastaven do logické jedničky. To znamená že se fyzicky na pinu 15 objeví napětí 3V, což rozsvítí modrou diodu.

Poslední je cyklus while, kde podmínkou je logická jednička. Takže vznikne nekonečný cyklus. Po nahrání programu do procesoru se pouze rozsvítí modrá LED dioda.
 

Tlačítko na vstupním pinu

Nyní tedy svítí modrá LED dioda, ale koukat jen na rozsvícenou diodu může být nuda. Takže přidáme ještě červenou diodu (ta je připojena na pin 14 portu D) a obě diody, modrou i červenou, budeme střídavě rozsvěcet a zhášet pomocí tlačítka (tlačítko je připojeno na pin 0 portu A).

Aby kód programu byl přehledný, tak veškeré nastavení portů dáme do samostatných funkcí, které na začátku funkce main zavoláme.
 

#include<stm32f4xx.h>

void GPIOD_conf(void)
{
	/* Reset portu GPID */
	RCC->AHB1RSTR |= RCC_AHB1RSTR_GPIODRST;
	RCC->AHB1RSTR &= ~(RCC_AHB1RSTR_GPIODRST);
	/* Povoleni hodin pro GPIOD */
	RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN;
	
	/* Nastaveni modu */
	GPIOD->MODER |= GPIO_MODER_MODER15_0 | GPIO_MODER_MODER14_0;	//nastaveni pinu 15 a 14 jako výstupní
	/* Nastaveni max. frekvence */
	GPIOD-OSPEEDR = GPIO_OSPEEDER_OSPEEDR14 | GPIO_OSPEEDER_OSPEEDR15;	//maximalni frekvence 100MHz
	
	return;
}

void GPIOA_conf(void)
{
	/* Reset portu GPIA */
	RCC->AHB1RSTR |= RCC_AHB1RSTR_GPIOARST;
	RCC->AHB1RSTR &= ~(RCC_AHB1RSTR_GPIOARST);
	/* Povoleni hodin pro GPIOA */
	RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
	
	/* Nastaveni modu */
	GPIOA->MODER |= 0x0;	//nastaveni pinu 0 jako vstupní
	/* Nastaveni max. frekvence */
	GPIOA->OSPEEDR = GPIO_OSPEEDER_OSPEEDR0;	//maximalni frekvence 100MHz
	
	return;
}

int main(void)
{
	GPIOD_conf();
	GPIOA_conf();
		
	while(1)
	{
		/* Pokud je tlacitko stiskle, rozsvit modrou LED a zhasni cervenou LED */
		if(GPIOA->IDR & GPIO_IDR_IDR_0)
		{
			/* Zhasne cervenou LED */
			GPIOD->ODR &= ~GPIO_ODR_ODR_14;
			/* Rozsviti modrou LED */
			GPIOD->ODR |= GPIO_ODR_ODR_15;
		}
		else
		{
			/* Zhasne modrou LED */
			GPIOD->ODR &= ~GPIO_ODR_ODR_15;
			/* Rozsviti cervenou LED */
			GPIOD->ODR |= GPIO_ODR_ODR_14;
		}
	}
}

 

Na řádku 3 až 17 je první funkce GPIOD_conf. Její obsah už známe. Pouze na řádku 12 je zápis do konfiguračního registru upraven a je přidáno pomocí binárního součtu nastavení pinu 14 jako výstupní (červená LED dioda).

Na řádku 19 až 33 je další funkce GPIOA_conf. Její obsah je podobný první funkci. Rozdíl je pouze  že nastavujeme port A a že na řádku 28 nastavujeme všechny piny (tedy i pin 0) jako vstupní.

Následuje už jen hlavní funkce main, kde na na začátku voláme obě předchozí funkce a v nekonečném cyklu while se opakovaně ptáme, jestli je tlačítko stisknuté. Logickou jedničku získáme, když je tlačítko stisknuté a naopak pokud není stisknuté, získáme logickou nulu. Tuto hodnotu najdeme v registru IDR. Pomocí logického součinu „vyfiltrujeme“ pouze nultý bit. Pokud je tento bit v logické jedničce, je zřejmě stisknuté tlačítko a podmínka je splněna. V opačném případě se vykoná blok za else. V obou blocích pak už jen zapisujeme do registru ODR, kde pomocí bitových operací upravujeme podle potřeby poslední dva bity (15. bit pro modrou a 14. bit pro červenou LED diodu).

Může si dále zkusit program ještě upravit a blikat i dalšími dvěma diodami. Napovím že jsou připojeny na piny 13 a 12 portu D.

Pokud vám přijde složité používat předdefinovaná makra, jako například GPIO_ODR_ODR_15, a nevidíte tak jaký bit upravujete, můžete místo těchto maker zapisovat vlastní hodnoty.
 

GPIOD->ODR = (1<<15);

 

V binární podobě je jednička zapsaná jako 0b1. Abychom ji dostali na poslední patnáctou pozici, provedeme binární posun doleva o patnáct pozic. Existuje několik dalších způsobů.

 

Závěr

Dnes jsme konečně napsali funkční program, co něco dělá. Dále například můžete k Discovery kitu připojit vlastní diody a tlačítka na jiné piny a porty a zkoušet napsat složitější programy (je třeba nahlídnout do schématu kitu, některé piny jsou již nějak využity). Příště se podíváme na hodinové signály a nastavení taktu hodin.


Projekt ke stažení ZDE.


Komentáře  

 
0 # jiri 2016-12-22 18:24
dobry den podle vašeho kodu jsem udelal svuj na stm32f0 a po třech hodinách hledání chyb proč mi to nejde jsem to zdal.zasílám kod

#include "stm32f0xx.h"



void GPIOC_conf(void)

{
//reset registru AHBRSTR
RCC->AHBRSTR |=RCC_AHBRSTR_G PIOCRST;//(1AHB ENR |= RCC_AHBENR_GPIOCEN;

//nastaveni modu
GPIOC->MODER |=GPIO_MODER_MO DER9_0 | GPIO_MODER_MODE R8_0;//(1ODR &= ~ GPIO_ODR_8;

GPIOC->ODR |= GPIO_ODR_9;
}
}




}
Odpovědět | Odpovědět citací | Citovat
 
 
0 # jiri 2016-12-22 18:25
#include "stm32f0xx.h"



void GPIOC_conf(void)

{
//reset registru AHBRSTR
RCC->AHBRSTR |=RCC_AHBRSTR_G PIOCRST;//(1AHB ENR |= RCC_AHBENR_GPIOCEN;

//nastaveni modu
GPIOC->MODER |=GPIO_MODER_MO DER9_0 | GPIO_MODER_MODE R8_0;//(1ODR &= ~ GPIO_ODR_8;

GPIOC->ODR |= GPIO_ODR_9;
}
}




}

to první byl omyl špatně mi funguje myš
Odpovědět | Odpovědět citací | Citovat