Produkty Novinky Články Návody Kontakty

SAM9260 a grafický TFT displej - 5. řadič SSD1963 a příprava ovladače

V uplynulých dílech jsem se věnoval výběru, koupi, zapojení a oživení TFT displeje. Tím vyvoleným se nakonec stal TFT displej INT070ATFT-TS připojený k procesorovému modulu SAM9260. Dalším krokem, který mě čekal, byla implementace jednoduchého ovladače TFT displeje, který by mi pomohl ověřit, že TFT displej kompletně funguje a že jsem schopen jej správně zinicializovat a přenášet do něj obrazová data.
Jak už jsem několikrát uvedl, TFT displej INT070ATFT-TS obsahuje integrovaný řadič displeje SSD1963, který je jakýmsi šikovným prostředníkem mezi mikrokontrolérem a samotným TFT panelem (= zobrazovadlem). Modul SAM9260 tak vlastně nekomunikuje přímo s TFT panelem, ale právě s tímto řadičem displeje. Ovládnout TFT displej tak vlastně znamenalo porozumět a naučit se nastavit a řídit řadič SSD1963. A to bude můj další cíl. Chcete vědět, jak to dopadlo? Čtěte dál!
V datasheetu řadiče displeje SSD1963 jsem se dozvěděl, že konfigurační registry se nastavují a připadně i vyčitají pomocí sady příkazů a jejich parametrů. Příkazy i parametry se přenáší po stejné datové sběrnici jako obrazová data. Jen s tím rozdílem, že příkazy a jejich parametry jsou vždy osmibitové, takže bez ohledu na šířku datové sběrnice se přenášejí jen po nejnižších osmi bitech datové sběrnice. Nemělo cenu se hned trápit celým seznamem příkazů, bylo evidentní, že prvním praktickým úkolem bude zvládnout samotnou komunikaci, tj. zápis/čtení osmibitové hodnoty do/z řadiče SSD1963.
Řadič SSD1963 nabízí hned dva režimy komunikace s mikrokontrolérem: režim 8080 a režim 6800. Oba režimy používají stejné řídící signály, liší se jen v jejich použití (označení) a časování. Pánové z Displaytechu mi usnadnili volbu - výchozí je režim 8080, ti co by chtěli režim 6800, musí na desce plošných spojů TFT displeje odpájet SMD odpor R4 a připájet odpor R19 s hodnotu 0 Ohmů. Hmm, děkuji, myslím, že mi režim 8080 bude zcela vyhovovat.
Časový průběh zápisu
Režim 8080 používá čtveřici řídících signálů označených jako: /CS (vývod č. 13) - chipselect, /RS (vývod č. 14) - data/command select, /RD (vývod č. 15) - read strobe a /WR (vývod č. 16) - write strobe. Časové průběhy řídících signálů při zápisu/čtení do/z řadiče jsou zobrazeny na obrázcích (zdrojem byl datasheet řadiče SSD1963, revize 1.3; tabulku s hodnotami jednotlivých časových intervalů najdete tamtéž). Potěšilo mě, že jsou definovány v podstatě jen minimální hodnoty časových intervalů a prodlev, takže se zdálo, že implementace režimu 8080 bude jednoduchá. S ohledem na časové intervaly v jednotkách nanosekund prostě jen dodržím posloupnost nastavení signálů do patřičné logické hodnoty. Jasně, musím si dát pozor na to, jak dlouho bude držet signál /WR, resp. /RD, aktivní. Ale to je jinak celé.
Časový průběh čtení
S čerstvě nabitými znalostmi jsem se ihned pustil do implementace ovladače pro Linux, resp. pro moji vlastní linuxovou distribuci, kterou jsem vytvořil pro modul SAM9260. Je postavena na jádře 2.6.38 s patchem at91 a patchem přidávajícím podporu modulu SAM9260.
Jako základ ovladače TFT displeje INT070ATFT-TS jsem využil ovladač pro znakový displej 2x16 znaků LCD1602. Chvíli jsem mazal a přejmenovával proměnné a funkce z lcd_neco na tft_neco. Nové tvorbě tak nějak vždy předchází destrukce.
První nově implementované funkce byly funkce read_raw() a write_raw(). Ty implementují základ cyklu čtení/zápisu. Tyto funkce jsou volány z nadřazených funkcí read_data(), write_data() a write_cmd(), které řídí signály /CS a /RS (nebo také D/C). Níže uvádím zdrojový kód pro ukázku cyklu zápisu:
static inline void write_raw(unsigned int value)
{ 	
	// orizneme na 16bit a posuneme zapisovanou hodnotu na PC16 - PC31 	
	unsigned int reg_val = (value & 0xFFFF) << 16;
	
	// shodime WR
	at91_set_gpio_value(TFT_nWR, 0);
	
	// na D0-D15 vystavime data
	pio_writel(PIO_ODSR, reg_val);
	
	// pockame min 12ns
	write_delay();
	
	// zapiseme data vytazenim WR na log. 1
	at91_set_gpio_value(TFT_nWR, 1);
}

static inline void write_data(unsigned int data)
{ 	
	// nastavime signal D/C (RS) na data 	
	at91_set_gpio_value(TFT_DC, 1);
	
	// aktivujeme chipselect
	at91_set_gpio_value(TFT_nCS, 0);
	
	// zapiseme data 	
	write_raw(data);
	
	// deaktivujeme chipset
	at91_set_gpio_value(TFT_nCS, 1);
}
Jak je vidět z kódu funkce write_raw(), nakonec jsem nic neriskoval a signál /WR nechávám aktivní minimálně předepsaných 12ns. Ve skutečnosti je to však více, protože funkce write_delay() je realizována pomocí assembleru - vkládám zde tři instrukce NOP v blahé naději, že jedna při taktu CPU 198MHz trvá přibližně 5ns.
Za pozornost stojí i skutečnost, že pro zápis hodnoty na datovou sběrnici (piny PC16PC31) využívám funkci ”synchronous data output”. Ta umožňuje nastavit najednou všechny zvolené I/O piny mikrokontroléru AT91SAM9260 do potřebné logické úrovně a to zápisem do registru PIO_ODSR. Normálně bych I/O piny do log. 1 nastavil zápisem do registru PIO_SODR, zatímco do log. 0 zápisem do registru PIO_CODR. To by znamenalo dvě operace zápisu pro jednu hodnotu zapsanou na výstupy mikrokontroléru. Takhle je to vše v rámci jedné operace zápisu. Piny, kterých se tato funkce má týkat, zvolíme v registru PIO_OWER.
static void write_delay(void)
{
	// cca 15ns 	
	asm volatile 
	(
		"NOP\n\t"
		"NOP\n\t"
		"NOP\n\t"
	);
}
Poslední věc, která stojí za zmínku, je inicializace portu PIOC v souladu se schématem zapojení, kdy dotčené I/O piny musíme patřičně nakonfigurovat, nejlépe v init funkci ovladače. Pro přehlednost uvádím i kód funkce init_pio().
static void __init init_pio(void)
{
	// vypneme u PIO pro LCD preruseni
	pio_writel(PIO_IDR, (TFT_CTRL_PINS_MASK | TFT_DB0_DB15_PIN_MASK));
	// vypneme u PIO pro LCD pullup odpory
	pio_writel(PIO_PUDR, (TFT_CTRL_PINS_MASK | TFT_DB0_DB15_PIN_MASK));
	// nastavime ridici signaly na log. 1
	pio_writel(PIO_SODR, TFT_CTRL_PINS_MASK);
	// nastavime data na log. 0 (prikaz NOP)
	pio_writel(PIO_CODR, TFT_DB0_DB15_PIN_MASK);
	// prepneme PIO pro TFT na vystupni PIO
	pio_writel(PIO_OER, (TFT_CTRL_PINS_MASK | TFT_DB0_DB15_PIN_MASK));
	// pro D0-D17 povolime zapis dat primo pres PIO_ODSR
	// lze tak zapisovat rovnou cele slovo, nicmene prenesou se jen ty bity,
	// ktere maji v masce 1 v PIO_OWER
	pio_writel(PIO_OWER, TFT_DB0_DB15_PIN_MASK);
	// prepneme piny pro TFT na funkci GPIO
	pio_writel(PIO_PER, (TFT_CTRL_PINS_MASK | TFT_DB0_DB15_PIN_MASK));
}
Málem bych zapomněl, kompletní zdrojový kód ovladače TFT displeje INT070ATFT-TS si můžete stáhnout z produktových stránek modulu SAM9260. To je pro dnešek vše. Inicializaci TFT displeje si nechám na další díl.

Seznam dílů seriálu SAM9260 a grafický TFT displej