ili9341 + тачскрин под управлением HAL и FSMC

Ответить
Аватара пользователя
2Qay
Сообщения: 59
Зарегистрирован: 14 окт 2019, 12:58
Откуда: Татарстан
Позывной: ----
Город: Казань
Благодарил (а): 19 раз
Поблагодарили: 11 раз

ili9341 + тачскрин под управлением HAL и FSMC

Сообщение 2Qay » 31 мар 2020, 01:11

Здравствуйте товарищи.
Немного предыстории. Вообщем купил я экранчик на али как на фото ниже, с ним еще в комплекте идет преобразователь логики 5 вольт в 3.3 вольт.
IMG_20200330_215707-min.jpg
IMG_20200330_215657-min.jpg
ВАЖНО! экран работает с логикой 3.3 , логика в 5 вольт сожжет чип, проверено интернетом.
На ардуино этот экран завелся без проблем, и нашел я его сново спустя 2-3 года в закромах. Решил запустить уже на стмке, по взрослому как говорится. Ознакомился с кучей статей, но именно на 16 битный, с использованием HAL и кубовских программ ничего не было (были готовые библиотеки на CMSIS с использованием "ногодрыга"). Собрал кучу информации из разных источников, и вообщем всё запустилось, затем нашел библиотеку для тачскрина от одного иностранца, сдружил её с библиотекой для самого экран, и все заработало (ссылки на все исходные данные приведу ниже по ходу изложения). ВАЖНО! Данная тема не претендует на оригинальность и собственную разработку, я лично нового ничего не придумал, просто взял исходник одних, добавил в них всё что нашел у других, будет описание именно того, что было изменено, ну и получившиеся файлы скину ниже.
Вкратце об экране:
- чип экрана ili9341, в этом модуле работающий только в 16 бит режиме (где то под экраном запаяны контакты шлейфа определяющие битность)
- чип тачскрина ххх2046 .В названии ххх потому что производители разные, главное последние четыре цифры (у меня лично стоит чип XPT2046, у товарища о котором напишу ниже TSC2046), чип использует SPI интерфейс на низкой скорости.
- имеется возможность подключения флешки к МК (о данной функции речь не пойдет).

Начнем с экрана. Перед этим советую ознакомится с циклом статей на ресурсе narodstream от Владимира Воробьёва (Он же основатель ресурса, ссылка на первый урок http://narodstream.ru/stm-urok-37-displ ... t-chast-1/ ). Именно на его основе написал (фактически скопировал :D ) библиотеку. Начнем.
При создании проекта в кубе выбираем пункт FSMC и выставляем как на фото (тут думаю комментарии лишние)
1.jpg
В отличие от исходника Владимира у нас LCD register select установлен A19 и data установлена 16 бит. И как следствие пин FSMC переехал с PD11 на PE3. Затем так же делаем PD6 на выход, он будет управлять перезагрузкой экрана. По кубу в данном случае всё, переходим уже в редактирование кода (лично я использую кейл пятый).
Создание хидер(.h) файла.
Подключаем библиотеки:

Код: Выделить всё

#include <stdlib.h>
#include "stm32f4xx_hal.h"
Уточнение: Владимир использует флешку с записанными шрифтами, и для чего использует библиотеки fatfs.h и stdlib.h . Я использую хидер файл с массивом шрифта 5х7 пикселей, и по этому библиотеки не подключал.

Затем идет указание начала адресации данных и команд в чипе экрана (на этом месте я висел недельку, по собственной глупости). Указываю адреса следующим образом:

Код: Выделить всё

#define ADDR_CMD        *(uint16_t*)0x60000000
#define ADDR_DATA       *(uint16_t*)0x60100000
В оригинале указатель на тип данных uint8_t так как шина 8 проводная, а в данном случае указатель на uint16_t так как шина 16 проводная.
далее идет полный копипаст с Владимира.
Продолжу с места где есть отличия. В некоторых функциях имеется разделение переменной цвета на старший и младший байты (цвет кодируется 16-ю битами). Например функция отрисовки пикселя у автора исходников выглядит след. образом:

Код: Выделить всё

void TFT9341_DrawPixel(int x, int y, uint16_t color)
{
    if((x<0)||(y<0)||(x>=X_SIZE)||(y>=Y_SIZE)) return;
    TFT9341_SetAddrWindow(x, y, x, y);
    TFT9341_SendCommand(0x2C);
[u]    TFT9341_SendData(color >> 8);
    TFT9341_SendData(color & 0xFF);[/u]
}
В нашем случае:

Код: Выделить всё

void TFT9341_DrawPixel(int x, int y, uint16_t color)
{
	if((x<0)||(y<0)||(x>=X_SIZE)||(y>=Y_SIZE)) return;
	TFT9341_SetAddrWindow(x, y, x, y);
	TFT9341_SendCommand(0x2C);
	[u]TFT9341_SendData(color);[/u]
}
Затем есть отличие в функции вывода символов. У Владимира используется работа с флешкой на которой файл с шрифтами и т.д. Я взял исходник от другого экрана (чей не вспомню)

Код: Выделить всё

void TFT9341_SendChar(uint16_t x,uint16_t y, uint8_t ch, uint16_t colorfont, uint16_t color)
{
	uint16_t i,j;
	uint16_t buffer[5];
	for(int i=0;i<5;i++)
	{
		buffer[i]=Font5x7[i+ch*5];
	}
	TFT9341_SetAddrWindow(x,y,x+5,y+7);
	TFT9341_SendCommand(0x2C);
	for(j=0;j<7;j++)
	{
		for(i=0;i<5;i++)
		{
			if((buffer[i] & (1<<j))==0)
			{
				TFT9341_SendData(colorfont);
			}
			else
			{
				TFT9341_SendData(color);
			}
		}
		TFT9341_SendData(colorfont);
	}
	for(j=0;j<5;j++)
	{
		TFT9341_SendData(colorfont);
	}
}

[/i][/i]
Очень популярный код реализации отрисовки символа, суть в том, что каждый знак хранится пятью байтами,каждый бит отвечает за отрисовку пикселя символа, или отрисовку пикселя заднего фона . То есть постепенный перебор каждого бита дает в итоге символ на экране.
Затем изменил в функции установки вращения числа 0,1,2,3 на 1,2,3,4 соответственно в операторе switch, потому что мне лично так удобнее))))

Код: Выделить всё

void TFT9341_SetRotation(unsigned char r)
{
	TFT9341_SendCommand(0x36);
	switch(r)
	{
		[u]case 1:[/u]  //было [u]case 0:[/u]
		rotation = 1;
		TFT9341_SendData(0x48);
		X_SIZE = 240;
		Y_SIZE = 320;
		break;
		[u]case 2:[/u]  //было [u]case 1:[/u]
		rotation = 2;
		TFT9341_SendData(0x28);
		X_SIZE = 320;
		Y_SIZE = 240;
		break;
		[u]case 3:[/u]  //было [u]case 2:[/u]
		rotation = 3;
		TFT9341_SendData(0x88);
		X_SIZE = 240;
		Y_SIZE = 320;
		break;
		[u]case 4:[/u]  //было [u]case 3:[/u]
		rotation = 4;
		TFT9341_SendData(0xE8);
		X_SIZE = 320;
		Y_SIZE = 240;
		break;
	}
}
Главное, была необходимость получения переменных Y_SIZE и X_SIZE (y и x максимальные), которые меняются в зависимости от установки поворота экрана, а так же rotation, для работы с библиотекой тачскрина. Немного философии. Можно было это реализовать посредством расширения области переменной используя её декларирование (например extern uint16_t X_SIZE;). Но тут уже взрослые дяди говорят что так не правильно и может привести к кряку программы, лучше решить этот вопрос функционально. Вот пример:

Код: Выделить всё

uint16_t get_x_size(void)
{
	return X_SIZE; // и всё
}
Далее про тачскрин.
Исходник взят тут https://www.youtube.com/watch?v=gd-BHZ5ZyPc&t=875s, и вообще тут можно уложится в пару слов.
1) В библиотеке местами вызываются функции библиотеки для ili9341(например в режиме калибровки вызывается функции отрисовки круга). Следовательно эти функции меняем на свои.
функция изначальная:

Код: Выделить всё

[u]ILI9341_fillCircle(myTS_Calibrate.Width-10, myTS_Calibrate.Height-10, 3, COLOR_RED);[/u]
поменял на:

Код: Выделить всё

[u]TFT9341_DrawCircle(myTS_Calibrate.Width-10, myTS_Calibrate.Height-10, 3, RED);[/u]
(сделал круги поболее в радиусе)
2)Есть функция которая нужна в целом для работы с тачем, и где требуется указать переменную поворота экрана. В оригинале переменная доходит через вызов нескольких функций и сохранений, кратко это выглядит так: переменную ScreenOrientation получаем в функции TSC2046_Begin, где ScreenOrientation приравниваем к функции TSC2046_getOrientation(), которая в свою очередь просто делает ретёрн функции ILI9341_getRotation(), которая возвращает переменную rotationNum.

Код: Выделить всё

TS_TOUCH_RAW_Def TSC2046_GetRawTouch(void)
{
	switch ([u]ScreenOrientation[/u])
	{
		case 1:
			localRawTouch.x_touch = 4095 - TSC2046_getRaw_X();
			localRawTouch.y_touch = TSC2046_getRaw_Y();
			myTS_Calibrate.Width = 230;
			myTS_Calibrate.Height = 320;
			break;
		 ............// и ниже ещё три case 
От части это обоснованно, но функция TSC2046_getOrientation вызывается только в одном месте, так что вместо создания ещё одной переменной для хранения вращения просто вызываем функцию TFT9341_GetRotation().

Код: Выделить всё

TS_TOUCH_RAW_Def TSC2046_GetRawTouch(void)
{
	switch ([u]TFT9341_GetRotation()[/u])
	{
		case 1:
			localRa....... //далее понятно
На этом всё (вроде как). С помощью не хитрых манипуляций и наглого копипаста из интернета получилось запустить экранчик. Исходники будут по ссылке ниже, так как я эти библиотеки потихоньку пилю/допиливаю/пополняю и так далее, и не вижу смысла заливать их сюда зипом.
https://yadi.sk/d/EBPifkJSYYTcYg
И ещё там на диске есть хидер файл с шрифтом 5 на 7 с кириллицей, правда работает криво, но не суть, исправим))))
Пару фоток экрана в работе (почему повернуты понять не могу)
IMG_20200219_122418.jpg
IMG_20200219_122455.jpg
Спасибо за внимание)
И да, критику и предложения никто не отменял, я не сахарный, не растаю)

P.S.
И есть еще желание записать видео просто с демонстрацией экрана в работе, без комментариев, так как экран в связке с STM32f407 на 168 МГц тактирования работает ооочень шустро, не как какой нибудь spi или ещё что-то.

Аватара пользователя
2Qay
Сообщения: 59
Зарегистрирован: 14 окт 2019, 12:58
Откуда: Татарстан
Позывной: ----
Город: Казань
Благодарил (а): 19 раз
Поблагодарили: 11 раз

ili9341 + тачскрин под управлением HAL и FSMC

Сообщение 2Qay » 31 мар 2020, 01:12

phpBB [video]


Аватара пользователя
R2AJI
Сообщения: 746
Зарегистрирован: 12 окт 2019, 22:48
Город: Россошь
Благодарил (а): 183 раза
Поблагодарили: 240 раз

ili9341 + тачскрин под управлением HAL и FSMC

Сообщение R2AJI » 31 мар 2020, 13:03

Здравствуйте уважаемый 2Qay.
Пожалуйста, используйте тег "Код"
изображение.png
Так гораздо легче текст воспринимать.
Все вопросы про радио, на форум пожалуйста, в личные сообщения, только личные вопросы.
В противном случае, все равно отправлю на форум.

YouTube канал HAM Radio Channel

Ответить

Вернуться в «Микроконтроллеры и программирование»