Инициализация TFT дисплея на примере SSD1289 для AVR.

Инициализация TFT дисплея на примере SSD1289 для AVR.

На днях пришёл TFT дисплей, заказанный на али, давайте рассмотрим его основные характеристики.
Инициализация TFT дисплея на примере SSD1289 для AVR.

Основные характеристики дисплея:
  • 3,2 дюйма, с разрешением 320х240
  • драйвер TFT дисплея - SSD1289, драйвера сенсорной панели - XPT2046
  • управление TFT по протоколу 6800, 8080, поддержка FSMC
  • интерфейс управления сенсорной панелью SPI
  • напряжение питания 5V или 3.3V, благодаря встроенному понижающему стабилизатору
  • возможность управления подсветкой с помощью ШИМ
  • встроенный разъем для SD card
  • свободное место для пайки FLASH памяти
  • поддерживает горизонтальную и вертикальную ориентацию, возможность отображения нескольких окон
  • глубина цвета: 18бит (262 144 комбинаций)

В качестве управляющего микроконтроллера возьмем Atmega16. Готовые примеры инициализации искать не стал, решил разобраться как он работает и написать свою. Для начала разберёмся с интерфейсом подключения. Общение с контроллером SSD1289 может происходить по 1 из 4 интерфейсов: i8080, M6800, RGB, SPI, но чтобы мы не мучились, не зная какой выбрать, производитель модуля помог нам. Он оставил на выбор два 16 битных интерфейса: интеловский i8080 и мотороловский M6800. i8080 и M6800 — параллельные интерфейсы, которые могут работать в 18/16/8-разрядном режиме. Выбор пал на i8080, хотя судя по даташиту он отличается от M6800 только тем, что у i8080 сигналы записи (WR) и чтения (RD) раздельные, а у M6800 же сигнал управления направлением RD/WR один, но дополнительно к нему есть сигнал разрешения E.
Теперь давайте посмотрим на распиновку модуля.
Инициализация TFT дисплея на примере SSD1289 для AVR.

Выводы питания.
VCC – напряжение питания модуля. Внутри модуля находится стабилизатор напряжения на 3.3V, от которого питаются графический контроллер(SSD1289), контроллер резистивного сенсорного экрана(XPT2046) и SD карта. Наличие стабилизатора позволяет подавать на модуль питание равное 5V. Но обмен информацией между микроконтроллером и модулем должен проходить с помощью 3.3V. У меня в схеме модуль и микроконтроллер питаются одним напряжением — 3.3V, что обеспечивает нормальный обмен данными.При таком напряжении питания микроконтроллер нормально работает на частоте 8MHz. Да, кстати, я подавал 5 вольт на микроконтроллер и модуль, мне повезло ничего не сгорело и все работало, но так делать не стоит.
GND – общий вывод (земля).
LED-A – анод подсветки TFT дисплея, необходимо подключать через токоограничивающий резистор, при питании 3,3V подключил через 200 Оhm.

Выводы управления графическим контроллером.
[DB15, DB0] (Data Bus) – 16-разрядная шина данных/команд.
RS (Register Select) –пин с помощью которого можно переключаться между регистрами данных (GRAM) и регистрами команд (Instruction Registers), в даташите он называется D/C.
WR (Write) – строб записи данных/команд.
RD (Read) – строб чтения данных/параметров.
REST (Reset) – сброс графического контроллера.
CS (Chip Select) – активация/дезактивация графического дисплея.

Общая схема подключения TFT дисплея изображена ниже.
Инициализация TFT дисплея на примере SSD1289 для AVR.


Теперь надо разобраться как отправить SSD1289 команды/данные, для этого давайте посмотрим на картинку ниже.
Инициализация TFT дисплея на примере SSD1289 для AVR.

На картинке видно, что это можно сделать двумя способами, мы реализуем первый.
Для того чтобы отправить команду надо выполнить следующую последовательность действий:
  • на ножке D/C выставляем ноль говорим, что будем слать команду
  • на ножке RD выставляем единицу, чтобы точно записывать
  • активируем чип, устанавливая на ножке CS нуль
  • выдаем на шину данные, в нашем случае это два порта
  • на ножке WR выставляем единицу
  • ждем несколько микросекунд
  • на ножке WR выставляем нуль
  • на ножке CS выставляем единицу, деактивируем чип

Для того чтобы отправить данные надо выполнить следующую последовательность действий:
  • на ножке D/C выставляем единицу говорим, что будем слать данные
  • на ножке RD выставляем единицу, чтобы точно записывать
  • активируем чип, устанавливая на ножке CS нуль
  • выдаем на шину данные, в нашем случае это два порта
  • на ножке WR выставляем единицу
  • ждем несколько микросекунд
  • на ножке WR выставляем нуль
  • на ножке CS выставляем единицу, деактивируем чип

Ниже реализация отправки команд/данных на С.

#define D0 PORTA           //так данные передаются по 16 битной шине,
#define D7 PORTD           //под это дело мы используем два порта

#define COMMAND_PORT PORTB  //управляющий порт

#define lcd_dc 0            //так же может называться RS(comm - 0; data - 1)
#define lcd_res 1           //(active - 0)
#define lcd_rd 2	         //(read_active - 0)
#define lcd_cs 3             //(chip_select_active - 0)
#define lcd_wr 5	         //(write_active - 0)
void Lcd_Write_Index(uint16_t index)
{
	COMMAND_PORT &= ~(1<<lcd_dc);            //будем слать команду
	COMMAND_PORT |= (1<<lcd_rd);	          //выставляем на ножке, отвечающей за чтение 1
                                                                                  
	COMMAND_PORT &= ~(1<<lcd_cs);            //активируем чип
	
	D0 = (index & 0X00FF);	                               //через D0 шлем младший байт
	D7 = (index & 0XFF00)>>8;		               //затем через D7 старший
	
	COMMAND_PORT &= ~(1<<lcd_wr);	        //теперь стробируем битом записи
	_delay_us(5);
	COMMAND_PORT |= (1<<lcd_wr);
	
	COMMAND_PORT |= (1<<lcd_cs);	               //деактивируем чип
}
////////////////////////
void Lcd_Write_Data(uint16_t data)        //все то же самое только DC устанавливаем в единицу
{
	COMMAND_PORT |= (1<<lcd_dc) ;
	COMMAND_PORT |= (1<<lcd_rd);
	COMMAND_PORT &= ~(1<<lcd_cs);
	
	D0 = (data & 0X00FF);
	D7 = (data & 0XFF00)>>8;
	
	COMMAND_PORT &= ~(1<<lcd_wr);
	_delay_us(5);
	COMMAND_PORT |= (1<<lcd_wr);
	
	COMMAND_PORT |= (1<<lcd_cs);
	
}
/////////////для записи данных в регистры напишем простенькую функцию
void Lcd_Write_Reg(uint16_t lcd_reg, uint16_t lcd_data)                  
{
	COMMAND_PORT &= ~(1<<lcd_cs);
	Lcd_Write_Index(lcd_reg);
	Lcd_Write_Data(lcd_data);
	COMMAND_PORT |= (1<<lcd_cs);
}


С подключением разобрались теперь переходим к инициализации. Открываем даташит и находим странницу, на которой описан порядок инициализации.
Инициализация TFT дисплея на примере SSD1289 для AVR.

Для того чтобы инициализировать контроллер SSD1289 надо записать в регистр R07, значение 0021h , выставив, таким образом, GON = 1, DTE = 0, D[1:0] = 01, что делают эти биты рассматривать не будем, пока это значения не имеет.
Инициализация TFT дисплея на примере SSD1289 для AVR.

На следующем шаге включаем тактирование, установив в регистр R00 значение 0001h. Кстати, если после инициализации прочесть данные с этого регистра, в случае успешной инициализации должно вернуться 8989h.
Инициализация TFT дисплея на примере SSD1289 для AVR.

Далее, снова возвращаемся в R07 и устанавливаем значение 0023h.
Следующим шагом выходим из спящего режима, устанавливая в R10 значение 0000h.
Инициализация TFT дисплея на примере SSD1289 для AVR.

Ждём 30 миллисекунд. Устанавливаем в регистр R07 значение 0033h. Далее, в регистр R11 устанавливаем значение 6838h, давайте рассмотрим, что означают эти цифры.
POR - это значение по умолчанию и оно равно 6830h. Значит, по умолчанию дисплей может отображать 65K цветов, за это отвечает первая цифра 6 в значении 6830h, это надо запомнить так дальше при формировании цвета мы к этому ещё вернёмся.
Инициализация TFT дисплея на примере SSD1289 для AVR.

Инициализация TFT дисплея на примере SSD1289 для AVR.

Дальше мы определяем порядок записи точек, дело в том, что нам для вывода изображения достаточно выставить координаты только первой точки, далее, надо отправлять SSD1289 только цвет следующей точки, а он сам будет её отрисовывать по алгоритму, который мы сейчас выберем. И вот здесь, точно сказать почему нельзя, при таких настройках включился режим, отмеченный зелёным кружком, а должен был включиться отмеченный красным.
Инициализация TFT дисплея на примере SSD1289 для AVR.

Значение в регистре R02 оставим по умолчанию и на этом закончим инициализацию.
Теперь все то, что рассмотрели оформим в виде кода.

#define lcd_res 1  //(active - 0)
void Init()
{
	_delay_ms(100);    //не большая задержка после включения
	COMMAND_PORT |= (1<<lcd_res);   //устанавливаем reset в 1, чтобы включился SSD1289 
	
	Lcd_Write_Reg(0X0007, 0X0021);   //далее записываем в регистры значения
	Lcd_Write_Reg(0X0000, 0X0001);
	Lcd_Write_Reg(0X0007, 0X0023);
	Lcd_Write_Reg(0X0010, 0X0000);
	_delay_ms(30);
	Lcd_Write_Reg(0X0007, 0X0033);
	Lcd_Write_Reg(0X0011, 0X6838);
	Lcd_Write_Reg(0X0002, 0X0600);
	
}

Если последовательно выполнить все описанные действия, в случае успешной инициализации, экран хаотично раскраситься разноцветными точками, как на фото ниже.
Инициализация TFT дисплея на примере SSD1289 для AVR.

Теперь мы знаем как инициализировать TFT дисплей на котором установлен контроллер SSD1289, в следующей статье мы рассмотрим как выводить отдельные символы и писать строки. Также в конце следующей статьи можно скачать пример для Atmel Studio 6.2.

P.S там где покупал дисплей больше не продают, в комментариях Андрей оставил ссылку на дисплей, который у него запустился, чтобы не искать, оставлю её тут.
Display_ebay

P.S.S для желающих быстро проверить работает ли их дисплей, оставляю тут прошивку для Atmega16 ssd1289_i8080.hex [5,75 Kb] (cкачиваний: 400)
комментарии
16