跳转至

rocketpi_spi_lcd_speedtest

效果展示

lcd_speedtest

功能说明

  • SPI LCD(240x240)全屏渲染帧率测试

硬件连接

image-20251217035516546

驱动以及测试代码

Core/Src/main.c
/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2025 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "adc.h"
#include "dma.h"
#include "spi.h"
#include "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "st7789.h"
#include "font16x24_ascii.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
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_DMA_Init();
  MX_USART2_UART_Init();
  MX_SPI1_Init();
  MX_ADC1_Init();
  /* USER CODE BEGIN 2 */
    extern const unsigned char rgb565_grid_240x240[] ;

  ST7789_Init();
    ST7789_Clear(GRED);

  ST7789_TestFrameRate(); /* 帧率测试 */

  /* USER CODE END 2 */

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

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

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Configure the main internal regulator output voltage
  */
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 4;
  RCC_OscInitStruct.PLL.PLLN = 84;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 7;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
bsp/st7789/font16x24_ascii.h
// Auto-generated 16x24 ASCII bitmap font (0x20..0x7E)
// Each glyph: 24 rows of uint16_t, MSB=leftmost pixel

#ifndef FONT16X24_ASCII_H
#define FONT16X24_ASCII_H

#include <stdint.h>
#include "fonts.h"
//typedef struct { uint16_t width; uint16_t height;  uint16_t *data; } FontDef;

  uint16_t Font16x24_ASCII[] = {
  /* 0x20 ' ' */
  0x0000,  0x0000,  0x0000,  0x0000,  0x0000,  0x0000,  0x0000,  0x0000,
  0x0000,  0x0000,  0x0000,  0x0000,  0x0000,  0x0000,  0x0000,  0x0000,
  0x0000,  0x0000,  0x0000,  0x0000,  0x0000,  0x0000,  0x0000,  0x0000,
  /* 0x21 '!' */
  0x07FF,  0x07FF,  0x07FF,  0x07FF,  0x07FF,  0x07FF,  0x07FF,  0x07FF,
  0x07FF,  0x07FF,  0x07FF,  0x07FF,  0x07FF,  0x07FF,  0x07FF,  0x07FF,
  0x07FF,  0x0000,  0x0000,  0x0000,  0x07FF,  0x07FF,  0x07FF,  0x07FF,
  /* 0x22 '"' */
  0x3E1F,  0x3E1F,  0x3E1F,  0x3E1F,  0x3E1F,  0x3E1F,  0x3E1F,  0x3E1F,
  0x3E1F,  0x3E1F,  0x3E1F,  0x3E1F,  0x3E1F,  0x3E1F,  0x3E1F,  0x3E1F,
  0x3E1F,  0x3E1F,  0x3E1F,  0x3E1F,  0x3E1F,  0x3E1F,  0x3E1F,  0x3E1F,
  /* 0x23 '#' */
  0x031C,  0x031C,  0x0318,  0x0338,  0x0338,  0x0238,  0x7FFE,  0x7FFE,
  0x7FFE,  0x7FFE,  0x0660,  0x0460,  0x0460,  0x1C40,  0xFFFC,  0xFFFC,
  0xFFFC,  0xFFFC,  0x18C0,  0x3880,  0x3880,  0x3980,  0x3980,  0x3980,
  /* 0x24 '$' */
  0x0300,  0x0300,  0x0300,  0x0300,  0x1FF8,  0x3FFC,  0xFB04,  0xE300,
  0xE300,  0xE300,  0xFB00,  0x3FC0,  0x07FC,  0x031F,  0x0307,  0x0307,
  0x0307,  0xC31F,  0xFFFC,  0x1FF8,  0x0300,  0x0300,  0x0300,  0x0300,
  /* 0x25 '%' */
  0x3C00,  0x7380,  0x7380,  0x4180,  0x4180,  0xC180,  0x4180,  0x7380,
  0x7380,  0x3E1E,  0x01E0,  0x01E0,  0x0780,  0x783C,  0x783C,  0x0042,
  0x0042,  0x01C3,  0x01C3,  0x01C3,  0x01C3,  0x0042,  0x0042,  0x003C,
  /* 0x26 '&' */
  0x0780,  0x1FC0,  0x1FC0,  0x1C00,  0x1C00,  0x1800,  0x1C00,  0x1C00,
  0x1C00,  0x1E00,  0x3F00,  0x3F00,  0x2306,  0x6186,  0x6186,  0x60C6,
  0x60C6,  0x607C,  0x603C,  0x603C,  0x787C,  0x3FFC,  0x3FFC,  0x1F86,
  /* 0x27 ''' */
  0x07FF,  0x07FF,  0x07FF,  0x07FF,  0x07FF,  0x07FF,  0x07FF,  0x07FF,
  0x07FF,  0x07FF,  0x07FF,  0x07FF,  0x07FF,  0x07FF,  0x07FF,  0x07FF,
  0x07FF,  0x07FF,  0x07FF,  0x07FF,  0x07FF,  0x07FF,  0x07FF,  0x07FF,
  /* 0x28 '(' */
  0x0018,  0x00F8,  0x07E0,  0x07E0,  0x07E0,  0x07E0,  0x1F00,  0x1F00,
  0x1F00,  0x1F00,  0x1F00,  0x1F00,  0x1F00,  0x1F00,  0x1F00,  0x1F00,
  0x1F00,  0x1F00,  0x07E0,  0x07E0,  0x07E0,  0x07E0,  0x00F8,  0x0018,
  /* 0x29 ')' */
  0x1F00,  0x1F00,  0x07E0,  0x07E0,  0x07E0,  0x00F8,  0x00F8,  0x00F8,
  0x00F8,  0x00F8,  0x00FF,  0x001F,  0x001F,  0x00FF,  0x00F8,  0x00F8,
  0x00F8,  0x00F8,  0x00F8,  0x07E0,  0x07E0,  0x07E0,  0x1F00,  0x1F00,
  /* 0x2A '*' */
  0x0180,  0x0180,  0x0180,  0x0180,  0x0180,  0x6186,  0x6186,  0x1DBE,
  0x1DBE,  0x1DBE,  0x03F0,  0x03F0,  0x03F0,  0x03F0,  0x1DBE,  0x1DBE,
  0x1DBE,  0x6186,  0x6186,  0x0180,  0x0180,  0x0180,  0x0180,  0x0180,
  /* 0x2B '+' */
  0x01C0,  0x01C0,  0x01C0,  0x01C0,  0x01C0,  0x01C0,  0x01C0,  0x01C0,
  0x01C0,  0x01C0,  0x7FFE,  0x7FFE,  0x7FFE,  0x7FFE,  0x01C0,  0x01C0,
  0x01C0,  0x01C0,  0x01C0,  0x01C0,  0x01C0,  0x01C0,  0x01C0,  0x01C0,
  /* 0x2C ',' */
  0x1FF8,  0x1FF8,  0x1FF8,  0x1FF8,  0x1FF8,  0x1FF8,  0x1FF8,  0x1FF8,
  0x1FF8,  0x1FF8,  0x1FF8,  0x1FF8,  0x1FC0,  0x1FC0,  0x1FC0,  0x1FC0,
  0x1FC0,  0x1FC0,  0x1FC0,  0x1FC0,  0xFC00,  0xFC00,  0xFC00,  0xFC00,
  /* 0x2D '-' */
  0x3FFC,  0x3FFC,  0x3FFC,  0x3FFC,  0x3FFC,  0x3FFC,  0x3FFC,  0x3FFC,
  0x3FFC,  0x3FFC,  0x3FFC,  0x3FFC,  0x3FFC,  0x3FFC,  0x3FFC,  0x3FFC,
  0x3FFC,  0x3FFC,  0x3FFC,  0x3FFC,  0x3FFC,  0x3FFC,  0x3FFC,  0x3FFC,
  /* 0x2E '.' */
  0x0000,  0x0000,  0x0000,  0x0000,  0x0000,  0x0000,  0x0000,  0x0000,
  0x0000,  0x0000,  0x0000,  0x0000,  0x0000,  0x0000,  0x0000,  0x0000,
  0x0000,  0x0000,  0x0000,  0x03C0,  0x03C0,  0x03C0,  0x03C0,  0x0000,
  /* 0x2F '/' */
  0x000E,  0x000E,  0x000E,  0x0038,  0x0038,  0x0070,  0x0070,  0x0070,
  0x01F0,  0x01C0,  0x01C0,  0x01C0,  0x0380,  0x0380,  0x0380,  0x0E00,
  0x0E00,  0x1C00,  0x1C00,  0x1C00,  0x7000,  0x7000,  0x7000,  0xE000,
  /* 0x30 '0' */
  0x0FF0,  0x1FF8,  0x1FF8,  0x7C3E,  0x7C3E,  0x700E,  0x700E,  0x700F,
  0x700F,  0xF007,  0xF3C7,  0xF3C7,  0xF3C7,  0xF007,  0xF007,  0x700F,
  0x700F,  0x700E,  0x700E,  0x700E,  0x7C3E,  0x1FF8,  0x1FF8,  0x0FF0,
  /* 0x31 '1' */
  0x1FC0,  0x3FC0,  0x3FC0,  0x23C0,  0x23C0,  0x03C0,  0x03C0,  0x03C0,
  0x03C0,  0x03C0,  0x03C0,  0x03C0,  0x03C0,  0x03C0,  0x03C0,  0x03C0,
  0x03C0,  0x03C0,  0x03C0,  0x03C0,  0x03C0,  0x3FFF,  0x3FFF,  0x3FFF,
  /* 0x32 '2' */
  0x1FF0,  0x7FF8,  0x7FF8,  0x603E,  0x603E,  0x000E,  0x000E,  0x000E,
  0x000E,  0x000E,  0x0038,  0x0038,  0x0070,  0x01C0,  0x01C0,  0x0380,
  0x0380,  0x0E00,  0x1C00,  0x1C00,  0x7000,  0x7FFE,  0x7FFE,  0x7FFE,
  /* 0x33 '3' */
  0x1FF0,  0x7FF8,  0x7FF8,  0x603E,  0x603E,  0x000E,  0x000E,  0x000E,
  0x000E,  0x003E,  0x0FF0,  0x0FF0,  0x0FF8,  0x003E,  0x003E,  0x000E,
  0x000E,  0x000F,  0x000F,  0x000F,  0x603E,  0xFFF8,  0xFFF8,  0x1FF0,
  /* 0x34 '4' */
  0x00F0,  0x00F0,  0x00F0,  0x01F0,  0x01F0,  0x0770,  0x0670,  0x0E70,
  0x0E70,  0x1870,  0x1070,  0x1070,  0x7070,  0xE070,  0xE070,  0xFFFE,
  0xFFFE,  0xFFFE,  0x0070,  0x0070,  0x0070,  0x0070,  0x0070,  0x0070,
  /* 0x35 '5' */
  0x7FF8,  0x7FF8,  0x7FF8,  0x7000,  0x7000,  0x7000,  0x7000,  0x7FF0,
  0x7FF0,  0x7FF8,  0x603E,  0x603E,  0x000E,  0x000E,  0x000E,  0x000E,
  0x000E,  0x000E,  0x000E,  0x000E,  0x603E,  0x7FF8,  0x7FF8,  0x1FC0,
  /* 0x36 '6' */
  0x03F8,  0x0FFE,  0x0FFE,  0x1E06,  0x1E06,  0x7C00,  0x7000,  0x7000,
  0x7000,  0x73F0,  0xFFFE,  0xFFFE,  0xFC0E,  0xF00F,  0xF00F,  0x7007,
  0x7007,  0x7007,  0x700F,  0x700F,  0x7C0E,  0x1FFE,  0x1FFE,  0x0FF0,
  /* 0x37 '7' */
  0xFFFF,  0xFFFE,  0xFFFE,  0x000E,  0x000E,  0x000E,  0x0038,  0x0038,
  0x0038,  0x0070,  0x0070,  0x0070,  0x0070,  0x01C0,  0x01C0,  0x01C0,
  0x01C0,  0x03C0,  0x0380,  0x0380,  0x0380,  0x0E00,  0x0E00,  0x0E00,
  /* 0x38 '8' */
  0x0FF0,  0x1FF8,  0x1FF8,  0x7C3E,  0x7C3E,  0x700E,  0x700E,  0x700E,
  0x700E,  0x1C3E,  0x0FF8,  0x0FF8,  0x1FF8,  0x7C0E,  0x7C0E,  0x700F,
  0x700F,  0xF007,  0xF00F,  0xF00F,  0x7C0E,  0x7FFE,  0x7FFE,  0x0FF0,
  /* 0x39 '9' */
  0x0FF0,  0x1FF8,  0x1FF8,  0x7C3E,  0x7C3E,  0x700E,  0xF00E,  0xF00F,
  0xF00F,  0x700F,  0x7C3F,  0x7C3F,  0x1FFF,  0x0FC7,  0x0FC7,  0x000F,
  0x000F,  0x000E,  0x000E,  0x000E,  0x0078,  0x1FF8,  0x1FF8,  0x0FC0,
  /* 0x3A ':' */
  0xFFFF,  0xFFFF,  0xFFFF,  0xFFFF,  0xFFFF,  0xFFFF,  0xFFFF,  0x0000,
  0x0000,  0x0000,  0x0000,  0x0000,  0x0000,  0x0000,  0x0000,  0x0000,
  0x0000,  0xFFFF,  0xFFFF,  0xFFFF,  0xFFFF,  0xFFFF,  0xFFFF,  0xFFFF,
  /* 0x3B ';' */
  0x1FF8,  0x1FF8,  0x1FF8,  0x1FF8,  0x1FF8,  0x0000,  0x0000,  0x0000,
  0x0000,  0x0000,  0x0000,  0x0000,  0x0000,  0x0000,  0x1FF8,  0x1FF8,
  0x1FF8,  0x1FF8,  0x1FF8,  0x1FC0,  0x1FC0,  0x1FC0,  0xFC00,  0xFC00,
  /* 0x3C '<' */
  0x0002,  0x0002,  0x001E,  0x001E,  0x01FC,  0x01FC,  0x01FC,  0x07C0,
  0x07C0,  0x7E00,  0x7E00,  0x7800,  0x7800,  0x7E00,  0x7E00,  0x07C0,
  0x07C0,  0x01FC,  0x01FC,  0x01FC,  0x001E,  0x001E,  0x0002,  0x0002,
  /* 0x3D '=' */
  0x7FFE,  0x7FFE,  0x7FFE,  0x7FFE,  0x7FFE,  0x7FFE,  0x7FFE,  0x0000,
  0x0000,  0x0000,  0x0000,  0x0000,  0x0000,  0x0000,  0x0000,  0x0000,
  0x0000,  0x7FFE,  0x7FFE,  0x7FFE,  0x7FFE,  0x7FFE,  0x7FFE,  0x7FFE,
  /* 0x3E '>' */
  0x4000,  0x4000,  0x7C00,  0x7C00,  0x3F80,  0x3F80,  0x3F80,  0x03F0,
  0x03F0,  0x007E,  0x007E,  0x001E,  0x001E,  0x007E,  0x007E,  0x03F0,
  0x03F0,  0x3F80,  0x3F80,  0x3F80,  0x7C00,  0x7C00,  0x4000,  0x4000,
  /* 0x3F '?' */
  0x1FE0,  0x3FF8,  0x3FF8,  0x203C,  0x203C,  0x001C,  0x001C,  0x0038,
  0x0038,  0x00E0,  0x03C0,  0x03C0,  0x07C0,  0x0700,  0x0700,  0x0700,
  0x0700,  0x0000,  0x0000,  0x0000,  0x0700,  0x0700,  0x0700,  0x0700,
  /* 0x40 '@' */
  0x03F0,  0x0FFC,  0x0FFC,  0x3C1E,  0x380E,  0x7003,  0x7003,  0x71F3,
  0x43FF,  0xC38F,  0xC38F,  0xC603,  0xC603,  0xC38F,  0xC38F,  0x43FF,
  0x71F3,  0x7000,  0x7000,  0x3800,  0x0E00,  0x07FC,  0x07FC,  0x01FC,
  /* 0x41 'A' */
  0x03C0,  0x03C0,  0x03C0,  0x03E0,  0x03E0,  0x0660,  0x0660,  0x0630,
  0x0630,  0x0C30,  0x0C30,  0x0C30,  0x0C3C,  0x381C,  0x381C,  0x3FFC,
  0x3FFC,  0x3FFC,  0x780E,  0x780E,  0x700E,  0x700E,  0x700E,  0x700F,
  /* 0x42 'B' */
  0x7FE0,  0x7FF8,  0x7FF8,  0x7018,  0x7018,  0x701E,  0x701E,  0x7018,
  0x7018,  0x7078,  0x7FF0,  0x7FF0,  0x7FF0,  0x7018,  0x7018,  0x700E,
  0x700E,  0x700E,  0x700E,  0x700E,  0x701E,  0x7FF8,  0x7FF8,  0x7FF0,
  /* 0x43 'C' */
  0x03F8,  0x0FFF,  0x0FFF,  0x1E06,  0x1E06,  0x7C00,  0x7000,  0x7000,
  0x7000,  0x7000,  0x7000,  0x7000,  0x7000,  0x7000,  0x7000,  0x7000,
  0x7000,  0x7000,  0x7C00,  0x7C00,  0x1E06,  0x0FFF,  0x0FFF,  0x03F8,
  /* 0x44 'D' */
  0xFFC0,  0xFFF8,  0xFFF8,  0xF07E,  0xF07E,  0xF00E,  0xF00E,  0xF00F,
  0xF00F,  0xF007,  0xF007,  0xF007,  0xF007,  0xF007,  0xF007,  0xF00F,
  0xF00F,  0xF00E,  0xF00E,  0xF00E,  0xF07E,  0xFFF8,  0xFFF8,  0xFFC0,
  /* 0x45 'E' */
  0xFFFF,  0xFFFF,  0xFFFF,  0xE000,  0xE000,  0xE000,  0xE000,  0xE000,
  0xE000,  0xE000,  0xFFFC,  0xFFFC,  0xFFFC,  0xE000,  0xE000,  0xE000,
  0xE000,  0xE000,  0xE000,  0xE000,  0xE000,  0xFFFF,  0xFFFF,  0xFFFF,
  /* 0x46 'F' */
  0xFFFF,  0xFFFF,  0xFFFF,  0xF800,  0xF800,  0xF800,  0xF800,  0xF800,
  0xF800,  0xF800,  0xFFFC,  0xFFFC,  0xFFFC,  0xF800,  0xF800,  0xF800,
  0xF800,  0xF800,  0xF800,  0xF800,  0xF800,  0xF800,  0xF800,  0xF800,
  /* 0x47 'G' */
  0x03F8,  0x1FFE,  0x1FFE,  0x1E06,  0x1E06,  0x7000,  0x7000,  0xF000,
  0xF000,  0xE000,  0xE07F,  0xE07F,  0xE07F,  0xE007,  0xE007,  0xF007,
  0xF007,  0x7007,  0x7007,  0x7007,  0x1C0F,  0x1FFE,  0x1FFE,  0x03F8,
  /* 0x48 'H' */
  0xF007,  0xF007,  0xF007,  0xF007,  0xF007,  0xF007,  0xF007,  0xF007,
  0xF007,  0xF007,  0xFFFF,  0xFFFF,  0xFFFF,  0xF007,  0xF007,  0xF007,
  0xF007,  0xF007,  0xF007,  0xF007,  0xF007,  0xF007,  0xF007,  0xF007,
  /* 0x49 'I' */
  0xFFFC,  0xFFFC,  0xFFFC,  0x03C0,  0x03C0,  0x03C0,  0x03C0,  0x03C0,
  0x03C0,  0x03C0,  0x03C0,  0x03C0,  0x03C0,  0x03C0,  0x03C0,  0x03C0,
  0x03C0,  0x03C0,  0x03C0,  0x03C0,  0x03C0,  0xFFFC,  0xFFFC,  0xFFFC,
  /* 0x4A 'J' */
  0x07FC,  0x07FC,  0x07FC,  0x001C,  0x001C,  0x001C,  0x001C,  0x001C,
  0x001C,  0x001C,  0x001C,  0x001C,  0x001C,  0x001C,  0x001C,  0x001C,
  0x001C,  0x001C,  0xC01C,  0xC01C,  0xE03C,  0xFFF8,  0xFFF8,  0x3FE0,
  /* 0x4B 'K' */
  0xF01E,  0xF03C,  0xF03C,  0xF070,  0xF070,  0xF1E0,  0xF3C0,  0xF780,
  0xF780,  0xFE00,  0xFE00,  0xFE00,  0xFB80,  0xF3C0,  0xF3C0,  0xF1C0,
  0xF1C0,  0xF060,  0xF070,  0xF070,  0xF030,  0xF01C,  0xF01C,  0xF01E,
  /* 0x4C 'L' */
  0xE000,  0xE000,  0xE000,  0xE000,  0xE000,  0xE000,  0xE000,  0xE000,
  0xE000,  0xE000,  0xE000,  0xE000,  0xE000,  0xE000,  0xE000,  0xE000,
  0xE000,  0xE000,  0xE000,  0xE000,  0xE000,  0xFFFE,  0xFFFE,  0xFFFE,
  /* 0x4D 'M' */
  0x781E,  0x781E,  0x781E,  0x7C1E,  0x7C1E,  0x743E,  0x742E,  0x766E,
  0x766E,  0x726E,  0x73CE,  0x73CE,  0x73CE,  0x71CE,  0x71CE,  0x700E,
  0x700E,  0x700E,  0x700E,  0x700E,  0x700E,  0x700E,  0x700E,  0x700E,
  /* 0x4E 'N' */
  0xF007,  0xFC07,  0xFC07,  0xFC07,  0xFC07,  0xFE07,  0xFE07,  0xF387,
  0xF387,  0xF387,  0xF187,  0xF187,  0xF1C7,  0xF1C7,  0xF1C7,  0xF077,
  0xF077,  0xF077,  0xF03F,  0xF03F,  0xF03F,  0xF03F,  0xF03F,  0xF00F,
  /* 0x4F 'O' */
  0x0FF0,  0x1FF8,  0x1FF8,  0x7C3E,  0x7C3E,  0x700E,  0x700F,  0xF007,
  0xF007,  0xF007,  0xF007,  0xF007,  0xF007,  0xF007,  0xF007,  0xF007,
  0xF007,  0x700F,  0x700E,  0x700E,  0x7C3E,  0x1FF8,  0x1FF8,  0x0FF0,
  /* 0x50 'P' */
  0xFFF0,  0xFFF8,  0xFFF8,  0xE03E,  0xE03E,  0xE00E,  0xE00E,  0xE00E,
  0xE00E,  0xE00E,  0xE03E,  0xE03E,  0xFFF8,  0xFFF0,  0xFFF0,  0xE000,
  0xE000,  0xE000,  0xE000,  0xE000,  0xE000,  0xE000,  0xE000,  0xE000,
  /* 0x51 'Q' */
  0x0FF0,  0x1FF8,  0x1FF8,  0x7C3E,  0x700E,  0x700F,  0xF007,  0xF007,
  0xF007,  0xF007,  0xF007,  0xF007,  0xF007,  0xF007,  0x700F,  0x700E,
  0x7C3E,  0x7C3E,  0x1FF8,  0x0FF0,  0x0078,  0x003E,  0x003E,  0x0008,
  /* 0x52 'R' */
  0x7FC0,  0x7FE0,  0x7FE0,  0x7070,  0x7070,  0x7030,  0x7030,  0x7030,
  0x7030,  0x7070,  0x7FE0,  0x7FE0,  0x7FC0,  0x71E0,  0x71E0,  0x7070,
  0x7070,  0x7030,  0x703C,  0x703C,  0x701C,  0x701E,  0x701E,  0x700E,
  /* 0x53 'S' */
  0x0FF0,  0x1FFE,  0x1FFE,  0x7C06,  0x7C06,  0x7000,  0x7000,  0x7000,
  0x7000,  0x7C00,  0x1FF0,  0x1FF0,  0x03FE,  0x003E,  0x003E,  0x000F,
  0x000F,  0x0007,  0x000F,  0x000F,  0x603E,  0x7FFE,  0x7FFE,  0x1FF0,
  /* 0x54 'T' */
  0xFFFF,  0xFFFF,  0xFFFF,  0x01C0,  0x01C0,  0x01C0,  0x01C0,  0x01C0,
  0x01C0,  0x01C0,  0x01C0,  0x01C0,  0x01C0,  0x01C0,  0x01C0,  0x01C0,
  0x01C0,  0x01C0,  0x01C0,  0x01C0,  0x01C0,  0x01C0,  0x01C0,  0x01C0,
  /* 0x55 'U' */
  0x700F,  0x700F,  0x700F,  0x700F,  0x700F,  0x700F,  0x700F,  0x700F,
  0x700F,  0x700F,  0x700F,  0x700F,  0x700F,  0x700F,  0x700F,  0x700F,
  0x700F,  0x700F,  0x700E,  0x700E,  0x7C3E,  0x1FF8,  0x1FF8,  0x0FF0,
  /* 0x56 'V' */
  0x700E,  0x700E,  0x700E,  0x780E,  0x780E,  0x381E,  0x381C,  0x381C,
  0x381C,  0x0C1C,  0x0C30,  0x0C30,  0x0C30,  0x0C30,  0x0C30,  0x0630,
  0x0630,  0x0660,  0x0660,  0x0660,  0x03E0,  0x03C0,  0x03C0,  0x03C0,
  /* 0x57 'W' */
  0xC006,  0xC006,  0xC006,  0xC006,  0xC006,  0x6006,  0x6386,  0x639C,
  0x639C,  0x639C,  0x629C,  0x629C,  0x62DC,  0x66DC,  0x66DC,  0x265C,
  0x265C,  0x3C7C,  0x3C78,  0x3C78,  0x3C78,  0x3C78,  0x3C78,  0x3C38,
  /* 0x58 'X' */
  0x780E,  0x381E,  0x381E,  0x3C1C,  0x3C1C,  0x0C30,  0x0630,  0x07E0,
  0x07E0,  0x03E0,  0x03C0,  0x03C0,  0x03C0,  0x07E0,  0x07E0,  0x0630,
  0x0630,  0x0C30,  0x3C1C,  0x3C1C,  0x381E,  0x700E,  0x700E,  0x700F,
  /* 0x59 'Y' */
  0x700F,  0x780E,  0x780E,  0x381C,  0x381C,  0x3C1C,  0x0C30,  0x0670,
  0x0670,  0x0660,  0x03C0,  0x03C0,  0x03C0,  0x01C0,  0x01C0,  0x01C0,
  0x01C0,  0x01C0,  0x01C0,  0x01C0,  0x01C0,  0x01C0,  0x01C0,  0x01C0,
  /* 0x5A 'Z' */
  0x7FFE,  0x7FFE,  0x7FFE,  0x001E,  0x001E,  0x0018,  0x0070,  0x0070,
  0x0070,  0x00E0,  0x0180,  0x0180,  0x0180,  0x0700,  0x0700,  0x0E00,
  0x0E00,  0x0E00,  0x1800,  0x1800,  0x7000,  0x7FFF,  0x7FFF,  0x7FFF,
  /* 0x5B '[' */
  0x1FFF,  0x1FFF,  0x1F00,  0x1F00,  0x1F00,  0x1F00,  0x1F00,  0x1F00,
  0x1F00,  0x1F00,  0x1F00,  0x1F00,  0x1F00,  0x1F00,  0x1F00,  0x1F00,
  0x1F00,  0x1F00,  0x1F00,  0x1F00,  0x1F00,  0x1F00,  0x1FFF,  0x1FFF,
  /* 0x5C '\' */
  0xE000,  0x7000,  0x7000,  0x7000,  0x1C00,  0x1C00,  0x1C00,  0x0E00,
  0x0E00,  0x0380,  0x0380,  0x0380,  0x01C0,  0x01C0,  0x01C0,  0x01F0,
  0x0070,  0x0070,  0x0070,  0x0038,  0x0038,  0x000E,  0x000E,  0x000E,
  /* 0x5D ']' */
  0x1FF8,  0x1FF8,  0x00F8,  0x00F8,  0x00F8,  0x00F8,  0x00F8,  0x00F8,
  0x00F8,  0x00F8,  0x00F8,  0x00F8,  0x00F8,  0x00F8,  0x00F8,  0x00F8,
  0x00F8,  0x00F8,  0x00F8,  0x00F8,  0x00F8,  0x00F8,  0x1FF8,  0x1FF8,
  /* 0x5E '^' */
  0x03C0,  0x03C0,  0x03C0,  0x03C0,  0x07E0,  0x07E0,  0x07E0,  0x07E0,
  0x0670,  0x0670,  0x0670,  0x0670,  0x0C30,  0x0C30,  0x0C30,  0x0C30,
  0x381C,  0x381C,  0x381C,  0x381C,  0x700E,  0x700E,  0x700E,  0x700E,
  /* 0x5F '_' */
  0xFFFE,  0xFFFE,  0xFFFE,  0xFFFE,  0xFFFE,  0xFFFE,  0xFFFE,  0xFFFE,
  0xFFFE,  0xFFFE,  0xFFFE,  0xFFFE,  0xFFFE,  0xFFFE,  0xFFFE,  0xFFFE,
  0xFFFE,  0xFFFE,  0xFFFE,  0xFFFE,  0xFFFE,  0xFFFE,  0xFFFE,  0xFFFE,
  /* 0x60 '`' */
  0xF800,  0xF800,  0xF800,  0xF800,  0xF800,  0xF800,  0x1F00,  0x1F00,
  0x1F00,  0x1F00,  0x1F00,  0x1F00,  0x07E0,  0x07E0,  0x07E0,  0x07E0,
  0x07E0,  0x07E0,  0x00F8,  0x00F8,  0x00F8,  0x00F8,  0x00F8,  0x00F8,
  /* 0x61 'a' */
  0x0FF0,  0x0FF0,  0x7FF8,  0x7FF8,  0x700E,  0x700E,  0x000E,  0x000E,
  0x0FFE,  0x0FFE,  0x7FFE,  0x7FFE,  0x700E,  0x700E,  0xF00E,  0xF00E,
  0xE00E,  0xE00E,  0x703E,  0x703E,  0x7FFE,  0x7FFE,  0x1FCE,  0x1FCE,
  /* 0x62 'b' */
  0xE000,  0xE000,  0xE000,  0xE000,  0xE000,  0xE000,  0xE000,  0xE3E0,
  0xFFFC,  0xFFFC,  0xF81C,  0xF81F,  0xF81F,  0xE007,  0xE007,  0xE007,
  0xE007,  0xE007,  0xF81F,  0xF81F,  0xF81C,  0xFFFC,  0xFFFC,  0xE3E0,
  /* 0x63 'c' */
  0x07F8,  0x07F8,  0x1FFC,  0x1FFC,  0x3C04,  0x3C04,  0x3800,  0x3800,
  0xE000,  0xE000,  0xE000,  0xE000,  0xE000,  0xE000,  0xE000,  0xE000,
  0x3800,  0x3800,  0x3C00,  0x3C00,  0x1FFC,  0x1FFC,  0x07F8,  0x07F8,
  /* 0x64 'd' */
  0x000E,  0x000E,  0x000E,  0x000E,  0x000E,  0x000E,  0x000E,  0x0FCE,
  0x1FFE,  0x1FFE,  0x7C3E,  0x700E,  0x700E,  0xF00E,  0xE00E,  0xE00E,
  0xE00E,  0xF00E,  0x700E,  0x700E,  0x7C3E,  0x1FFE,  0x1FFE,  0x0FCE,
  /* 0x65 'e' */
  0x03F0,  0x03F0,  0x1FFE,  0x1FFE,  0x7C0E,  0x7C0E,  0x7007,  0x7007,
  0xF007,  0xF007,  0xFFFF,  0xFFFF,  0xFFFF,  0xFFFF,  0xE000,  0xE000,
  0x7000,  0x7000,  0x7C06,  0x7C06,  0x1FFE,  0x1FFE,  0x03F8,  0x03F8,
  /* 0x66 'f' */
  0x00FC,  0x03FC,  0x03FC,  0x03C0,  0x0700,  0x0700,  0x0700,  0xFFFC,
  0xFFFC,  0xFFFC,  0x0700,  0x0700,  0x0700,  0x0700,  0x0700,  0x0700,
  0x0700,  0x0700,  0x0700,  0x0700,  0x0700,  0x0700,  0x0700,  0x0700,
  /* 0x67 'g' */
  0x0FCE,  0x1FFE,  0x1FFE,  0x7C3E,  0x700E,  0x700E,  0xF00E,  0xE00E,
  0xE00E,  0xE00E,  0xF00E,  0x700E,  0x700E,  0x7C3E,  0x1FFE,  0x1FFE,
  0x0FCE,  0x000E,  0x000E,  0x000E,  0x1038,  0x1FF8,  0x1FF8,  0x0FF0,
  /* 0x68 'h' */
  0xE000,  0xE000,  0xE000,  0xE000,  0xE000,  0xE000,  0xE000,  0xE3F8,
  0xE7FC,  0xE7FC,  0xF83C,  0xF81C,  0xF81C,  0xE01C,  0xE01C,  0xE01C,
  0xE01C,  0xE01C,  0xE01C,  0xE01C,  0xE01C,  0xE01C,  0xE01C,  0xE01C,
  /* 0x69 'i' */
  0x01C0,  0x01C0,  0x01C0,  0x01C0,  0x0000,  0x0000,  0x0000,  0x1FC0,
  0x1FC0,  0x1FC0,  0x01C0,  0x01C0,  0x01C0,  0x01C0,  0x01C0,  0x01C0,
  0x01C0,  0x01C0,  0x01C0,  0x01C0,  0x01C0,  0x7FFF,  0x7FFF,  0x7FFF,
  /* 0x6A 'j' */
  0x007C,  0x007C,  0x007C,  0x0000,  0x0000,  0x3FFC,  0x3FFC,  0x3FFC,
  0x007C,  0x007C,  0x007C,  0x007C,  0x007C,  0x007C,  0x007C,  0x007C,
  0x007C,  0x007C,  0x007C,  0x007C,  0x007C,  0x007C,  0xFFFC,  0xFFE0,
  /* 0x6B 'k' */
  0x7000,  0x7000,  0x7000,  0x7000,  0x7000,  0x7000,  0x7000,  0x703E,
  0x7078,  0x7078,  0x71F0,  0x73C0,  0x73C0,  0x7F80,  0x7F80,  0x7F80,
  0x71C0,  0x71F0,  0x7070,  0x7070,  0x7038,  0x703E,  0x703E,  0x700F,
  /* 0x6C 'l' */
  0x7F80,  0x7F80,  0x7F80,  0x0380,  0x0380,  0x0380,  0x0380,  0x0380,
  0x0380,  0x0380,  0x0380,  0x0380,  0x0380,  0x0380,  0x0380,  0x0380,
  0x0380,  0x0380,  0x0380,  0x0380,  0x03C0,  0x01FE,  0x01FE,  0x007E,
  /* 0x6D 'm' */
  0xEE78,  0xEE78,  0xFFFE,  0xFFFE,  0xE78E,  0xE78E,  0xE18E,  0xE18E,
  0xE18E,  0xE18E,  0xE18E,  0xE18E,  0xE18E,  0xE18E,  0xE18E,  0xE18E,
  0xE18E,  0xE18E,  0xE18E,  0xE18E,  0xE18E,  0xE18E,  0xE18E,  0xE18E,
  /* 0x6E 'n' */
  0xE3F8,  0xE3F8,  0xE7FC,  0xE7FC,  0xF83C,  0xF83C,  0xF81C,  0xF81C,
  0xE01C,  0xE01C,  0xE01C,  0xE01C,  0xE01C,  0xE01C,  0xE01C,  0xE01C,
  0xE01C,  0xE01C,  0xE01C,  0xE01C,  0xE01C,  0xE01C,  0xE01C,  0xE01C,
  /* 0x6F 'o' */
  0x0FF0,  0x0FF0,  0x1FF8,  0x1FF8,  0x7C3E,  0x7C3E,  0x700E,  0x700E,
  0x700F,  0x700F,  0xF007,  0xF007,  0xF007,  0xF007,  0x700F,  0x700F,
  0x700E,  0x700E,  0x7C3E,  0x7C3E,  0x1FF8,  0x1FF8,  0x0FF0,  0x0FF0,
  /* 0x70 'p' */
  0xE3E0,  0xFFFC,  0xFFFC,  0xF81C,  0xF81F,  0xF81F,  0xE007,  0xE007,
  0xE007,  0xE007,  0xE007,  0xF81F,  0xF81F,  0xF83C,  0xFFFC,  0xFFFC,
  0xE7E0,  0xE000,  0xE000,  0xE000,  0xE000,  0xE000,  0xE000,  0xE000,
  /* 0x71 'q' */
  0x0FCE,  0x1FFE,  0x1FFE,  0x7C3E,  0x700E,  0x700E,  0x700E,  0xF00E,
  0xF00E,  0xF00E,  0x700E,  0x700E,  0x700E,  0x7C3E,  0x1FFE,  0x1FFE,
  0x0FCE,  0x000E,  0x000E,  0x000E,  0x000E,  0x000E,  0x000E,  0x000E,
  /* 0x72 'r' */
  0x38FC,  0x38FC,  0x3BFC,  0x3BFC,  0x3F00,  0x3F00,  0x3C00,  0x3C00,
  0x3800,  0x3800,  0x3800,  0x3800,  0x3800,  0x3800,  0x3800,  0x3800,
  0x3800,  0x3800,  0x3800,  0x3800,  0x3800,  0x3800,  0x3800,  0x3800,
  /* 0x73 's' */
  0x1FE0,  0x1FE0,  0x3FF8,  0x3FF8,  0xF818,  0xF818,  0xE000,  0xE000,
  0x3800,  0x3800,  0x3FC0,  0x3FC0,  0x03F8,  0x03F8,  0x001C,  0x001C,
  0x001C,  0x001C,  0xE03C,  0xE03C,  0xFFF8,  0xFFF8,  0x1FE0,  0x1FE0,
  /* 0x74 't' */
  0x0380,  0x0380,  0x0380,  0x0380,  0x0380,  0xFFFE,  0xFFFE,  0xFFFE,
  0x0380,  0x0380,  0x0380,  0x0380,  0x0380,  0x0380,  0x0380,  0x0380,
  0x0380,  0x0380,  0x0380,  0x0380,  0x0380,  0x03FE,  0x01FE,  0x01FE,
  /* 0x75 'u' */
  0xE01C,  0xE01C,  0xE01C,  0xE01C,  0xE01C,  0xE01C,  0xE01C,  0xE01C,
  0xE01C,  0xE01C,  0xE01C,  0xE01C,  0xE01C,  0xE01C,  0xE01C,  0xE01C,
  0xE01C,  0xE01C,  0xF83C,  0xF83C,  0x3FFC,  0x3FFC,  0x1FDC,  0x1FDC,
  /* 0x76 'v' */
  0xE00E,  0xE00E,  0x700E,  0x700E,  0x7018,  0x7018,  0x7018,  0x7018,
  0x1818,  0x1818,  0x1870,  0x1870,  0x1870,  0x1870,  0x0E60,  0x0E60,
  0x0EE0,  0x0EE0,  0x0FE0,  0x0FE0,  0x0780,  0x0780,  0x0780,  0x0780,
  /* 0x77 'w' */
  0xC006,  0xC006,  0xC006,  0xC006,  0x4006,  0x4006,  0x6004,  0x6004,
  0x619C,  0x619C,  0x639C,  0x639C,  0x239C,  0x239C,  0x3AD8,  0x3AD8,
  0x3EF8,  0x3EF8,  0x3C78,  0x3C78,  0x3C78,  0x3C78,  0x1C78,  0x1C78,
  /* 0x78 'x' */
  0x381E,  0x381E,  0x3C1C,  0x3C1C,  0x0C30,  0x0C30,  0x0660,  0x0660,
  0x03E0,  0x03E0,  0x03C0,  0x03C0,  0x03C0,  0x03C0,  0x07E0,  0x07E0,
  0x0E30,  0x0E30,  0x0C3C,  0x0C3C,  0x381C,  0x381C,  0x700E,  0x700E,
  /* 0x79 'y' */
  0xE00E,  0x700E,  0x700E,  0x7018,  0x7818,  0x7818,  0x1818,  0x1870,
  0x0E70,  0x0E70,  0x0EE0,  0x0EE0,  0x0EE0,  0x07E0,  0x0780,  0x0780,
  0x0180,  0x0180,  0x0700,  0x0700,  0x0F00,  0x7E00,  0x7E00,  0x7800,
  /* 0x7A 'z' */
  0xFFFC,  0xFFFC,  0xFFFC,  0xFFFC,  0x001C,  0x001C,  0x0038,  0x0038,
  0x00E0,  0x00E0,  0x03C0,  0x03C0,  0x0700,  0x0700,  0x1C00,  0x1C00,
  0x1C00,  0x1C00,  0x3800,  0x3800,  0xFFFC,  0xFFFC,  0xFFFC,  0xFFFC,
  /* 0x7B '{' */
  0x007F,  0x01FF,  0x01E0,  0x01E0,  0x01E0,  0x01E0,  0x01E0,  0x01E0,
  0x01E0,  0x01E0,  0x0780,  0xFF80,  0xFF80,  0x0780,  0x01E0,  0x01E0,
  0x01E0,  0x01E0,  0x01E0,  0x01E0,  0x01E0,  0x01E0,  0x01FF,  0x007F,
  /* 0x7C '|' */
  0x07FF,  0x07FF,  0x07FF,  0x07FF,  0x07FF,  0x07FF,  0x07FF,  0x07FF,
  0x07FF,  0x07FF,  0x07FF,  0x07FF,  0x07FF,  0x07FF,  0x07FF,  0x07FF,
  0x07FF,  0x07FF,  0x07FF,  0x07FF,  0x07FF,  0x07FF,  0x07FF,  0x07FF,
  /* 0x7D '}' */
  0xFE00,  0xFF80,  0x0780,  0x0780,  0x0780,  0x01E0,  0x01E0,  0x01E0,
  0x01E0,  0x01E0,  0x01E0,  0x007F,  0x007F,  0x01E0,  0x01E0,  0x01E0,
  0x01E0,  0x01E0,  0x01E0,  0x0780,  0x0780,  0x0780,  0xFF80,  0xFE00,
  /* 0x7E '~' */
  0x3F82,  0x3F82,  0x3F82,  0x3F82,  0x3F82,  0x3F82,  0x3F82,  0x3F82,
  0x7FFE,  0x7FFE,  0x7FFE,  0x7FFE,  0x7FFE,  0x7FFE,  0x7FFE,  0x7FFE,
  0x407C,  0x407C,  0x407C,  0x407C,  0x407C,  0x407C,  0x407C,  0x407C,
};

 FontDef Font16x24 = { 16, 24, Font16x24_ASCII };

#endif // FONT16X24_ASCII_H
bsp/st7789/fonts.h
#ifndef __FONTS_H__
#define __FONTS_H__

#include <stdint.h>

typedef struct {
    const uint8_t width;
    uint8_t height;
    const uint16_t *data;
} FontDef;

extern FontDef Font16x24;



#endif // __FONTS_H__
bsp/st7789/st7789.c
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
#include "st7789.h"
#include <string.h>
#include <stdio.h>

#define ST7789_X_RES   (ST7789_LCD_WIDTH)
#define ST7789_Y_RES   (ST7789_LCD_HEIGHT)

#ifndef ST7789_SPI
#warning "Please define ST7789_SPI (SPI_HandleTypeDef*)"
#endif

/*========================= 本地缓冲与工具函数 =========================*/
static uint8_t ST7789_Buf[ST7789_BUF_SIZE];

/* 阻塞发送(命令/小数据使用) */
static inline void st7789_tx_blocking(const uint8_t *buf, size_t len) {
    HAL_SPI_Transmit(ST7789_SPI, (uint8_t*)buf, len, HAL_MAX_DELAY);
}

/* 命令写入 */
static inline void ST7789_WriteCmd(uint8_t cmd) {
    ST7789_CS_LOW();
    ST7789_DC_LOW();
    st7789_tx_blocking(&cmd, 1);
    ST7789_CS_HIGH();
}

/* 数据写入(小块,阻塞式) */
static inline void ST7789_WriteData(const uint8_t *data, size_t len) {
    if (len == 0) return;
    ST7789_CS_LOW();
    ST7789_DC_HIGH();
    st7789_tx_blocking(data, len);
    ST7789_CS_HIGH();
}

/* 数据写入(大块,DMA + 轮询;需更高效可改用回调或双缓冲) */
static inline void ST7789_WriteDataDMA(const uint8_t *data, size_t len) {
    if (len == 0) return;
    ST7789_CS_LOW();
    ST7789_DC_HIGH();
    HAL_SPI_Transmit_DMA(ST7789_SPI, (uint8_t*)data, len);
    while (HAL_SPI_GetState(ST7789_SPI) == HAL_SPI_STATE_BUSY_TX) { /* 轮询等待 */ }
    ST7789_CS_HIGH();
}

/* 设置窗口:一次性下发 CASET/RASET/RAMWR,仅应用坐标偏移 */
static void ST7789_SetWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1)
{
    uint16_t xs = x0;
    uint16_t xe = x1;
    uint16_t ys = y0;
    uint16_t ye = y1;

    xs += X_SHIFT;
    xe += X_SHIFT;
    ys += Y_SHIFT;
    ye += Y_SHIFT;

    uint8_t caset[4] = { xs >> 8, xs & 0xFF, xe >> 8, xe & 0xFF };
    uint8_t raset[4] = { ys >> 8, ys & 0xFF, ye >> 8, ye & 0xFF };

    ST7789_CS_LOW();

    /* CASET */
    { uint8_t c = 0x2A;
      ST7789_DC_LOW();  st7789_tx_blocking(&c,1);
      ST7789_DC_HIGH(); st7789_tx_blocking(caset,4);
    }

    /* RASET */
    { uint8_t c = 0x2B;
      ST7789_DC_LOW();  st7789_tx_blocking(&c,1);
      ST7789_DC_HIGH(); st7789_tx_blocking(raset,4);
    }

    /* RAMWR */
    { uint8_t c = 0x2C;
      ST7789_DC_LOW();  st7789_tx_blocking(&c,1);
    }

    ST7789_CS_HIGH();
}

/*========================= 公共 API 实现 =========================*/

void ST7789_Init(void)
{
    /* 背光优先点亮(可按需调整) */
    ST7789_BL_HIGH();
    ST7789_CS_HIGH();

    /* 复位:建议 >=10ms 低电平,>=120ms 出睡眠后延时 */
    ST7789_RST_HIGH();
    HAL_Delay(1);
    ST7789_RST_LOW();
    HAL_Delay(10);
    ST7789_RST_HIGH();
    HAL_Delay(120);

    /* Sleep Out */
    ST7789_WriteCmd(0x11);
    HAL_Delay(120);

    /* 像素格式:16bpp RGB565 */
    ST7789_WriteCmd(0x3A);
    { uint8_t fmt = 0x55; ST7789_WriteData(&fmt,1); }

    /* Porch control */
    ST7789_WriteCmd(0xB2); {
        uint8_t d[] = {0x0C,0x0C,0x00,0x33,0x33};
        ST7789_WriteData(d, sizeof(d));
    }

    /* Gate control */
    ST7789_WriteCmd(0xB7); { uint8_t d=0x35; ST7789_WriteData(&d,1); }

    /* VCOM */
    ST7789_WriteCmd(0xBB); { uint8_t d=0x32; ST7789_WriteData(&d,1); } /* 1.35V */

    /* LCM control */
    ST7789_WriteCmd(0xC0); { uint8_t d=0x2C; ST7789_WriteData(&d,1); } /* 可调 */

    /* VDV/VRH */
    ST7789_WriteCmd(0xC2); { uint8_t d=0x01; ST7789_WriteData(&d,1); }
    ST7789_WriteCmd(0xC3); { uint8_t d=0x19; ST7789_WriteData(&d,1); } /* GVDD=4.8V */
    ST7789_WriteCmd(0xC4); { uint8_t d=0x20; ST7789_WriteData(&d,1); } /* VDV, 0x20:0V */

    /* Frame rate */
    ST7789_WriteCmd(0xC6); { uint8_t d=0x0F; ST7789_WriteData(&d,1); } /* 60Hz */

    /* Power control */
    ST7789_WriteCmd(0xD0); { uint8_t d[2]={0xA4,0xA1}; ST7789_WriteData(d,2); }

    /* 正伽玛 */
    ST7789_WriteCmd(0xE0); {
        uint8_t d[] = {0xD0,0x08,0x0E,0x09,0x09,0x05,0x31,0x33,0x48,0x17,0x14,0x15,0x31,0x34};
        ST7789_WriteData(d,sizeof(d));
    }
    /* 负伽玛 */
    ST7789_WriteCmd(0xE1); {
        uint8_t d[] = {0xD0,0x08,0x0E,0x09,0x09,0x15,0x31,0x33,0x48,0x17,0x14,0x15,0x31,0x34};
        ST7789_WriteData(d,sizeof(d));
    }


    /* 反色 */
    ST7789_WriteCmd(0x21); /* Normal display */

    /* MADCTL:方向 + RGB/BGR */
    {
        uint8_t madctl = 0x00;
    #if (ST7789_BGR == 1)
        madctl |= 0x08; /* BGR 模式 */
    #endif
        ST7789_WriteCmd(0x36);
        ST7789_WriteData(&madctl,1);
    }

    /* 显示开 */
    ST7789_WriteCmd(0x29);
}

/* 清屏(整屏填充 color) */
void ST7789_Clear(uint16_t color)
{
    uint32_t total_bytes = (uint32_t)ST7789_X_RES * ST7789_Y_RES * 2;
    /* 预填充缓冲 */
    for (uint32_t i = 0; i < ST7789_BUF_SIZE; i += 2) {
        ST7789_Buf[i]   = color >> 8;
        ST7789_Buf[i+1] = color & 0xFF;
    }

    ST7789_SetWindow(0, 0, ST7789_X_RES - 1, ST7789_Y_RES - 1);

    /* 启动 RAMWR 后,连续写数据 */
    uint8_t ramwr = 0x2C;
    ST7789_WriteCmd(ramwr);

    /* 按块写入 */
    uint32_t remain = total_bytes;
    while (remain) {
        uint32_t chunk = (remain > ST7789_BUF_SIZE) ? ST7789_BUF_SIZE : remain;
        ST7789_WriteDataDMA(ST7789_Buf, chunk);
        remain -= chunk;
    }
}

/* 画一个像素(不建议频繁调用,演示用) */
void ST7789_DrawPixel(uint16_t x, uint16_t y, uint16_t color)
{
    if (x >= ST7789_X_RES || y >= ST7789_Y_RES) return;
    ST7789_SetWindow(x, y, x, y);
    uint8_t px[2] = { color >> 8, color & 0xFF };
    ST7789_WriteCmd(0x2C);
    ST7789_WriteData(px, 2);
}

/* 横线(一次性打包) */
void ST7789_DrawHLine(uint16_t xs, uint16_t xe, uint16_t y, uint16_t color)
{
    if (y >= ST7789_Y_RES) return;
    if (xe < xs) { uint16_t t = xs; xs = xe; xe = t; }
    if (xs >= ST7789_X_RES) return;
    if (xe >= ST7789_X_RES) xe = ST7789_X_RES - 1;

    uint16_t w = xe - xs + 1;
    uint32_t bytes = (uint32_t)w * 2;

    /* 准备一行颜色数据 */
    for (uint32_t i=0; i<bytes; i+=2) {
        ST7789_Buf[i]   = color >> 8;
        ST7789_Buf[i+1] = color & 0xFF;
    }

    ST7789_SetWindow(xs, y, xe, y);
    ST7789_WriteCmd(0x2C);
    ST7789_WriteDataDMA(ST7789_Buf, bytes);
}

/* 竖线(一次性打包后多段写) */
void ST7789_DrawVLine(uint16_t ys, uint16_t ye, uint16_t x, uint16_t color)
{
    if (x >= ST7789_X_RES) return;
    if (ye < ys) { uint16_t t = ys; ys = ye; ye = t; }
    if (ys >= ST7789_Y_RES) return;
    if (ye >= ST7789_Y_RES) ye = ST7789_Y_RES - 1;

    uint16_t h = ye - ys + 1;
    uint32_t bytes = (uint32_t)h * 2;

    /* 若一整段能装入缓冲,则一次写完,否则分块 */
    if (bytes <= ST7789_BUF_SIZE) {
        for (uint32_t i=0; i<bytes; i+=2) {
            ST7789_Buf[i]   = color >> 8;
            ST7789_Buf[i+1] = color & 0xFF;
        }
        ST7789_SetWindow(x, ys, x, ye);
        ST7789_WriteCmd(0x2C);
        ST7789_WriteDataDMA(ST7789_Buf, bytes);
    } else {
        ST7789_SetWindow(x, ys, x, ye);
        ST7789_WriteCmd(0x2C);
        /* 先填满一次缓冲 */
        for (uint32_t i=0; i<ST7789_BUF_SIZE; i+=2) {
            ST7789_Buf[i]   = color >> 8;
            ST7789_Buf[i+1] = color & 0xFF;
        }
        uint32_t remain = bytes;
        while (remain) {
            uint32_t chunk = (remain > ST7789_BUF_SIZE) ? ST7789_BUF_SIZE : remain;
            ST7789_WriteDataDMA(ST7789_Buf, chunk);
            remain -= chunk;
        }
    }
}

/* 填充矩形(尽量用整块 DMA) */
void ST7789_FillRect(uint16_t xs, uint16_t ys, uint16_t xe, uint16_t ye, uint16_t color)
{
    if (xe < xs) { uint16_t t=xs; xs=xe; xe=t; }
    if (ye < ys) { uint16_t t=ys; ys=ye; ye=t; }
    if (xs >= ST7789_X_RES || ys >= ST7789_Y_RES) return;
    if (xe >= ST7789_X_RES)  xe = ST7789_X_RES - 1;
    if (ye >= ST7789_Y_RES) ye = ST7789_Y_RES - 1;

    uint16_t w = xe - xs + 1;
    uint16_t h = ye - ys + 1;
    uint32_t total = (uint32_t)w * h * 2;

    /* 预填充缓冲 */
    for (uint32_t i=0; i<ST7789_BUF_SIZE; i+=2) {
        ST7789_Buf[i]   = color >> 8;
        ST7789_Buf[i+1] = color & 0xFF;
    }

    ST7789_SetWindow(xs, ys, xe, ye);
    ST7789_WriteCmd(0x2C);

    /* 按块写入 */
    uint32_t remain = total;
    while (remain) {
        uint32_t chunk = (remain > ST7789_BUF_SIZE) ? ST7789_BUF_SIZE : remain;
        ST7789_WriteDataDMA(ST7789_Buf, chunk);
        remain -= chunk;
    }
}

/**
 * 画一行 16BPP 位图(RGB565,小端存储:p[0]=low, p[1]=high)
 * xsize 范围 [1, ST7789_X_RES]
 */
void ST7789_DrawBitLine16BPP(uint16_t xs, uint16_t y, const uint8_t *p, uint16_t xsize)
{
    if (y >= ST7789_Y_RES || xs >= ST7789_X_RES) return;
    if (xsize == 0) return;
    if (xs + xsize > ST7789_X_RES) xsize = ST7789_X_RES - xs;

    uint32_t bytes = (uint32_t)xsize * 2;

    /* 小端 -> 转换成高字节在前(面板需要高字节先出) */
    for (uint32_t i = 0; i < bytes; i += 2) {
        uint8_t lo = p[i];
        uint8_t hi = p[i+1];
        ST7789_Buf[i]   = hi;
        ST7789_Buf[i+1] = lo;
    }

    ST7789_SetWindow(xs, y, xs + xsize - 1, y);
    ST7789_WriteCmd(0x2C);
    ST7789_WriteDataDMA(ST7789_Buf, bytes);
}

/* 画任意矩形位图 */
void ST7789_DrawBitmap(uint16_t xs, uint16_t ys, uint16_t xsize, uint16_t ysize, const uint8_t *p)
{
    if (xs >= ST7789_X_RES || ys >= ST7789_Y_RES) return;
    if (xsize == 0 || ysize == 0) return;

    uint16_t xmax = (xs + xsize > ST7789_X_RES)  ? (ST7789_X_RES  - xs) : xsize;
    uint16_t ymax = (ys + ysize > ST7789_Y_RES) ? (ST7789_Y_RES - ys) : ysize;

    for (uint16_t i=0; i<ymax; i++) {
        ST7789_DrawBitLine16BPP(xs, ys + i, p + (uint32_t)i * xsize * 2, xmax);
    }
}

void ST7789_ShowChar(uint16_t x, uint16_t y, uint8_t ch, FontDef font, uint16_t color, uint16_t bgcolor)
{
    if (x >= ST7789_X_RES || y >= ST7789_Y_RES) return;
    if (font.width == 0 || font.height == 0) return;

    /* 使用局部变量承接,避免修改 font 本体 */
    uint16_t w = font.width;
    uint16_t h = font.height;

    /* 每行最多 16 位位图,超出则按 16 处理 */
    if (w > 16) w = 16;

    /* 越界裁剪 */
    if (x + w - 1 >= ST7789_X_RES || y + h - 1 >= ST7789_Y_RES) return;

    ST7789_SetWindow(x, y, x + w - 1, y + h - 1);
    ST7789_WriteCmd(0x2C);

    uint32_t wrote = 0;
    for (uint16_t row = 0; row < h; row++) {
        /* 注意:如果fonts.h 定义不是每行 16bit,需要按格式改这里 */
        uint16_t bits = font.data[((uint32_t)(ch - 32) * h) + row];
        for (uint16_t col = 0; col < w; col++) {
            uint16_t c = (bits & (1U << (w - 1 - col))) ? color : bgcolor;

            /* 将像素写入发送缓冲(双字节:高位在前) */
            uint32_t idx = wrote % ST7789_BUF_SIZE;
            ST7789_Buf[idx + 0] = (uint8_t)(c >> 8);
            ST7789_Buf[idx + 1] = (uint8_t)(c & 0xFF);
            wrote += 2;

            if ((wrote % ST7789_BUF_SIZE) == 0) {
                ST7789_WriteDataDMA(ST7789_Buf, ST7789_BUF_SIZE);
            }
        }
    }

    uint32_t remain = wrote % ST7789_BUF_SIZE;
    if (remain) {
        ST7789_WriteDataDMA(ST7789_Buf, remain);
    }
}

void ST7789_ShowString(uint16_t x, uint16_t y, const char *str, FontDef font, uint16_t color, uint16_t bgcolor)
{
    if (!str) return;

    uint16_t fw = font.width;
    uint16_t fh = font.height;
    if (fw == 0 || fh == 0) return;
    if (fw > 16) fw = 16;

    uint16_t cx = x, cy = y;
    while (*str) {
        /* 自动换行 */
        if (cx + fw > ST7789_X_RES) {
            cx = 0;
            cy += fh;
            if (cy + fh > ST7789_Y_RES) break;
            if (*str == ' ') { str++; continue; }
        }

        ST7789_ShowChar(cx, cy, (uint8_t)*str, font, color, bgcolor);
        cx += fw;
        str++;
    }
}


/* 帧率测试整屏填充不同色 */
void ST7789_TestFrameRate(void)
{
    static const uint16_t test_colors[] = { 0xF800, /*RED*/ 0x07E0, /*GREEN*/ 0x001F, /*BLUE*/
                                            0xFFFF, /*WHITE*/ 0x0000, /*BLACK*/ 0x07FF, /*CYAN*/
                                            0xF81F, /*MAGENTA*/ 0xFFE0 /*YELLOW*/ };
    const uint32_t frame_count = 60U;
    uint32_t tick_start = 0, elapsed = 0;

    ST7789_Clear(0x0000);
    tick_start = HAL_GetTick();
    for (uint32_t f=0; f<frame_count; f++) {
        uint16_t color = test_colors[f % (sizeof(test_colors)/sizeof(test_colors[0]))];
        ST7789_FillRect(0, 0, ST7789_X_RES - 1, ST7789_Y_RES - 1, color);
    }
    elapsed = HAL_GetTick() - tick_start;

    double fps = (elapsed > 0) ? ((double)frame_count * 1000.0) / (double)elapsed : 0.0;
    printf("ST7789 frame test: %lu frames in %lums (%.2f FPS)\r\n",
           (unsigned long)frame_count, (unsigned long)elapsed, fps);

    char fps_text[32];
    int written = snprintf(fps_text, sizeof(fps_text), "%.2f FPS", fps);
    if (written < 0) {
        return;
    }
    if (written >= (int)sizeof(fps_text)) {
        fps_text[sizeof(fps_text) - 1] = '\0';
        written = (int)(sizeof(fps_text) - 1);
    }

    uint16_t text_len = (uint16_t)strlen(fps_text);
    uint16_t text_width = (uint16_t)((uint16_t)Font16x24.width * text_len);
    uint16_t x = (text_width < ST7789_X_RES) ? (uint16_t)((ST7789_X_RES - text_width) / 2U) : 0;
    uint16_t y = (Font16x24.height < ST7789_Y_RES) ? (uint16_t)((ST7789_Y_RES - Font16x24.height) / 2U) : 0;

    ST7789_Clear(BLACK);
    ST7789_ShowString(x, y, fps_text, Font16x24, WHITE, BLACK);
}
bsp/st7789/st7789.h
#ifndef ST7789_H
#define ST7789_H

#ifdef __cplusplus
extern "C" {
#endif

#include "main.h"
#include "gpio.h"
#include "spi.h"
#include "fonts.h" 

/*================= 用户配置(与实际屏幕/连线匹配) =================*/

/* 分辨率 */
#ifndef ST7789_WIDTH
#define ST7789_WIDTH    240
#endif
#ifndef ST7789_HEIGHT
#define ST7789_HEIGHT   240
#endif

#ifndef ST7789_HIGHT
#define ST7789_HIGHT    ST7789_HEIGHT
#endif

/* 旋转角仅保留 0 度显示方向 */
#define ST7789_LCD_WIDTH   ST7789_WIDTH
#define ST7789_LCD_HEIGHT  ST7789_HEIGHT

/* 若 240x240 模组实际 IC 窗口为 240x320,需要 Y 方向偏移 80(常见)。
   如发现图像上下移/被裁剪,尝试把 Y_SHIFT 改为 80。 */
#ifndef X_SHIFT
#define X_SHIFT 0
#endif
#ifndef Y_SHIFT
#define Y_SHIFT 0 /* 常见:0 或 80 */
#endif


/* 颜色顺序:有的屏需要 BGR。0=RGB,1=BGR */
#ifndef ST7789_BGR
#define ST7789_BGR 0
#endif

/* SPI 句柄 */
#ifndef ST7789_SPI
#define ST7789_SPI (&hspi1)
#endif

/* 发送像素缓冲大小(字节,偶数)。越大整屏填充越快(受 RAM 限制)。 */
#ifndef ST7789_BUF_SIZE
#define ST7789_BUF_SIZE (240 * 2)
#endif

/* 控制引脚 */
#define ST7789_RST_LOW()   HAL_GPIO_WritePin(LCD_RST_GPIO_Port, LCD_RST_Pin, GPIO_PIN_RESET)
#define ST7789_RST_HIGH()  HAL_GPIO_WritePin(LCD_RST_GPIO_Port, LCD_RST_Pin, GPIO_PIN_SET)

#define ST7789_CS_LOW()    HAL_GPIO_WritePin(LCD_CS_GPIO_Port,  LCD_CS_Pin,  GPIO_PIN_RESET)
#define ST7789_CS_HIGH()   HAL_GPIO_WritePin(LCD_CS_GPIO_Port,  LCD_CS_Pin,  GPIO_PIN_SET)

#define ST7789_DC_LOW()    HAL_GPIO_WritePin(LCD_DC_GPIO_Port,  LCD_DC_Pin,  GPIO_PIN_RESET)
#define ST7789_DC_HIGH()   HAL_GPIO_WritePin(LCD_DC_GPIO_Port,  LCD_DC_Pin,  GPIO_PIN_SET)

#define ST7789_BL_LOW()    HAL_GPIO_WritePin(LCD_BL_GPIO_Port,  LCD_BL_Pin,  GPIO_PIN_RESET)
#define ST7789_BL_HIGH()   HAL_GPIO_WritePin(LCD_BL_GPIO_Port,  LCD_BL_Pin,  GPIO_PIN_SET)

/* 颜色常量 */
#define WHITE     0xFFFF
#define BLACK     0x0000
#define BLUE      0x001F
#define BRED      0xF81F
#define GRED      0xFFE0
#define GBLUE     0x07FF
#define RED       0xF800
#define MAGENTA   0xF81F
#define GREEN     0x07E0
#define CYAN      0x7FFF
#define YELLOW    0xFFE0
#define BROWN     0xBC40
#define BRRED     0xFC07
#define GRAY      0x8430


/*================= 对外 API =================*/

void ST7789_Init(void);
void ST7789_Clear(uint16_t color);

void ST7789_DrawPixel(uint16_t x, uint16_t y, uint16_t color);
void ST7789_DrawHLine(uint16_t xs, uint16_t xe, uint16_t y, uint16_t color);
void ST7789_DrawVLine(uint16_t ys, uint16_t ye, uint16_t x, uint16_t color);
void ST7789_FillRect(uint16_t xs, uint16_t ys, uint16_t xe, uint16_t ye, uint16_t color);

/* 位图(RGB565 小端:低字节在前) */
void ST7789_DrawBitLine16BPP(uint16_t xs, uint16_t y, const uint8_t *p, uint16_t xsize);
void ST7789_DrawBitmap(uint16_t xs, uint16_t ys, uint16_t xsize, uint16_t ysize, const uint8_t *p);

/* 文本(FontDef 要与 fonts.h 匹配;若每行不是 16bit 位图,需要改位取法) */
void ST7789_ShowChar(uint16_t x, uint16_t y, uint8_t ch, FontDef font, uint16_t color, uint16_t bgcolor);
void ST7789_ShowString(uint16_t x, uint16_t y, const char *str, FontDef font, uint16_t color, uint16_t bgcolor);

/* 简单帧率测试 */
void ST7789_TestFrameRate(void);

#ifdef __cplusplus
}
#endif
#endif /* ST7789_H */