вівторок, 20 жовтня 2020 р.

STM32CubeIDE: Встановлення Serial Terminal

Передмова

 Коли перейшов з засобу розробки Atolic TrueStudio на STM32CubeIDE, зіткнувся з тим, що з "коробки" Serial Terminal - не встановлено. І відправляти відладочну інформацію по UART нікуди, крім як на сторонню термінальну програму. Що не зовсім зручно. А так як, що Atolic TrueStudio, що STM32CubeIDE це - Eclipse IDE з певними налаштуваннями і плагінами (надбудовами), то можемо потрібний нам Serial Terminal встановити самотужки із репозиторію.

Встановлення Terminal

Йдемо по меню “Help->Install New Software”:

Install New Software
Install New Software

Потрібно обрати репозиторій, або Eclipse Repository або TM Terminal Marketplace Update Site. І вводимо в поле пошуку "terminal" або "serial" (без лапок). Або робимо як на зображені, обираємо всі сайти, вводимо для пошуку "tm terminal" і обираємо свіжу версію "TM Terminal":

Обрати останню версію TM Terminal

Можливо в додачу до цього, потрібно ще, додати плагін "RXTX", або "Serial Connector":

Встановлення плагіну RXTX End-User Runtime
Serial Terminal - встановлено!

Як користуватись

Тепер розберемось як користуватись Serial Monitor. Покажемо вікно для терміналу "Window -> Show View -> Terminal:

Виклик вікна для терміналу

Тепер викличемо сам термінал, або через "іконку", або за допомоги "гарячих" кнопок "Ctrl + Alt + Shift + T":

Виклик терміналу Ctrl + Alt + Shift + T

Та оберемо/погодимось з налаштуваннями. Обираєм COM порт до якого під'єднано UART мікроконтролера. Наприклад, через пристрій UART 2 USB Converter і в системі на ПК він визначений як COM4, тоді налаштування будуть виглядати так:

Налаштування Serial Monitor
Тиснемо "ОК" і термінал готовий до прийому байтів з вашого МК. Натиснувши "іконку" командний рядок, можна і надсилати байти в ваш МК:

Обмін байтами між ПК і МК

Як надсилати інформацію відладки

Потрібно задіяти UART мікроконтролера, наприклад увімкнути і налаштувати USART2 на мікроконтролері і тоді код який треба додати до вашого проекту буде виглядати так. Вставте в відповідні ділянки коду (визначення який UART задіяний, прототип функції і саму функцію), як в прикладі нижче:
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define UART_PRINTF	huart2
/* USER CODE END PD */

/* USER CODE BEGIN PFP */
int _write(int file, char *ptr, int len);
/* USER CODE END PFP */

/* USER CODE BEGIN 4 */
int _write(int file, char *ptr, int len)
{
	HAL_UART_Transmit(&UART_PRINTF, (uint8_t *) ptr, len, HAL_MAX_DELAY);
	return len;
}
/* USER CODE END 4 */
Тепер можна користуватись функцією "printf" і вона буде виводити потік через UART MK в термінальну програму на ПК:
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART2_UART_Init();
  /* USER CODE BEGIN 2 */
  printf("%8lu: UART is Ok!\r\n", HAL_GetTick());
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
	  printf("%8lu: Current Tick\r\n", HAL_GetTick());
	  HAL_Delay(1000);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

пʼятниця, 15 листопада 2019 р.

STEmWin: GUIBuilder приклад побудови вікна з графічними елементами і їх взаємодія


Передмова

В попередній статті інтегрували професійну бібліотеку EmWin до свого проекту та спробували щось відобразити на екрані і навіть помалювати за допомоги сенсорної панелі. В цій статті побудуємо, за допомоги програми GUIBuilder, графічний інтерфейс та додамо код взаємодії з графічним інтерфейсом.

Залізяччя

GUI Builder

Відкрийте програму "GUIBuilder", яка знаходиться в репозиторію CubeMX, або CubeIDE за шляхом "...\Middlewares\ST\STemWin\Software\GUIBuilder.exe".

Window

  1. Додайте елемент "Window";
  2. Встановіть властивості вікна: xPos - 0, yPos - 0, xSize - 240, ySize - 320;
  3. Встановимо колір вікна. ПКМ на елементі "Window", та оберіть "Set background color" -> Сірий (0xC0C0C0).
Window

Text

  1. Додайте елемент "Text";
  2. Встановимо позицію та розмір елементу. xPos - 0, yPos - 0, xSize - 240, ySize - 40;
  3. Встановимо шрифт. ПКМ на елементі "Text" -> "Set font" -> "GUI_FONT_24_1";
  4. Встановимо текст. ПКМ на елементі "Text" -> "Set text" -> "Example";
  5. Встановимо рівняння тексту. ПКМ на елементі "Text" -> "Set text alignment" -> "HV";
Text

Radio

  1. Додайте елемент "Radio";
  2. Встановимо позицію та розмір елементу: xPos - 20, yPos - 60, xSize - 200, ySize - 60, distance - 30;
  3. Дамо назву пунктам. ПКМ на елементі "Radio" -> "Set item text" -> "Label text" -> "Option 1" -> "Label index" -> "1", "Radio" -> "Set item text" -> "Label text" -> "Option 2" -> "Label index" -> "2";
  4. Встановимо шрифт: Font - GUI_FONT_20_1;
Radio

Progbar та 2 x Button

По аналогії з попередніми елементами додайте елементи "Progbar" та "Button". Розташуйте, встановіть розмір, оберіть шрифт, дайте назви кнопкам. Щоб було приблизно як на малюнку.
Приклад інтерфейсу

Генерування проекту

Меню: "File" -> "Save...". Файл "WindowDLG.c" збережеться в директорію програми "GUIBuilder" за шляхом "...\Middlewares\ST\STemWin\Software\WindowDLG.c".

Перевірка роботи

Продовжимо працювати з проектом який створили в попередній статті "Підключення бібліотеки EmWin та перевірка роботи"
    1. Відкрийте проект створений в процесі роботи з попередньою статтею, який знаходиться на вашому диску, та відкрийте його в Atolic TrueStudio, CubeIDE, або в IDE, яку ви використовуєте; 
    2. Створіть файл "WindowDLG.h" в своєму засобі розробки, або будь яким іншим редактором, з таким змістом:
      #ifndef __WINDOWDLG_H
      #define __WINDOWDLG_H
      
      #include "DIALOG.h"
      
      WM_HWIN CreateWindow(void);
      
      #endif /* __WINDOWDLG_H */
      
    3. Внесіть зміни до файлу "WindowDLG.c". Було:
      // USER START (Optionally insert additional includes)
      // USER END
      
      #include "DIALOG.h"
      
    4. Стало:
      // USER START (Optionally insert additional includes)
      // USER END
      
      #include "WindowDLG.h"
      
    5. Зкопіюйте ці файли, "WindowDLG.h" та "WindowDLG.с" в свій проект за шляхом "..\Drivers\EmWin\inc" та "..\Drivers\EmWin\src" відповідно;
    6. Відкрийте файл "main.c" та вставте в код рядок з файлом "WindowDLG.h":
      /* Private includes ----------------------------------------------------------*/
      /* USER CODE BEGIN Includes */
      #include "ili9341_light.h"
      #include "GUI.h"
      #include "XPT2046_touch.h"
      #include "WindowDLG.h"
      /* USER CODE END Includes */
    7. В користувацькій секції 2 і безкінечному циклі видаліть код, який написали з попередньої статті. Тепер ця ділянка має виглядати так:
      /* USER CODE BEGIN 2 */
        GUI_Init();
        lcdBacklightOn();
        CreateWindow();
        /* USER CODE END 2 */
      
        /* Infinite loop */
        /* USER CODE BEGIN WHILE */
        while (1)
        {
           GUI_Exec();
          /* USER CODE END WHILE */
      
          /* USER CODE BEGIN 3 */
        }
        /* USER CODE END 3 */
      }
    8. Можна вже компілювати, як немає помилок, заливаємо до чипу і запускаємо. На дисплеї з'явилося зображення, що ми створили за допомогою програми "GUIBuilder.exe". Але поки що наш GUI ніяк не реагує на натискання сенсорної панелі.
    9. Додамо декілька глобальних змінних до файлу "main.c", це добуті координати від сенсорної панелі і структура для координат і статусу натискання на сенсорну панель для GUI:
      /* USER CODE BEGIN PV */
      uint16_t x, y;
      GUI_PID_STATE tsState;
      /* USER CODE END PV */
      
    10. Перейдемо до користувацької секції 4. Там має бути функція зворотного виклику, яка викликається кожного разу коли ви натискаєте на сенсорну панель, та відпускаєте її. За це відповідає сигнал T_IRQ. Докладно налаштування цієї шпильки описано в статті. Перевірте, щоб переривання цієї ніжки відбувалось, як при падінні сигналу, так і при зростанні сигналу на ніжці - GPIO mode -> External Interrupt Mode with Rising/Falling edge trigger detection. Видаляємо весь код який знаходиться в функції зворотного виклику void HAL_GPIO_EXTI_Callback (uint16_t GPIO_Pin) і залишився з попереднього прикладу, та пишемо там такий код:
      /* USER CODE BEGIN 4 */
      void HAL_GPIO_EXTI_Callback (uint16_t GPIO_Pin)
      {
       if (GPIO_Pin == T_IRQ_Pin)
       {
        if(XPT2046_TouchPressed())
        {
         tsState.Pressed = true;
      
         if(XPT2046_TouchGetCoordinates(&x, &y))
         {
           tsState.x = x;
           tsState.y = GUI_GetScreenSizeY() - y;
         }
        }
        else
        {
         tsState.Pressed = false;
         tsState.x = -1;
         tsState.y = -1;
        }
      
        GUI_TOUCH_StoreStateEx(&tsState);
       }
      }
      /* USER CODE END 4 */
      
    11. Пояснення до коду. Кожного разу коли ви натискаєте чи відпускаєте сенсорну панель, викликається ця функція. Тут перевіряється чи відбулось натискання, або звільнення сенсорної панелі. Як натиснули, то берем координати точки натискання і заповнюємо структуру координатами і встановлюємо прапорець "натиснуто". Як звільнили сенсорну панель, то заповнюємо структуру відповідно, що координат немає і скидаємо прапорець "натиснуто". Заносимо данні з структури до GUI_TOUCH.
    12. Компілюємо, заливаємо, запускаємо. Тепер наш GUI реагує на натискання кнопок і можемо обрати опцію в елементі "Radio", але при цьому ще нічого не відбувається.
    13. Щоб додати реакцію на події коли натискати на опції елементу "Radio", відкриваємо файл "WindowDLG.c", знайдіть рядок "case ID_RADIO_0: // Notifications sent by 'Radio'", та додамо в секцію "case WM_NOTIFICATION_RELEASED:" код який буде оброблятись коли ви будете змінювати опцію в елементі "Radio" при відпусканні:
      case ID_RADIO_0: // Notifications sent by 'Radio'
            switch(NCode) {
            case WM_NOTIFICATION_CLICKED:
              // USER START (Optionally insert code for reacting on notification message)
              // USER END
              break;
            case WM_NOTIFICATION_RELEASED:
              // USER START (Optionally insert code for reacting on notification message)
               {
                char buf[32];
                hItem = WM_GetDialogItem(pMsg->hWin, ID_RADIO_0);
                RADIO_GetText(hItem, RADIO_GetValue(hItem), buf, 32);
                hItem = WM_GetDialogItem(pMsg->hWin, ID_TEXT_0);
                TEXT_SetText(hItem, buf);
               }
              // USER END
              break;
            case WM_NOTIFICATION_VALUE_CHANGED:
              // USER START (Optionally insert code for reacting on notification message)
              // USER END
              break;
            // USER START (Optionally insert additional code for further notification handling)
            // USER END
            }
            break;
      
    14. Компілюємо, заливаємо, запускаємо. Тицяємо на опції "Radio" і текст елементу "Text" змінюється відповідно до змін.
    15. По аналогії додамо реакцію на натискання кнопок. Будемо змінювати значення елементу "Progbar", та міняти напис на елементі "Text". Спочатку додамо змінну "i", що буде зберігати значення для "Progbar", на початку файлу "WindowDLG.c":
      /*********************************************************************
      *
      *       Static data
      *
      **********************************************************************
      */
      
      // USER START (Optionally insert additional static data)
      int i;
      // USER END
      
    16. Та напишемо обробник події відпускання кнопок:
          case ID_BUTTON_0: // Notifications sent by 'Button'
            switch(NCode) {
            case WM_NOTIFICATION_CLICKED:
              // USER START (Optionally insert code for reacting on notification message)
              // USER END
              break;
            case WM_NOTIFICATION_RELEASED:
              // USER START (Optionally insert code for reacting on notification message)
         {
          char buf[32];
          hItem = WM_GetDialogItem(pMsg->hWin, ID_BUTTON_0);
          BUTTON_GetText(hItem, buf, 32);
          hItem = WM_GetDialogItem(pMsg->hWin, ID_TEXT_0);
          TEXT_SetText(hItem, buf);
          if(i < 100)
           ++i;
          hItem = WM_GetDialogItem(pMsg->hWin, ID_PROGBAR_0);
          PROGBAR_SetValue(hItem, i);
         }
              // USER END
              break;
            // USER START (Optionally insert additional code for further notification handling)
            // USER END
            }
            break;
          case ID_BUTTON_1: // Notifications sent by 'Button'
            switch(NCode) {
            case WM_NOTIFICATION_CLICKED:
              // USER START (Optionally insert code for reacting on notification message)
              // USER END
              break;
            case WM_NOTIFICATION_RELEASED:
              // USER START (Optionally insert code for reacting on notification message)
            {
           char buf[32];
        hItem = WM_GetDialogItem(pMsg->hWin, ID_BUTTON_1);
        BUTTON_GetText(hItem, buf, 32);
        hItem = WM_GetDialogItem(pMsg->hWin, ID_TEXT_0);
        TEXT_SetText(hItem, buf);
        if(i > 0)
          --i;
        hItem = WM_GetDialogItem(pMsg->hWin, ID_PROGBAR_0);
        PROGBAR_SetValue(hItem, i);
            }
              // USER END
              break;
            // USER START (Optionally insert additional code for further notification handling)
            // USER END
            }
            break;
          // USER START (Optionally insert additional code for further Ids)
          // USER END
          }
          break;
        // USER START (Optionally insert additional message handling)
        // USER END
      
    17. Компілюємо, заливаємо, запускаємо. Тицяємо на елементи, спостерігаємо за реакцією.

    Відео приклад роботи та практичні уроки





    субота, 9 листопада 2019 р.

    STEmWin: Підключення бібліотеки EmWin та перевірка роботи


    Передмова

    Свої графічні бібліотеки це добре, але професійна графічна бібліотека, що дозволяє створювати графічні інтерфейси користувача 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" в віконці файлового провідника.

    А тепер уважно крок за кроком робимо такі речі:
    1. В своєму засобі розробці в дереві проекту в теці "Drivers" створюємо теку "EmWin": на теці "Drivers" тиснемо ПКМ -> New -> Folder -> EmWin -> Finish;
    2. Аналогічно в теці "EmWin" створюємо теки "inc" та "src";
    3. Всі файли з теки "...\Middlewares\ST\STemWin\inc" репозиторію, копіюємо до теки "Drivers\EmWin\inc" вашого проекту;
    4. Файли "GUIConf.h", "LCDConf_FlexColor_Template.h" з теки "...\Middlewares\ST\STemWin\Config" репозиторію, копіюємо до теки "Drivers\EmWin\inc" вашого проекту;
    5. Файли "GUIConf.c""LCDConf_FlexColor_Template.c" з теки "...\Middlewares\ST\STemWin\Config" репозиторію, копіюємо до теки "Drivers\EmWin\src" вашого проекту;
    6. Перейдіть до свого засобу розробки і в дереві проекту знайдіть файли "LCDConf_FlexColor_Template.h" і  "LCDConf_FlexColor_Template.c" та переименуйте їх на "LCDConf_FlexColor.h" і "LCDConf_FlexColor.c";
    7. Файл "STemWin_CM4_wc32.a" з теки "...\Middlewares\ST\STemWin\Lib" репозиторію, копіюємо до теки "Drivers\EmWin" вашого проекту;
    8. Файл "GUI_X.c" з теки "...\Middlewares\ST\STemWin\OS" репозиторію, копіюємо до теки "Drivers\EmWin\src" вашого проекту;
    9. Тепер, як додали файли, потрібно вказати компілятору шлях до теки "Drivers\EmWin\inc" вашого проекту. Як це ми вже робили раніше, коли додали файли спрощеного драйверу ILI9341_LIGHT. Викликаємо властивості проекту: Project -> Properties -> C/C++ Build -> Settings -> Tool Settings -> C Compiler -> Directories -> Include path -> Add обираємо Workspace, та вказуємо в файловому провіднику шлях до теки "inc" бібліотеки "EmWin" вашого проекту;
    10. І на останок потрібно вказати лінковщику на файл "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

    1. В своєму засобі розробки відкриваємо файл "GUIConf.c" і шукаємо такий рядок:
      //
      // Define the available number of bytes available for the GUI
      //
      #define GUI_NUMBYTES  0x200000
    2. Зараз для GUI виділено аж 2Мб пам'яті RAM. Міняємо це значення на 32Кб:
      //
      // Define the available number of bytes available for the GUI
      //
      #define GUI_NUMBYTES  32 * 1024
      
    3. Відкриваємо файл "main.c" і додаємо такі рядки: 
      /* Private includes ----------------------------------------------------------*/
      /* USER CODE BEGIN Includes */
      #include "ili9341_light.h"
      #include "GUI.h"
      /* USER CODE END Includes */
      
    4. Та для проміжної перевірки, що все зроблено вірно, додамо ще виклик функції ініціалізації GUI: 
      /* USER CODE BEGIN 2 */
        GUI_Init();
        /* USER CODE END 2 */
      
    5. Компілюємо проект "Ctrl+B", як немає помилок, то все в порядку, зроблено все вірно. Продовжуємо налаштування далі;
    6. Відкриваємо файл "LCDConf_FlexColor.h", та додаємо рядок з "#include"
      #include "main.h"
      
    7. Відкриваємо файл "LCDConf_FlexColor.c", та додаємо такі рядки поруч з іншими "#include"
      #include "LCDConf_FlexColor.h"
      #include "ili9341_light.h"
      
    8. До функції "LcdWriteReg" додаємо виклик функції запису команди до дисплею: 
      /********************************************************************
      *
      *       LcdWriteReg
      *
      * Function description:
      *   Sets display register
      */
      static void LcdWriteReg(U16 Data)
      {
              // ... TBD by user
       LCD_CmdWrite(Data);
      }
      
    9. До функції "LcdWriteData" додаємо виклик функції запису даних до дисплею: 
      /********************************************************************
      *
      *       LcdWriteData
      *
      * Function description:
      *   Writes a value to a display register
      */
      static void LcdWriteData(U16 Data)
      {
              // ... TBD by user
       LCD_DataWrite(Data);
      }
      
    10. До функції "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++;
        }
      }
      
    11. До функції "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++;
        }
      }
      
    12. В розділі "Orientation" цього ж файлу "LCDConf_FlexColor.c" мають бути такі рядки: 
      //
      // Orientation
      //
      Config.Orientation = GUI_MIRROR_Y;
      GUIDRV_FlexColor_Config(pDevice, &Config);
      
    13. А в розділі "Set controller and operation mode" перевірте щоб був такий рядок:
      GUIDRV_FlexColor_SetFunc(pDevice, &PortAPI, GUIDRV_FLEXCOLOR_F66709, GUIDRV_FLEXCOLOR_M16C0B16);
      
    14. Функція "GUIDRV_FLEXCOLOR_F66709" з попереднього пункту обирається відповідно до документації, яка знаходится в репозиторію за шляхом "...\Middlewares\ST\STemWin\Documentation\STemWin544.pdf". В таблиці 33.42 вказано яка функція відповідає якому дисплею. Наш дисплей ILI9341 має функцію "GUIDRV_FLEXCOLOR_F66709";
    15. В функцію "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;
      }
      
    16. І на останок відкриваємо файл "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 */
      
    17. А в функцію "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 */
      }
      
    18. Остаточно перевіряємо проект на відсутність помилок. Компілюємо "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

    Підключення і налаштування бібліотеки для роботи з сенсорною панеллю детально описано в статті "Бібліотека touchscreen XPT2046 по шині SPI". Повторювати не має сенсу. Переходьте за ланкою і робіть, як зазначено в статті "Бібліотека touchscreen XPT2046 по шині SPI". Все абсолютно так само. Та не забувайте, що шина SPI, на якій "сидить" touch screen має бути не швидшою за 2.5Mb/s. 

    Тестування 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

    Файли

    Відео