понеділок, 25 березня 2019 р.

STM32: Бібліотека для роботи з LCD дисплеєм з контролером ST7735

update 10.03.2021: Замінив в файлі бібліотеки st7735.c дефайни з маніпулюванням регістрами GPIO на HAL функції. Для сумісності з будь яким чипом. Додав відео-підтримку до статті.

Передмова

Бібліотека призначена для роботи з LCD дисплеєм з контролером ST7735(S) по SPI шині. Для розмірів 128X160, 128X128 та 160X80. Дисплей можна придбати деінде, наприклад: ebay, aliexpress, тощо.

Я в проекті використовую:

Схема з'єднання

Схема з'єднання
Клацайте по зображенню, щоб збільшити. На деяких дисплеях, як на моєму, шпильки MOSI та SCK позначені як SDA та SCL. Та помилково на платі надруковано роздільна здатність як 128Х120, насправді роздільна здатність дисплею 128X160 точок.
Приклад дисплею ST7735S

Створюємо проект в CubeMX

Запускаємо CubeMX, обираємо свій мікроконтролер, або дошку. Та налаштовуємо проект:
Налаштування периферії
  1. Тиснемо RCC -> High Speed Clock (HSE) -> Crystal/Ceramic Resonator, та SYS -> Debug -> Serial Wire.
  2. Тиснемо SPI1.
  3. Обираємо Mode -> Transmit Only Master, та Hardware NSS Signal -> Disable, все інше без змін.
  4. Обираємо шпильки для сигналів BL (підсвітка), CS (вибір чипу), DC (дані/команда), RES (скидання). Шпильки називаємо так як на малюнку: ST7735_BL, ST7735_CS, ST7735_DC, ST7735_RES.
  5. Генеруємо проект: вказуємо шлях, даємо назву проекту "STM32F103C8T6_ST7735_SPI", обираємо свій засіб розробки. В мене це "Atolic Truestudio". Тиснемо "OK".

Демонстраційний код

Відкриваємо свій засіб розробки та експортуємо згенерований, CubeMX, проект. Файли st7735.h, st7735_cfg.h, fonts.h, testimg.h копіюємо до теки "inc" проекту, а файли st7735.c та fonts.c до теки "src" проекту.
Відкриваємо файл st7735_cfg.h та налаштовуємо бібліотеку.
Вказуємо до якого саме SPI під'єднано дисплей. В прикладі до SPI1, та якщо використовуєте DMA для передачі даних по SPI, то розкоментуйте рядок з "USE_SPI_DMA". Але хочу зауважити, що в режимі SPI з DMA екран дисплею промальовується повільніше ніж без DMA.
#define ST7735_SPI_PORT hspi1 //hspi1, hspi2, hspi3...
//#define USE_SPI_DMA   //if used DMA for SPI bus
Вказуємо тип дисплею. В прикладі це ST7735S.
//#define ST7735_1_8_DEFAULT_ORIENTATION // AliExpress/eBay 1.8" display, default orientation
#define ST7735S_1_8_DEFAULT_ORIENTATION  // WaveShare ST7735S-based 1.8" display, default orientation
//#define ST7735_1_44_DEFAULT_ORIENTATION  // 1.44" display, default orientation
//#define ST7735_MINI_DEFAULT_ORIENTATION  // mini 160x80 display (it's unlikely you want the default orientation)
Та якщо ви не дали назви шпилькам в CubeMX, то потрібно самому назначити порт і шпильку до відповідних назв:
//Port and pin connected signal 'RES' (reset) ST7735 display
#ifndef ST7735_RES_Pin
#define ST7735_RES_Pin   GPIO_PIN_12
#endif
#ifndef ST7735_RES_GPIO_Port
#define ST7735_RES_GPIO_Port  GPIOB
#endif
//Port and pin connected signal 'DC' (data or command) ST7735 display
#ifndef ST7735_DC_Pin
#define ST7735_DC_Pin   GPIO_PIN_13
#endif
#ifndef ST7735_DC_GPIO_Port
#define ST7735_DC_GPIO_Port  GPIOB
#endif
//Port and pin connected signal 'CS' (chip select) ST7735 display
#ifndef ST7735_CS_Pin
#define ST7735_CS_Pin   GPIO_PIN_14
#endif
#ifndef ST7735_CS_GPIO_Port
#define ST7735_CS_GPIO_Port  GPIOB
#endif
//Port and pin connected signal 'BL' (back light) ST7735 display
#ifndef ST7735_BL_Pin
#define ST7735_BL_Pin  GPIO_PIN_15
#endif
#ifndef ST7735_BL_GPIO_Port
#define ST7735_BL_GPIO_Port  GPIOB
#endif
Якщо ви вже дали назви шпилькам в програмі CubeMX, то про це вже не потрібно турбуватись. З налаштуванням бібліотеки це все.

Залишилось додати демонстраційний код до файлу main.c. Відкриваємо його і додаємо такі рядки в секцію "USER CODE BEGIN Includes":
/* USER CODE BEGIN Includes */
#include "st7735.h"
#include "fonts.h"
#include "testimg.h"
/* USER CODE END Includes */
В секцію "USER CODE BEGIN PV" оголошуємо глобальну змінну:
/* USER CODE BEGIN PV */
uint8_t r = 0;
/* USER CODE END PV */
В секцію "USER CODE BEGIN 0" додаємо функцію демонстрації можливостей бібліотеки:
/* USER CODE BEGIN 0 */
void demoTFT(void)
{
 ST7735_SetRotation(r);

 ST7735_FillScreen(ST7735_BLACK);

 for(int x = 0; x < ST7735_GetWidth(); x++)
 {
   ST7735_DrawPixel(x, 0, ST7735_WHITE);
   ST7735_DrawPixel(x, ST7735_GetHeight() - 1, ST7735_WHITE);
 }

 for(int y = 0; y < ST7735_GetHeight(); y++)
 {
   ST7735_DrawPixel(0, y, ST7735_WHITE);
   ST7735_DrawPixel(ST7735_GetWidth() - 1, y, ST7735_WHITE);
 }

 ST7735_DrawLine(0, 0, ST7735_GetWidth(), ST7735_GetHeight(), ST7735_WHITE);
 ST7735_DrawLine(ST7735_GetWidth(), 0, 0, ST7735_GetHeight(), ST7735_WHITE);

 HAL_Delay(2000);

 ST7735_FillScreen(ST7735_BLACK);

 for (int i = 0; i < ST7735_GetHeight(); i += 4)
 {
  ST7735_DrawFastHLine(0, i, ST7735_GetWidth() - 1, ST7735_WHITE);
 }

 for (int i = 0; i < ST7735_GetWidth(); i += 4)
 {
  ST7735_DrawFastVLine(i, 0, ST7735_GetHeight() - 1, ST7735_WHITE);
 }

 HAL_Delay(2000);

 // Check fonts
 ST7735_FillScreen(ST7735_BLACK);
 ST7735_DrawString(0, 0, "Font_7x10, red on black, lorem ipsum dolor sit amet", Font_7x10, ST7735_RED, ST7735_BLACK);
 ST7735_DrawString(0, 3*10, "Font_11x18, green, lorem ipsum", Font_11x18, ST7735_GREEN, ST7735_BLACK);
 ST7735_DrawString(0, 3*10+3*18, "Font_16x26", Font_16x26, ST7735_BLUE, ST7735_BLACK);
 HAL_Delay(2000);

 // Check colors
 ST7735_FillScreen(ST7735_BLACK);
 ST7735_DrawString(0, 0, "BLACK", Font_11x18, ST7735_WHITE, ST7735_BLACK);
 HAL_Delay(500);

 ST7735_FillScreen(ST7735_BLUE);
 ST7735_DrawString(0, 0, "BLUE", Font_11x18, ST7735_BLACK, ST7735_BLUE);
 HAL_Delay(500);

 ST7735_FillScreen(ST7735_RED);
 ST7735_DrawString(0, 0, "RED", Font_11x18, ST7735_BLACK, ST7735_RED);
 HAL_Delay(500);

 ST7735_FillScreen(ST7735_GREEN);
 ST7735_DrawString(0, 0, "GREEN", Font_11x18, ST7735_BLACK, ST7735_GREEN);
 HAL_Delay(500);

 ST7735_FillScreen(ST7735_CYAN);
 ST7735_DrawString(0, 0, "CYAN", Font_11x18, ST7735_BLACK, ST7735_CYAN);
 HAL_Delay(500);

 ST7735_FillScreen(ST7735_MAGENTA);
 ST7735_DrawString(0, 0, "MAGENTA", Font_11x18, ST7735_BLACK, ST7735_MAGENTA);
 HAL_Delay(500);

 ST7735_FillScreen(ST7735_YELLOW);
 ST7735_DrawString(0, 0, "YELLOW", Font_11x18, ST7735_BLACK, ST7735_YELLOW);
 HAL_Delay(500);

 ST7735_FillScreen(ST7735_WHITE);
 ST7735_DrawString(0, 0, "WHITE", Font_11x18, ST7735_BLACK, ST7735_WHITE);
 HAL_Delay(500);

 // Draw circles
 ST7735_FillScreen(ST7735_BLACK);
 for (int i = 0; i < ST7735_GetHeight() / 2; i += 2)
 {
  ST7735_DrawCircle(ST7735_GetWidth() / 2, ST7735_GetHeight() / 2, i, ST7735_YELLOW);
 }
 HAL_Delay(1000);

 ST7735_FillScreen(ST7735_BLACK);
 ST7735_FillTriangle(0, 0, ST7735_GetWidth() / 2, ST7735_GetHeight(), ST7735_GetWidth(), 0, ST7735_RED);
 HAL_Delay(1000);

 ST7735_FillScreen(ST7735_BLACK);
 ST7735_DrawImage(0, 0, 128, 128, (uint16_t*) test_img_128x128);
 HAL_Delay(3000);

 r++;
}
/* USER CODE END 0 */
Та додаємо код що ініціалізує дисплей, вмикає підсвітку, та по колу запускає демонстрацію:
/* USER CODE BEGIN 2 */
  ST7735_Init();
  ST7735_Backlight_On();
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
   demoTFT();
    /* USER CODE END WHILE */

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

Файли для завантаження

Відео інструкція


Відео-демонстрація


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

  1. Доброго дня!
    Дякую за статтю.
    Підкажіть будь ласка, якою програмою можна конвертувати картинки в масив для даної бібліотеки? Дякую.

    ВідповістиВидалити
    Відповіді
    1. Перепрошую, я не знаю. Брав готову картинку з іншого прикладу.

      Видалити
  2. Відповіді
    1. Скорее всего какойто глюк HAL/компилятор (MDK) (под F042), т.к. тот же проект скомпилированный под F103 работает прекрасно.
      А по данным, уходид в хард фол при выполнении ST7735_Init() далее вызов ST7735_ExecuteCommandList(init_cmds1); далее при передаче данных ф-й ST7735_WriteData((uint8_t*)addr, numArgs); вызывается HAL_SPI_Transmit(&ST7735_SPI_PORT, buff, buff_size, 100); и уход в хард фол со строки: hspi->Instance->DR = *((uint16_t *)pData).

      Видалити
    2. Може якісь особливості налаштування SPI в F042? Швидкість передачі не перевищує можливості ST7735?

      Видалити
    3. Дуже глибоко не копав, інші проєкти працюють на цьому контроллеру.
      PS: Дуже дякую за цю бібліотеку, трішки дописав щоб була можливість виводити данні в Landscape Mode.

      Видалити
  3. Thanks for your tutorials, I'm doing first steps with HAL and LL. I've used SPL before but ST don't support them anymore.
    I don't understand your language but Google translate well !
    I did some corrections to your nice job to get DMA working. In brief you must use a buffer to burst data with DMA, check function ST7735_FillRectangle. FastVline and FastHline can be treated as rectangle. now display is very fast!
    Best regards!
    https://github.com/ScarsFun/STM32F103C8T6_cubeIDE_ST7735_1.8_DMA

    ВідповістиВидалити
  4. Привіт! Дякую! Мануал дуже допоміг мені почати розбиратися у програмуванні під STM32.
    Хочу додати, що у CubeMX треба вибрати Pull-up для всіх GPIO пінів. Можливо, якомусь новачку це зекономить купу часу))

    ВідповістиВидалити
  5. Здравствуйте, как вывести значение переменной на экран?

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