суботу, 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

Файли

Відео









16 коментарів:

  1. Спрабавалі ці не падключыць гэтую плату да touchgfx? Вельмі хацелася б маляваць у ёй. Вельмі інтэрфейс прыгожы атрымліваецца. Зараз спрабую, не ведаю хопіць мазгоў на гэта ці не.
    На сайце ёсць мануал па падключэнне дысплея. Спробую.
    https://support.touchgfx.com/docs/development/touchgfx-hal-development/scenarios/scenarios-fmc

    ВідповістиВидалити
  2. Vse zrobyv po instrukciji, ale orymav pomylku - "undefined reference to `GUI_Init'" :-(

    ВідповістиВидалити
    Відповіді
    1. Значить не по інструкції. Компілятору вказали де знаходиться тека "inc" бібліотеки emWin?

      Видалити
  3. Доброго дня! Спробував знайти цю бібліотеку у CubeMX6.2 але виявилося, що вона більше не підтримується Кубом. А так треба терміново перевірити дісплей що надійшов з АліЕкспрес...

    ВідповістиВидалити
    Відповіді
    1. CubeMX тут взагалі ні до чого. Бібліотека emWin окрема сутність. Знаходиться в репозиторію разом з драйверами на ваш МК. Наприклад C:\Users\ваш_логін\STM32Cube\Repository\STM32Cube_FW_Fx_Vx.xx.x\Middlewares\ST\STemWi

      Видалити
  4. Автор видалив цей коментар.

    ВідповістиВидалити
  5. Добрый вечер. Такой вопрос "Hello, Worold!" на экране в зеркальном виде. Как исправить ?

    ВідповістиВидалити
  6. Разобрался у меня была строчка Config.Orientation = GUI_SWAP_XY |GUI_MIRROR_Y; а нужно было ее заменить как советует автор на эту Config.Orientation = GUI_MIRROR_Y; теперь все правильно отображается .

    ВідповістиВидалити
  7. Еще такой вопрос как включить русские символы ? А то на экране если написать на русском рисует краказяблики:)

    ВідповістиВидалити
    Відповіді
    1. В комплекті emWin є редактор шрифтів. Завантажуємо будь який шрифт з системи, чи малюємо свій. Зберігаємо файл з шрифтами як масив. Додаємо до проекту. Вказуємо на свій шрифт. Вуаля.

      Видалити
  8. Якщо кому-небудь згодиться - ініціалізація для SPI
    0хb6 (Display Function Control) - виставити біт SS (другий параметр команди)

    2)Функція GUIDRV_FlexColor_SetFunc(pDevice, &PortAPI, GUIDRV_FLEXCOLOR_F66709, GUIDRV_FLEXCOLOR_M24C0B8);

    3) Функція GUI_DEVICE_CreateAndLink(GUIDRV_FLEXCOLOR,GUICC_888, 0, 0);

    4)ініціалізувати PortAPI.pfWrite8_A0, PortAPI.pfWrite8_A1,PortAPI.pfWriteM8_A1,
    PortAPI.pfReadM8_A1 - це покажчики на функції читання/запису у дисплей, передаємо/приймаємо один байт або группу по 1 байту.Я використав HAL_SPI_Receive()

    P.S. Загрузка зображення недопустимо довга - десь 4 секунди(((

    ВідповістиВидалити
    Відповіді
    1. Дякую за цікавість до статті. І проведену роботу. Щоб збільшити швидкість оновлення екрану потрібно надсилати не попіксельно, а блоками з dma тоді швидкість буде норм.

      Видалити
  9. Адміністратор блогу видалив цей коментар.

    ВідповістиВидалити