Передмова
Свої графічні бібліотеки це добре, але професійна графічна бібліотека, що дозволяє створювати графічні інтерфейси користувача
STEmWin від
Segger - ще краща. Пропоную навчитись спочатку інтегрувати цю бібліотеку до свого проекту і спробувати намалювати декілька примітивів для проби. Хоч бібліотека і входить до складу репозиторіїв, що надаються STM32CubeMX, але ще не для всіх серій МК CubeMX інтегрує цю бібліотеку автоматично до вашого проекту. Тому, вміти це зробити самому, буде нам завиграшки.
Залізяччя
Схема підключення та розпіновка TFT дисплею з TOUCH SCREEN є у попередній статті
"STM32: Бібліотека дисплею ILI9341 по інтерфейсу FSMC". В тій статті також описано як налаштувати FSMC в CubeMX, але для зручності налаштування інтерфейсу FSMC продублюю і в цій статті. Плюс є деякі доповнення для роботи бібліотеки EmWin.
CubeMX
Відкриваємо CubeMX або CubeIDE, створюємо новий проект, обираємо чип STM32F407VE і налаштовуємо периферію:
- В розділі "System Core" обираємо "RCC": "High Speed Clock -> Crystal/Ceramic Resonator";
- У вкладці "Clock Configuration" обираємо зовнішній кварц, та потрібну частоту. Раз ми працюємо з графікою, то швидкість буде тільки на користь, я виставив максимальну частоту для цього чипу - 160МГц.
- В розділі "System Core" обираємо "SYS": "Debug -> Serial Wire";
- В розділі "Connectivity" обираємо "FSMC";
- В розділі "NOR Flash/PSRAM/SRAM/ROM/LCD 1" активуємо "NE1 Chip Select", обираємо "Memory type -> LCD Interface", "LCD Register Select -> A18" (відповідно до розпіновки роз'єму для дисплею, в мене сигнал RS дисплею під'єднано до PD13 мікроконтролеру. А ніжка PD13 активується для RS, коли обрати A18), "Data -> 16 bits";
- В розділі "Configurations -> NOR/PSRAM control" обираємо: "Memory type -> LCD Interface", "Bank -> Bank 1 NOR/PSRAM 1", "Write operation -> Enabled", "Extended mode -> Disabled". В розділі "NOR/PSRAM timing" обираємо: "Address setup time in HCLK clock cicles -> 1", "Data setup time in HCLK clock cycles -> 5", "Bus turn around time in HCLK clock cycles -> 0";
- Не забуваємо про підсвічування екрану. Відповідно до схеми це PB1. Встановимо режим GPIO_Output і дамо назву цій шпильці - "LCD_BL";
- Увага! В розділі "Computing" обираємо "CRC" та активуємо "Activated". Без цього бібліотека компілюється, але ніякого зображення на екран не виводиться.
- Генеруємо проект. Даємо назву проекту, наприклад: "STM32F407VET6_Black_ILI9341_EmWin". Вказуємо шлях до проекту та зберігаємо проект на диску.
 |
Налаштування FSMC |
 |
Налаштування CRC |
Інтегруємо бібліотеку до проекту
Запускаємо свій засіб розробки. Я використовую, або "
CubeIDE for STM32", або "
Atolic True Studio for STM32". Обидві IDE абсолютно безкоштовні. Відкриваємо проект згенерований CubeMX або CubeIDE і додаємо потрібні файли бібліотеки до проекту.
Додаємо файли спрощеного драйверу дисплея ILI9341
Перед тим, як додати бібліотеку EmWin, додаємо спрощену бібліотеку для дисплею
ILI9341_LIGHT, де будуть лиш три функції, це ініціалізація дисплея, увімкнути підсвітку дисплея, та вимкнути підсвітку дисплея. А також дефайни запису команд, даних, та читання регистрів дисплея. Ця спрощена бібліотека складається з двох файлів
ili9341_light.h та
ili9341_light.c Так буде зручніше і зрозуміліше.
В цьому проекті буде дуже багато файлів і щоб не скидати все до купи, копіюємо всю теку бібліотеки
ILI9341_LIGHT до теки Drivers вашого проекту, як показано на малюнку:
 |
Додавання теки бібліотеки ili9341_light до проекту |
Тепер, як додали файли, потрібно вказати компілятору шлях до теки
"inc". Викликаємо властивості проекту:
Project -> Properties -> C/C++ Build -> Settings -> Tool Settings -> C Compiler -> Directories -> Include path -> Add обираємо
Workspace, та вказуємо в файловому провіднику шлях до теки
"inc" бібліотеки
"ili9341_light". Робимо як на малюнку. Тицяйте на зображенні для збільшення:
 |
Налаштування шляхів |
Додайте до коду в файлі
"main.c" файл бібліотеки
"ili9341_light.h":
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "ili9341_light.h"
/* USER CODE END Includes */
Тепер можна спробувати скомпілювати натиснувши "Ctrl+B", щоб переконатись у відсутності помилок при компіляції. Як все гаразд, рухаємось далі.
Додаємо файли бібліотеки EmWim
Бібліотеку можна завантажити на сайті
SEGGER, але я рекомендую взяти з репозиторію CubeMX, або CubeIDE, тим паче, що ця бібліотека вже входить в комплект репозиторію вашого чипу і скачувати вже нічого не потрібно. Знаходиться бібліотека за шляхом -
"C:\Users\ваш_логін\STM32Cube\Repository\STM32Cube_FW_F4_V1.24.1\Middlewares\ST\STemWin", де
"ваш_логін", це ваша локальна тека користувача. Відкриваємо теку
"STemWin" в віконці файлового провідника.
А тепер уважно крок за кроком робимо такі речі:
- В своєму засобі розробці в дереві проекту в теці "Drivers" створюємо теку "EmWin": на теці "Drivers" тиснемо ПКМ -> New -> Folder -> EmWin -> Finish;
- Аналогічно в теці "EmWin" створюємо теки "inc" та "src";
- Всі файли з теки "...\Middlewares\ST\STemWin\inc" репозиторію, копіюємо до теки "Drivers\EmWin\inc" вашого проекту;
- Файли "GUIConf.h", "LCDConf_FlexColor_Template.h" з теки "...\Middlewares\ST\STemWin\Config" репозиторію, копіюємо до теки "Drivers\EmWin\inc" вашого проекту;
- Файли "GUIConf.c", "LCDConf_FlexColor_Template.c" з теки "...\Middlewares\ST\STemWin\Config" репозиторію, копіюємо до теки "Drivers\EmWin\src" вашого проекту;
- Перейдіть до свого засобу розробки і в дереві проекту знайдіть файли "LCDConf_FlexColor_Template.h" і "LCDConf_FlexColor_Template.c" та переименуйте їх на "LCDConf_FlexColor.h" і "LCDConf_FlexColor.c";
- Файл "STemWin_CM4_wc32.a" з теки "...\Middlewares\ST\STemWin\Lib" репозиторію, копіюємо до теки "Drivers\EmWin" вашого проекту;
- Файл "GUI_X.c" з теки "...\Middlewares\ST\STemWin\OS" репозиторію, копіюємо до теки "Drivers\EmWin\src" вашого проекту;
- Тепер, як додали файли, потрібно вказати компілятору шлях до теки "Drivers\EmWin\inc" вашого проекту. Як це ми вже робили раніше, коли додали файли спрощеного драйверу ILI9341_LIGHT. Викликаємо властивості проекту: Project -> Properties -> C/C++ Build -> Settings -> Tool Settings -> C Compiler -> Directories -> Include path -> Add обираємо Workspace, та вказуємо в файловому провіднику шлях до теки "inc" бібліотеки "EmWin" вашого проекту;
- І на останок потрібно вказати лінковщику на файл "STemWin_CM4_wc32.a": Project -> Properties -> C/C++ Build -> Settings -> Tool Settings -> C Linker -> Miscellaneous -> Additional object files -> Add обираємо Workspace, та вказуємо в файловому провіднику шлях до файлу "STemWin_CM4_wc32.a" бібліотеки "EmWin" вашого проекту;
 |
Налаштування шляху до файла для лінковщика |
Налаштування бібліотеки EmWin
- В своєму засобі розробки відкриваємо файл "GUIConf.c" і шукаємо такий рядок:
//
// Define the available number of bytes available for the GUI
//
#define GUI_NUMBYTES 0x200000
- Зараз для GUI виділено аж 2Мб пам'яті RAM. Міняємо це значення на 32Кб:
//
// Define the available number of bytes available for the GUI
//
#define GUI_NUMBYTES 32 * 1024
- Відкриваємо файл "main.c" і додаємо такі рядки:
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "ili9341_light.h"
#include "GUI.h"
/* USER CODE END Includes */
- Та для проміжної перевірки, що все зроблено вірно, додамо ще виклик функції ініціалізації GUI:
/* USER CODE BEGIN 2 */
GUI_Init();
/* USER CODE END 2 */
- Компілюємо проект "Ctrl+B", як немає помилок, то все в порядку, зроблено все вірно. Продовжуємо налаштування далі;
- Відкриваємо файл "LCDConf_FlexColor.h", та додаємо рядок з "#include":
- Відкриваємо файл "LCDConf_FlexColor.c", та додаємо такі рядки поруч з іншими "#include":
#include "LCDConf_FlexColor.h"
#include "ili9341_light.h"
- До функції "LcdWriteReg" додаємо виклик функції запису команди до дисплею:
/********************************************************************
*
* LcdWriteReg
*
* Function description:
* Sets display register
*/
static void LcdWriteReg(U16 Data)
{
// ... TBD by user
LCD_CmdWrite(Data);
}
- До функції "LcdWriteData" додаємо виклик функції запису даних до дисплею:
/********************************************************************
*
* LcdWriteData
*
* Function description:
* Writes a value to a display register
*/
static void LcdWriteData(U16 Data)
{
// ... TBD by user
LCD_DataWrite(Data);
}
- До функції "LcdWriteDataMultiple" додаємо виклик функції запису масиву даних до дисплею:
/********************************************************************
*
* LcdWriteDataMultiple
*
* Function description:
* Writes multiple values to a display register.
*/
static void LcdWriteDataMultiple(U16 * pData, int NumItems)
{
while (NumItems--)
{
// ... TBD by user
LCD_DataWrite(*pData);
pData++;
}
}
- До функції "LcdReadDataMultiple" додаємо виклик функції читання масиву даних з дисплею:
/********************************************************************
*
* LcdReadDataMultiple
*
* Function description:
* Reads multiple values from a display register.
*/
static void LcdReadDataMultiple(U16 * pData, int NumItems)
{
while (NumItems--)
{
// ... TBD by user
*pData = LCD_DataRead();
pData++;
}
}
- В розділі "Orientation" цього ж файлу "LCDConf_FlexColor.c" мають бути такі рядки:
//
// Orientation
//
Config.Orientation = GUI_MIRROR_Y;
GUIDRV_FlexColor_Config(pDevice, &Config);
- А в розділі "Set controller and operation mode" перевірте щоб був такий рядок:
GUIDRV_FlexColor_SetFunc(pDevice, &PortAPI, GUIDRV_FLEXCOLOR_F66709, GUIDRV_FLEXCOLOR_M16C0B16);
- Функція "GUIDRV_FLEXCOLOR_F66709" з попереднього пункту обирається відповідно до документації, яка знаходится в репозиторію за шляхом "...\Middlewares\ST\STemWin\Documentation\STemWin544.pdf". В таблиці 33.42 вказано яка функція відповідає якому дисплею. Наш дисплей ILI9341 має функцію "GUIDRV_FLEXCOLOR_F66709";
- В функцію "LCD_X_DisplayDriver" додамо виклик функції ініціалізації дисплея:
int LCD_X_DisplayDriver(unsigned LayerIndex, unsigned Cmd, void * pData) {
int r;
(void) LayerIndex;
(void) pData;
switch (Cmd) {
case LCD_X_INITCONTROLLER: {
//
// Called during the initialization process in order to set up the
// display controller and put it into operation. If the display
// controller is not initialized by any external routine this needs
// to be adapted by the customer...
//
// ...
lcdInit();
return 0;
}
default:
r = -1;
}
return r;
}
- І на останок відкриваємо файл "stm32f4xx_it.c" і додаємо такі рядки:
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "GUI.h"
/* USER CODE END Includes */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
extern volatile GUI_TIMER_TIME OS_TimeMS;
/* USER CODE END PV */
- А в функцію "SysTick_Handler" додаємо інкремент змінної "OS_TimeMS" і тепер ця функція виглядатеме так:
/**
* @brief This function handles System tick timer.
*/
void SysTick_Handler(void)
{
/* USER CODE BEGIN SysTick_IRQn 0 */
/* USER CODE END SysTick_IRQn 0 */
HAL_IncTick();
/* USER CODE BEGIN SysTick_IRQn 1 */
OS_TimeMS++;
/* USER CODE END SysTick_IRQn 1 */
}
- Остаточно перевіряємо проект на відсутність помилок. Компілюємо "Ctrl+B". Як помилок немає переходимо до малювання.
Невеличка перевірка роботи дисплею
Відкриємо файл "main.c" і додамо декілька рядків для перевірки роботи дисплею і бібліотеки:
/* USER CODE BEGIN 2 */
GUI_Init();
lcdBacklightOn();
GUI_SetColor(GUI_YELLOW);
GUI_SetBkColor(GUI_BLUE);
GUI_Clear();
GUI_FillCircle(GUI_GetScreenSizeX() / 2, GUI_GetScreenSizeY() / 2, 100);
GUI_SetFont(&GUI_Font16B_1);
GUI_SetColor(GUI_RED);
GUI_SetBkColor(GUI_YELLOW);
GUI_DispStringHCenterAt("Hello, World!",GUI_GetScreenSizeX() / 2, GUI_GetScreenSizeY() / 2);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
Компілюємо, заливаємо, запускаємо, спостерігаємо:
 |
Приклад роботи |
Додавання бібліотеки touch screen
Тестування touch screen
Додамо до коду декілька рядків.
Вставимо в код заголовний файл бібліотеки touch screen:
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "ili9341_light.h"
#include "GUI.h"
#include "XPT2046_touch.h"
/* USER CODE END Includes */
Користувацька секція 2 тепер буде виглядати так:
/* USER CODE BEGIN 2 */
GUI_Init();
lcdBacklightOn();
GUI_SetColor(GUI_YELLOW);
GUI_SetBkColor(GUI_BLUE);
GUI_Clear();
GUI_SetPenSize(3);
/* USER CODE END 2 */
А в користувацьку секцію 4 додамо функцію зворотного виклику, яка викликається кожного разу коли відбувається доторкання до touch screen і ніжка T_IRQ притискається до логічного нуля:
/* USER CODE BEGIN 4 */
void HAL_GPIO_EXTI_Callback (uint16_t GPIO_Pin)
{
if (GPIO_Pin == T_IRQ_Pin)
{
if(XPT2046_TouchPressed())
{
uint16_t x, y;
if(XPT2046_TouchGetCoordinates(&x, &y))
{
GUI_DrawPoint(x, GUI_GetScreenSizeY() - y);
}
}
}
}
/* USER CODE END 4 */
Компілюємо, заливаємо, малюємо на екрані:
 |
Приклад роботи touch screen |
Файли