Освоение STM32F103VE + TFT LCD + touch screen

Началось всё с покупки демо-платы и st-link на ebay. Когда пришла плата, я включил её, подивился китайской демкой на экране с различными тестами, графиками и крутилками.

демо-плата STM32F103VE

А потом я затёр всю прошивку. И экран погас… почти на год (я снова занялся AVR'ками).

Когда появились статьи про STM32 на easy electronics, вновь возникла мысль оживить плату, подружить её с LCD и написать хотя бы обыкновенную рисовалку с сенсорной панелью.

Экран у меня, как оказалось, работает на контроллере ILI9320, а touch screen на TSC2046 (более новый аналог ADS7846).

Писал всё в KEIL uVision 4. Среда разработки чем-то понравилась сразу, подружилась с платой через uLink. После я стал использовать для прошивки и отладки Pinboard II, она слишком большая для таких целей, поэтому заказал FTDI модуль.

Итак, приступим…


Сначала был свет… то есть, сначала его не было, а потом он стал. Зажигается подсветка экрана простой установкой ножки LIGHT_PWM, которая подключена к ножке PortD 13 в положение 1. Для начала мне было не нужно регулировать яркость подсветки. Экран работает часами, не греется. Едва ощутимое тепло исходит от стабилизатора напряжения на плате.

Подключили экран непонятным на тот момент методом. Позднее выяснилось, что это подключение FSMC (контроллер внешней памяти). Но тогда я делал всё через порты ввода-вывода. Это медленнее, но лучше понимаешь, как работать с экраном. Смотрим схему и попробуем всё как-нибудь упорядочить.

lcd connector

Для LCD экрана используем управляющие выводы, и определим направление (выход или вход), чтобы сконфигурировать порты:
PE1_LCD_RST (reset экрана) — выход.
PD4_nOE (чтение с экрана — обратная логика) — выход
PD5_nWE (запись на экран — обратная логика) — выход
PD7_CS (выбор экрана) — выход
PD11_RS (register select — выбор адрес или данные) — выход
И разбросанные по разным портам выводы данных (шина 16 бит)
D0 — D15 — вход или выход

Таким образом вместо того, чтобы просто пнуть в порт данные, нужно побить в бубен. За вывод данных у меня отвечает такая функция:

void Lcd_Set (int com)
{
    int tmp;
    GPIOE->BRR = 0xFF80;  //clear port data bits only
    GPIOD->BRR = 0xC703;  //clean port  data bits only
    tmp = com  & 0x1FF0;  //mask for Port E;
    tmp = tmp << 3;       //move data to PE15 - PE7
    GPIOE->BSRR = tmp;	  //out on port E
    tmp = com & 0xE000;   //Mask for port D (hi part) 
    tmp = tmp >> 5;
    GPIOD->BSRR = tmp;
    tmp = com & 0x000C;    //Mask for port D (LO part)
    tmp = tmp >> 2;
    GPIOD->BSRR = tmp;
    tmp = com & 0x0003;    //Mask for port D (MD part)
    tmp = tmp << 14;
    GPIOD->BSRR = tmp;
}


lcd data set

Чтение из экрана выполняем в обратном направлении, не забывая перевести ножки порта на вход.


int Lcd_Read (void)
{
int tmp1, tmp2;
int data=0, tmp;
Lcd_Com (0x0000);
LCD_CS_ON;
Delay (5);
Lcd_Port_In_Conf ();   //config ports as Input
LCD_RS_1;
LCD_OE_ON;
Delay (5);
tmp1 = GPIOE->IDR;  //get Port E data
tmp2 = GPIOD->IDR;  //get Port D data
Delay (5);
LCD_OE_OFF;
LCD_CS_OFF;
Lcd_Port_Out_Conf ();   //return ports as Out
//prepare port E data
tmp1 &= 0xFF80;	  //mask for PE15 - PE7
tmp1 = tmp1 >> 3;	//to D12 - D4
data |= tmp1;       //Write to data
//prepare port D data
tmp = tmp2 & 0x0700; //mask PD10 - PD8
tmp = tmp << 5;           //to D15 - D13
data |= tmp;        //Write
tmp = tmp2 & 0xC000; //mask PD15 - PD14
tmp = tmp >> 14;           //to D1 - D0
data |= tmp;        //Write
tmp = tmp2 & 0x0003; //mask PD1 - PD0
tmp = tmp << 2;           //to D3 - D2
data |= tmp;        //Write
return data;
}


Чтение модуля выполняется только вначале инициализации, когда нужно определить тип контроллера LCD. Далее в программе выполняется только запись.

Чтение и запись немного похожи на обращение с обычными текстовыми экранами. Устанавливаем CS в 0, устанавливаем регистр адреса или данных (RS 0 — адрес, 1 — данные), сбрасываем в 0 чтение (OE) или запись (WO) — это и есть наш строб для данных. Теперь пишем или читаем данные с шины.


void Lcd_Com (int com)
{
Lcd_Set (com);
LCD_OE_OFF;
LCD_RS_0;	   //addr set
LCD_WR_ON;	   //Write com
Delay (1);
LCD_WR_OFF;
}

void Lcd_Data (int data)
{
Lcd_Set (data);
LCD_OE_OFF;
LCD_RS_1;	   //data sel
LCD_WR_ON;	   //Write data
Delay (1);
LCD_WR_OFF;
}

void Lcd_Com_Data (int addr, int data)
{
LCD_CS_ON;
Lcd_Com	(addr);
Lcd_Data	(data);
LCD_CS_OFF;
Delay (2);
}


Немного напоминает команды и данные, но в TFT экране данные могут быть либо командой, либо цветом отображаемого пикселя. Всё зависит, по какому адресу эти данные отправить. Цвет пикселей шлём на адрес 0x0022.

В следующей части настроим контроллер и сделаем инициализацию экрана.

Продолжение следует…
  • +3
  • 11 ноября 2013, 01:05
  • ilus
  • 1
Файлы в топике: 1282974717188.jpg

Комментарии (9)

RSS свернуть / развернуть
И разбросанные по разным портам выводы данных (шина 16 бит)
— категорически не рекомендую делать так. Если вывести данные (чаще всего это цвет пикселя) через один порт — код будет гораздо компактнее и выполняться намного быстрее. Для вывода картинок с произвольными цветами пикселей это очень существенно. Если это возможно — используйте один порт, если не получается, попытайтесь два, но в этом случае лучше разбить так — от одного младшие 8 бит, от другого старшие и в соответствии с двоичными разрядами шины данных дисплея.
0
PD7_CS (выбор экрана) — выход
PD7_RS (register select — выбор адрес или данные) — выход
— и здесь подправьте, я так понимаю, что во второй строке должно быть PD11_RS
0
Поправил. Спасибо.
0
Подключили экран совершенно извращенским методом
Это не «извращенский» метод, а FSMC. Так что всё правильно.
0
Я так понимаю, это контроллер внешней памяти?
0
Упс, это действительно FSMC (ночь была, проспал этот момент...)- значит с шиной данных все правильно, только тогда надо инициировать FSMC и использовать его возможности и все будет очень хорошо. Сам Lcd надо представить в виде двух ячеек памяти, используя 16-ый бит адреса для управления режимом: A16 = 0 (адрес 0x60000000) — обращение к регистрам Lcd, A16 = 1 (адрес 0x60020000) — данные.
0
Исправил немного.
0
А вот мне интересно, почему всегда используют именно резистивный тачскрин? Емкостный только в телефонах и планшетах, а в любительских проектах его не встречал. Что так сильно ограничивает использование дисплеев с емкостными тачскринами?
0
Относительная простота принципа работы и, как следствие, простота использования. Мелкие (да и более крупные, 7-ми дюймовые) экраны идут в комплекте с резистивным тач-скрином и драйвером. Стоят не так много (не сравнивал с ёмкостными, просто не встречал их).
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.