Funkční kód pro TFT displej s řadičem HX8743

Nemá te někdo zkušenosti jak rozchodit takovýhle displej?

Našel jsem sice několik inicializačních rutin - mimochodem každá nastavuje v registrech jiné hodnoty - a dalších funkcí (vykreslení tvarů, fonty…), ale nefunguje mi prakticky nic - jen při jedné se mi při inicializaci displej vybarví barvou naposledy použitou v nějaké funkci. Maximálně pak přes diplej problikávají různobarevné pruhy.

Byl bych velmi vděčen za jakýkoliv kód v C (atmel,PIC je to jedno) který ale máte odskoušený funkční.

:arrow_right: administrator: přesunuto z "Elektronika s mikrokontroléry, procesory"

cau, skusenosti s tim nemam ale resilo se to samy tady svetelektro.com/Forum/lcd-rd-wr-piny-t26521.html

MiloPS3: Ten displej HY32D používám, ale jeho řadič SSD1289 je bohužel nekompatibilní s dotazovaným HX8347-A, nedá se to použít.

aha, to se omlouvam,
tak mozna toto pomuze microchip.com/forums/m624935.aspx

Tak všechno je jinak

displej má místo deklarovaného HX8347 nejspíš SSD1289 - jediná inicializace co aspoň něco dělala se nápadně podobala té pro SSD1289.

Tak jsem si stáhl knihovnu - viz příloha - no něco to dělá, ale stejně je to nepoužitelné - třeba vyplnění celého displeje jednou barvou funguje tak do půlky - obdélník má jiné rozměry a je jinde a pod. takže je taky možné, že je tam třeba nějaký úplně jiný řadič možná nějaký ILI…

Navíc celá ta sranda zabere skoro 10k paměti.

Mohl bys tedy Pando poskytnout kód který pro SSD1289 používáš.
TFT240320 demo.zip (127 KB)

Tak jestli to je TFT240320, tak u toho se uvádí controller SSD1289, takže tím to bude snazší, k němu je celkem dost ukázkových zdrojáků na netu. Nemohu poskytnout svůj celý zdroják, protože je to firemní projekt, ale zkusím vypomoct v důležitých bodech.

Doporučuji odstavit grafické knihovny pro displej a začít od začátku, po malých krocích, jinak se to nerozjede. V knihovnách je příliš balastu který to znepřehledňuje.

  1. Nadefinovat si řídicí signály (podle schématu), na kterých portech je který řídicí pin připojený (čtecí signál RD jsem zatím nepotřeboval). Nadefinovat si makra pro ovládání řídicích signálů. Já to mám pro procesor ARM, pro zpřehlednění to upravím pro AVR, snad bude zřejmé převedení jinam. Pozor na polaritu, zda se signál zapíná stavem LOW nebo HIGH.

[code]// controll pins
#define LCD_CS_port PORTA /* chip select, active in 0 /
#define LCD_CS_bit 0
#define LCD_RS_port PORTA /
register select: 0=index or status, 1=control register /
#define LCD_RS_bit 1
#define LCD_RD_port PORTA /
read, active in 0 /
#define LCD_RD_bit 2
#define LCD_WR_port PORTA /
write, active in 0 /
#define LCD_WR_bit 3
#define LCD_RST_port PORTA /
reset controller, active in 0 */
#define LCD_RST_bit 13

// === LCD select INDEX mode
#define LCD_IndexMode() LCD_RS_port &= ~(1 << LCD_RS_bit)

// === LCD select DATA mode
#define LCD_DataMode() LCD_RS_port |= (1 << LCD_RS_bit)

// === LCD set CS signal ON
#define LCD_CS_ON() LCD_CS_port &= ~(1 << LCD_CS_bit)

// === LCD set CS signal OFF
#define LCD_CS_OFF() LCD_CS_port |= (1 << LCD_CS_bit)

// === LCD set WR signal ON
#define LCD_WR_ON() LCD_WR_port &= ~(1 << LCD_WR_bit)

// === LCD set WR signal OFF
#define LCD_WR_OFF() LCD_WR_port |= (1 << LCD_WR_bit)
[/code]

  1. Nadefinovat si výstup dat. Displej očekává 16-bitová data, zas je to upraveno pro AVR s připojením dat přes brány (ARM by dělal 1 zápis 16 bitů, AVR musí dělat 2 zápisy).

[code]#define LCD_DB_portL PORTB /* data bus LOW /
#define LCD_DB_portH PORTC /
data bus HIGH */

// output 16-bit data (unsigned short)
#define LCD_OutData(data) { LCD_DB_portL = data & 0xff; LCD_DB_portH = data >> 16; }[/code]

  1. Připravit si čekací prodlevu - v inicializaci je potřeba malé prodlevy (několik ms). Jestli není ověřeno tak si funkčnost ověřit např. intervalem blikání nějaké LED.

  2. Připravit si funkci na volbu registru řadiče. Řadič se přepne do indexového módu, na datovou sběrnici se zapíše číslo registru, nastaví se CS signál a vyšle se krátký WR impuls. Měl by mít délku alespoň 160 ns, u rychlých procesorů může být nutné přidat ještě nepatrnou prodlevu.

// === LCD select index void LCD_index(unsigned short index) { LCD_IndexMode(); // select INDEX mode LCD_OutData(index); // select register index LCD_CS_ON(); // chip select ON LCD_WR_ON(); // write pulse ON (160 ns) LCD_WR_OFF(); // write pulse OFF LCD_CS_OFF(); // chip select OFF }

  1. Připravit si funkci pro zápis dat do registru. Podobně, jen se volí datový mód.

// === LCD set data of register void LCD_data(unsigned short data) { LCD_DataMode(); // select DATA mode LCD_OutData(data); // output data LCD_CS_ON(); // chip select ON LCD_WR_ON(); // write pulse ON (160 ns) LCD_WR_OFF(); // write pulse OFF LCD_CS_OFF(); // chip select OFF }

  1. Funkce pro zápis hodnoty jednoho registru.

// === LCD write register void LCD_WriteReg(unsigned char reg, unsigned short data) { LCD_index(reg); LCD_data(data); }

  1. Inicializace displeje. Jednak je potřeba nastavit řídicí a datové piny procesoru na výstup a jednak je třeba inicializovat registry řadiče. Opět upraveno jako příklad pro AVR. Na rozdíl od jiných příkladů inicializuju registry tabulkou. Po každém registru je čekání 2 ms, jen po registru 0x10 je čekání 50 ms. Hodnotu registru 0x11 mám uchovanou stranou, protože ten je potřeba později často měnit - nastavení módu adresace (otáčení displeje) a přepínání mezi 16 a 24 bitovým výstupním módem. Inicializační rutina se volá při startu procesoru.

[code]// current register 11h
#define REG11h 0x6870
unsigned short Reg11h = REG11h;

// === LCD write register with delay

const unsigned short LCD_init_tab] = {
0x0007,0x0021, // display control
0x0000,0x0001, // oscillation start
0x0007,0x0023, // display control
0x0010,0x0000, // sleep mode
0x0007,0x0033, // display control
0x0011,REG11h, // entry mode
0x0002,0x0600, // LCD driving waveform control
0x0012,0x6CEB,
0x0003,0xA8A4, // power control 1
0x000C,0x0000, // power control 2
0x000D,0x080C, // power control 3
0x000E,0x2B00, // power control 4
0x001E,0x00B0, // power control 5
0x0001,0x2b3F, //RGB // output control
0x0005,0x0000, // compare register 1
0x0006,0x0000, // compare register 2
0x0016,0xEF1C, // horizontal porch
0x0017,0x0103, // vertical porch
0x000B,0x0000, // frame cycle control
0x000F,0x0000, // gate scan start position
0x0041,0x0000, // vertical scroll control 1
0x0042,0x0000, // vertical scroll control 2
0x0048,0x0000, // first window start
0x0049,0x013F, // first window end
0x004A,0x0000, // second window start
0x004B,0x0000, // second window end
0x0044,0xEF00, // horizontal RAM address position
0x0045,0x0000, // vertival RAM address start position
0x0046,0x013F, // vertical RAM address end position
0x0030,0x0707, // gamma control 1
0x0031,0x0204, // gamma control 2
0x0032,0x0204, // gamma control 3
0x0033,0x0502, // gamma control 4
0x0034,0x0507, // gamma control 5
0x0035,0x0204, // gamma control 6
0x0036,0x0204, // gamma control 7
0x0037,0x0502, // gamma control 8
0x003A,0x0302, // gamma control 9
0x002F,0x12BE,
0x003B,0x0302, // gamma control 10
0x0023,0x0000, // RAM write mask 1
0x0024,0x0000, // RAM write mask 2
0x0025,0x8000,
0x004f,0x0000, // GDDRAM Y address counter
0x004e,0x0000, // GDDRAM X address counter
0xffff
};

///////////////////////////////////////////////////////////////////////////////
// initialize LCD display (called during system startup)

void LCD_Init(void)
{
const unsigned short* t;

// set control registers to output mode
DDRA |= 0x0F;
PORTA |= 0x0F;
DDRB = 0xFF;
DDRC = 0xFF;

t = LCD_init_tab;
while (*t != 0xffff)
{
	LCD_WriteReg(t[0], t[1]);
	_delay_ms((t[0] == 0x10) ? 50 : 2);
	t += 2;
}

}[/code]
… když tak budu pokračovat dalším

Dík moc za vyčerpávající odpověď - teď to budu muset ale na pár dní opustit - dám ale hned jak to bude možné vědět jak jsem dopadl - jenom ještě otázka - jak by se měl displej chovat po správné inicializaci - co na něm bude vidět?

S tím co používám teď se po incializaci do určité doby objeví poslední stav - asi to tam drží nějaká kapacita - když to je po delší době , tak se objeví takový “šum” - jednotlivé body svítí různými barvami - případně se obraz skládá z různobarevných proužků o síle jednoho bodu.

Pokud se objeví šum nebo starý obraz, tak to je dobrá známka, že se displej rozběhl. Obsah paměti není inicializovaný, takže je v pořádku že zůstává starý stav. Doplnil bych ještě nějaké pokračování.

Při zápisu obrazových dat je možné zapisovat grafické body 16-bitově (5 nejnižších bitů modrá, 6 vyšších bitů zelená a 5 nejvyšších bitů červená složka) nebo 24-bitově (na 2 zápisy, nejdříve nižších 8 bitů zelená, vyšších 8 bitů červená, a druhý zápis 8 bitů modrá a vyšších 8 bitů nevyužito). 24-bitů využívá sice jen 6 vyšších bitů z každé barevné složky, ale lze tak snadno zapisovat 24-bitový obrazový buffer a červená a modrá složka využijí o 1 bit více než v 16-bitovém módu. Barevný mód určuje bit 13 registru Reg11h.

// set 24-bit interface void LCD_RGB24(void) { u16 r; r = Reg11h; r &= ~(1 << 13); if (r != Reg11h) { Reg11h = r; LCD_WriteReg(0x0011, r); } } ... analogicky LCD_RGB16(void)...

Před zápisem gafických dat je potřeba nastavit výstupní okno, kam se bude vykreslovat. Definuje se počáteční adresa ve videopaměti, počátek a konec okna a případně způsob adresování. Tímto způsobem lze snadno otáčet displej (ve 4 směrech), pouze nastavením hw registrů.

[code]// === set LCD write address
#define LCD_Addr(x,y) { LCD_WriteReg(0x4e, (x)); LCD_WriteReg(0x4f, (y)); }

// set address mode (hinc/vinc=horizontal/vertical increment, vfirst=change vertical first)
void LCD_SetAddrMode(bool hinc, bool vinc, bool vfirst)
{
u16 r;
r = Reg11h & ~((1<<5) | (1<<4) | (1<<3)); // ID1, ID0, AM
if (vinc) r |= (1<<5); // ID1
if (hinc) r |= (1<<4); // ID0
if (vfirst) r |= (1<<3); // AM
if (r != Reg11h)
{
Reg11h = r;
LCD_WriteReg(0x0011, r);
}
}

// set output window
void LCD_SetWindow(u16 x, u16 y, u16 w, u16 h)
{
switch (DispRot)
{
case DISP_ROT0:
LCD_SetAddrMode(TRUE, TRUE, FALSE);
LCD_WriteReg(0x44, ((x+w-1)<<8) | x);
LCD_WriteReg(0x45, y);
LCD_WriteReg(0x46, y+h-1);
LCD_Addr(x, y);
break;

… analogicky rotace 90, 180 a 270.[/code]

Je dobré začít vymazáním obdélníku jednou barvou, např. 16-bitovou.

[code]// display rectangle
void LCD_Rect(u16 x, u16 y, u16 w, u16 h, u16 color)
{
u32 i;

LCD_RGB16();		// set 16-bit interface

LCD_SetWindow(x, y, w, h); // set output window

LCD_index(0x22);	// budou se zapisovat data do GRAM
LCD_DataMode();		// select DATA mode
LCD_OutData(color); 	// output value
LCD_CS_ON();		// chip select ON

for (i=w*h; i>0; i--)
{
	LCD_WR_ON();
	LCD_WR_ON();		// prodlouzeni impulsu WR
	LCD_WR_OFF();
}

LCD_CS_OFF();		// chip select OFF

}[/code]

Při zobrazení obdélníku byla barva stejná, proto ji stačilo nastavit na výstup pouze jednou, před smyčkou. Při vykreslování obrázku je potřeba nastavovat grafická data uvnitř při každém průchodu smyčkou - data se načítají z ukazatele obrázku (v RGB nebo 16-bitovém módu). Pokud se vykresluje výřez, je třeba po každé lince posunout ukazatel dat na další linku, ale registry řadiče není třeba už nastavovat, řadič posune ukazatel sám na další linku v okně.

Tak už si maluju barevné obdélníčky a čverečky - musel jsem ještě do tvé inicializace doplnit reset chipu - ale je tu trochu problém - do parametrů funkce nemůžu pro osu x zadat větší hodnotu než 204 - při 205 a více se funkce nevykoná. Osa y v pohodě do 320.

KOntrolna otazka, ako rychlo je mozne vykreslovat na displej, asi to nebude pouzitelne ako LCD pre vykreslovanie vybudenia na jednotlivych frekvenciach s plynulym pochybom…

Já myslím že to by stíhalo bez problémů. Bude záležet na procesoru jak bude rychlý. Na STM 50 MHz když tahám po obrazovce nějakým prvkem, tak pohyb je úplně plynulý, bez zadrhání. Rychlé střídání pozadí (tj. přenesení kompletního obrazu 320x240) blikalo asi 10-20 fps. S AVR by to bylo asi trochu pomalejší. Ale u indikátoru vybuzení by se zobrazovaly sloupce, nekreslila by se celá obrazovka, tak by to mohlo také docela stíhat. Víc bude asi zpomalovat výpočet spektrální analýzy - proto by se asi víc hodil ARM jako např. LPC1114FN28, pro rychlejší výpočty (32 bitů).

ZAujimave, pripadne by som FFT ozelel a dam llen vybudenie kanalov, a co sa tyka citatelnosti, lebo graficky displej co tam mama teraz… je viac menej citatelny z pohladu 6 hodin, a vecinou na to pozeram bud kolmo a uz mi preblikuje text kedze je posuvany z prava do lava, Tak že hovoris ze by to šlo, len by to potrebovalo vela vyvodov k displeju aby to bolo rychle…

pozera mze ich na ebay je viacj viac menej sa lisia cenou, podla coho mam vybrtat ?

Já jsem vybíral podle ceny - ten nejlevnější - to stejně dělá jeden, dva a těch dvacet dalších s tím jenom kšeftuje.

Jinak se moc nedá věřit tomu co k tomu píšou - já jsem schválně objednával tam co bylo napsáno, že má řadič HX8743 - protože jsem na to našel kompletní projekt pro pic 18f4580, který mám doma - tak jsem si říkal, že to zapojím podle něho, nahraju hex a že to pošlape - jenže ejhle - ono to má řadič ssd1289 - no aspoň, že sedí konektor - těch je taky několik různých zapojení.

Co se týká rychlosti - to co se mi daří zatím zobrazovat - max 320x204 bodů trvá při 8MHz, na které to zkouším tak asi 500 ms - na nějaký reálný pohyb to teda rozhodně není, ale nějaké proužky by to při 20 mega mohlo stíhat.

měl bych dva dotazy

  1. u toho displeje je napsáné ovládání podsvícení PWM, tak by mě zajímalo kolik by měla být tak základní frekvence?

2)mám ARM 48MHz které nemá vyvedéné 16bitů vedle sebe na jednom portu, takže stejně nebudu moci zapisovat na 1x bez nějakého bitového posunu a tak…tak mě ještě i z duvodu ušetření nějakého toho pinu napadlo použit dva 8bitové buffery(transceiver), a vždy zapsal nejdřív do jednoho a pak do druhého a pak to překlopil navýstup…nebo použití posuvných registrů…nemáte někdo představu jak moc by to zpomalilo celou komunikaci a tím i rychlost displeje?

Ten displej má možnost i 8-bitového rozhraní, takže není potřeba používat své buffery (rychlost by byla stejná, jen je potřeba při startu synchronizovat pořadí bajtů). Samozřejmě je to dost pomalejší než 16-bitově, takže musí nastoupit software a zapisovat efektivně jen změněné oblasti. Ale pokud je možnost zapisovat 16-bitově i za cenu nějakých rotací, bylo by to rozumnější - protože např. při vymazání plochy jednou barvou není třeba měnit obsah datových registrů a tak to může být rychlé, ale při 8-bitovém zápisu by se musela data odesílat pro každý bod zvlášť, což je podstatně pomalejší.

tak asi vyzkousim ten 16bit s rotací…zatím ještě čekám než dorazí displej…
jinak mám právě od minulého týdne tohle:
freescale.com/webapp/sps/sit … FRDM-KL25Z

a chtěl bych právě rozjet tohle:
freescale.com/webapp/sps/sit … ?code=EGUI

tak už mi došel ten displej, tak si začnu hrát…nevíte někdo kolik to má odběr, jde mi o to jestli to utáhnu z USB ?