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

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