Initial commit.
This commit is contained in:
commit
e680528d73
6
CMakeLists.txt
Normal file
6
CMakeLists.txt
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
# The following lines of boilerplate have to be in your project's
|
||||||
|
# CMakeLists in this exact order for cmake to work correctly
|
||||||
|
cmake_minimum_required(VERSION 3.5)
|
||||||
|
|
||||||
|
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||||
|
project(hello_world)
|
8
Makefile
Normal file
8
Makefile
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
#
|
||||||
|
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||||
|
# project subdirectory.
|
||||||
|
#
|
||||||
|
|
||||||
|
PROJECT_NAME := hello_world
|
||||||
|
|
||||||
|
include $(IDF_PATH)/make/project.mk
|
52
README.md
Normal file
52
README.md
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
# Hello World Example
|
||||||
|
|
||||||
|
Starts a FreeRTOS task to print "Hello World".
|
||||||
|
|
||||||
|
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||||
|
|
||||||
|
## How to use example
|
||||||
|
|
||||||
|
Follow detailed instructions provided specifically for this example.
|
||||||
|
|
||||||
|
Select the instructions depending on Espressif chip installed on your development board:
|
||||||
|
|
||||||
|
- [ESP32 Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/stable/get-started/index.html)
|
||||||
|
- [ESP32-S2 Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/get-started/index.html)
|
||||||
|
|
||||||
|
|
||||||
|
## Example folder contents
|
||||||
|
|
||||||
|
The project **hello_world** contains one source file in C language [hello_world_main.c](main/hello_world_main.c). The file is located in folder [main](main).
|
||||||
|
|
||||||
|
ESP-IDF projects are built using CMake. The project build configuration is contained in `CMakeLists.txt` files that provide set of directives and instructions describing the project's source files and targets (executable, library, or both).
|
||||||
|
|
||||||
|
Below is short explanation of remaining files in the project folder.
|
||||||
|
|
||||||
|
```
|
||||||
|
├── CMakeLists.txt
|
||||||
|
├── example_test.py Python script used for automated example testing
|
||||||
|
├── main
|
||||||
|
│ ├── CMakeLists.txt
|
||||||
|
│ ├── component.mk Component make file
|
||||||
|
│ └── hello_world_main.c
|
||||||
|
├── Makefile Makefile used by legacy GNU Make
|
||||||
|
└── README.md This is the file you are currently reading
|
||||||
|
```
|
||||||
|
|
||||||
|
For more information on structure and contents of ESP-IDF projects, please refer to Section [Build System](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/build-system.html) of the ESP-IDF Programming Guide.
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
* Program upload failure
|
||||||
|
|
||||||
|
* Hardware connection is not correct: run `idf.py -p PORT monitor`, and reboot your board to see if there are any output logs.
|
||||||
|
* The baud rate for downloading is too high: lower your baud rate in the `menuconfig` menu, and try again.
|
||||||
|
|
||||||
|
## Technical support and feedback
|
||||||
|
|
||||||
|
Please use the following feedback channels:
|
||||||
|
|
||||||
|
* For technical queries, go to the [esp32.com](https://esp32.com/) forum
|
||||||
|
* For a feature request or bug report, create a [GitHub issue](https://github.com/espressif/esp-idf/issues)
|
||||||
|
|
||||||
|
We will get back to you as soon as possible.
|
20
example_test.py
Normal file
20
example_test.py
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
from __future__ import division, print_function, unicode_literals
|
||||||
|
|
||||||
|
import ttfw_idf
|
||||||
|
|
||||||
|
|
||||||
|
@ttfw_idf.idf_example_test(env_tag='Example_GENERIC', target=['esp32', 'esp32s2', 'esp32c3'], ci_target=['esp32'])
|
||||||
|
def test_examples_hello_world(env, extra_data):
|
||||||
|
app_name = 'hello_world'
|
||||||
|
dut = env.get_dut(app_name, 'examples/get-started/hello_world')
|
||||||
|
dut.start_app()
|
||||||
|
res = dut.expect(ttfw_idf.MINIMUM_FREE_HEAP_SIZE_RE)
|
||||||
|
if not res:
|
||||||
|
raise ValueError('Maximum heap size info not found')
|
||||||
|
ttfw_idf.print_heap_size(app_name, dut.app.config_name, dut.TARGET, res[0])
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
test_examples_hello_world()
|
9
main/CMakeLists.txt
Normal file
9
main/CMakeLists.txt
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
idf_component_register(
|
||||||
|
SRCS
|
||||||
|
"app_main.c"
|
||||||
|
"app_lcd_impl.c"
|
||||||
|
"lib/st7789_lcd.c"
|
||||||
|
|
||||||
|
INCLUDE_DIRS
|
||||||
|
"lib"
|
||||||
|
)
|
172
main/app_lcd_impl.c
Normal file
172
main/app_lcd_impl.c
Normal file
|
@ -0,0 +1,172 @@
|
||||||
|
/* IDF */
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "esp_system.h"
|
||||||
|
|
||||||
|
/* FreeRTOS */
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
|
||||||
|
/* IDF drivers */
|
||||||
|
#include "driver/gpio.h"
|
||||||
|
#include "driver/spi_master.h"
|
||||||
|
|
||||||
|
/* Private */
|
||||||
|
#include "st7789_lcd.h"
|
||||||
|
|
||||||
|
#define LCD_GPIO_RST 4
|
||||||
|
#define LCD_GPIO_DC 2
|
||||||
|
#define LCD_GPIO_MOSI 23
|
||||||
|
#define LCD_GPIO_SCK 18
|
||||||
|
#define LCD_GPIO_BL 5
|
||||||
|
|
||||||
|
#define LCD_SPI_HOST SPI3_HOST
|
||||||
|
#define LCD_SPI_MAX_SIZE 4096
|
||||||
|
#define LCD_SPI_MHZ 10
|
||||||
|
|
||||||
|
#define APP_LOG_TAG "LCD_IMPL"
|
||||||
|
|
||||||
|
static void lcd_impl_spi_pre_cb(spi_transaction_t *txn) {
|
||||||
|
int dc = (int)txn->user;
|
||||||
|
|
||||||
|
gpio_set_level(LCD_GPIO_DC, dc);
|
||||||
|
}
|
||||||
|
|
||||||
|
spi_device_handle_t lcd_impl_init(void) {
|
||||||
|
gpio_set_direction(LCD_GPIO_BL, GPIO_MODE_OUTPUT);
|
||||||
|
gpio_set_direction(LCD_GPIO_DC, GPIO_MODE_OUTPUT);
|
||||||
|
gpio_set_direction(LCD_GPIO_RST, GPIO_MODE_OUTPUT);
|
||||||
|
|
||||||
|
gpio_set_level(LCD_GPIO_BL, 0);
|
||||||
|
gpio_set_level(LCD_GPIO_RST, 1);
|
||||||
|
gpio_set_level(LCD_GPIO_DC, 0);
|
||||||
|
|
||||||
|
gpio_set_pull_mode(LCD_GPIO_MOSI, GPIO_PULLUP_ONLY);
|
||||||
|
gpio_set_pull_mode(LCD_GPIO_SCK, GPIO_PULLUP_ONLY);
|
||||||
|
|
||||||
|
esp_err_t err;
|
||||||
|
spi_device_handle_t spi_handle;
|
||||||
|
spi_bus_config_t bus_cfg = {
|
||||||
|
.mosi_io_num = LCD_GPIO_MOSI,
|
||||||
|
.sclk_io_num = LCD_GPIO_SCK,
|
||||||
|
.miso_io_num = -1,
|
||||||
|
.quadhd_io_num = -1,
|
||||||
|
.quadwp_io_num = -1,
|
||||||
|
.max_transfer_sz = LCD_SPI_MAX_SIZE,
|
||||||
|
};
|
||||||
|
|
||||||
|
spi_device_interface_config_t if_cfg = {
|
||||||
|
.clock_speed_hz = LCD_SPI_MHZ * 1000 * 1000,
|
||||||
|
.mode = 3,
|
||||||
|
.spics_io_num = -1,
|
||||||
|
.queue_size = 1,
|
||||||
|
.pre_cb = lcd_impl_spi_pre_cb,
|
||||||
|
};
|
||||||
|
|
||||||
|
err = spi_bus_initialize(LCD_SPI_HOST, &bus_cfg, SPI_DMA_CH_AUTO);
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
ESP_LOGE(APP_LOG_TAG, "SPI bus initialization failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = spi_bus_add_device(LCD_SPI_HOST, &if_cfg, &spi_handle);
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
ESP_LOGE(APP_LOG_TAG, "SPI add device failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return spi_handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
st7789_lcd_ret_t lcd_impl_reset(void *pdev) {
|
||||||
|
/* Hardware reset is necessary if CS not used !! */
|
||||||
|
|
||||||
|
ESP_LOGI(APP_LOG_TAG, "LCD reset!");
|
||||||
|
|
||||||
|
gpio_set_level(LCD_GPIO_RST, 0U);
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(10));
|
||||||
|
gpio_set_level(LCD_GPIO_RST, 1U);
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(100));
|
||||||
|
|
||||||
|
return ST7789_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
st7789_lcd_ret_t lcd_impl_delay(void *pdev, uint32_t msec) {
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(msec));
|
||||||
|
|
||||||
|
return ST7789_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
st7789_lcd_ret_t lcd_impl_write_command(void *pdev, uint8_t *command, uint32_t len) {
|
||||||
|
ESP_LOGD(APP_LOG_TAG, "Write CMD: %d bytes, 0x%02x...", len, command[0]);
|
||||||
|
|
||||||
|
esp_err_t ret;
|
||||||
|
|
||||||
|
spi_device_handle_t handle = pdev;
|
||||||
|
|
||||||
|
spi_transaction_t txn = {
|
||||||
|
.length = 0x08,
|
||||||
|
.tx_buffer = command,
|
||||||
|
.user = (void *)0U,
|
||||||
|
};
|
||||||
|
|
||||||
|
ret = spi_device_polling_transmit(handle, &txn);
|
||||||
|
if (ret != ESP_OK) {
|
||||||
|
ESP_LOGE(APP_LOG_TAG, "CMD transmit failed phase 1");
|
||||||
|
return ST7789_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This command has parameters */
|
||||||
|
if (len > 1) {
|
||||||
|
txn.length = (len - 1) * 8;
|
||||||
|
txn.tx_buffer = &command[1];
|
||||||
|
txn.user = (void *)1U;
|
||||||
|
|
||||||
|
gpio_set_level(LCD_GPIO_DC, 1U);
|
||||||
|
ret = spi_device_polling_transmit(handle, &txn);
|
||||||
|
if (ret != ESP_OK) {
|
||||||
|
ESP_LOGE(APP_LOG_TAG, "CMD transmit failed phase 2");
|
||||||
|
return ST7789_FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ST7789_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
st7789_lcd_ret_t lcd_impl_write_data(void *pdev, uint8_t *data, uint32_t len) {
|
||||||
|
ESP_LOGD(APP_LOG_TAG, "Write DATA: %d bytes", len);
|
||||||
|
|
||||||
|
esp_err_t ret;
|
||||||
|
spi_device_handle_t handle = pdev;
|
||||||
|
|
||||||
|
spi_transaction_t txn;
|
||||||
|
uint32_t d_ptr = 0U;
|
||||||
|
|
||||||
|
txn.user = (void *)1U;
|
||||||
|
|
||||||
|
while (len > LCD_SPI_MAX_SIZE) {
|
||||||
|
txn.tx_buffer = &data[d_ptr];
|
||||||
|
txn.length = LCD_SPI_MAX_SIZE * 8;
|
||||||
|
|
||||||
|
ret = spi_device_polling_transmit(handle, &txn);
|
||||||
|
if (ret != ESP_OK) {
|
||||||
|
ESP_LOGE(APP_LOG_TAG, "DATA transmit failed phase 1");
|
||||||
|
return ST7789_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
len -= LCD_SPI_MAX_SIZE;
|
||||||
|
d_ptr += LCD_SPI_MAX_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len > 0) {
|
||||||
|
txn.tx_buffer = &data[d_ptr];
|
||||||
|
txn.length = len * 8;
|
||||||
|
|
||||||
|
ret = spi_device_polling_transmit(handle, &txn);
|
||||||
|
if (ret != ESP_OK) {
|
||||||
|
ESP_LOGE(APP_LOG_TAG, "DATA transmit failed phase 2");
|
||||||
|
return ST7789_FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ST7789_SUCCESS;
|
||||||
|
}
|
70
main/app_main.c
Normal file
70
main/app_main.c
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
/* Hello World Example
|
||||||
|
|
||||||
|
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, this
|
||||||
|
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
*/
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
/* IDF headers */
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "esp_spi_flash.h"
|
||||||
|
#include "esp_system.h"
|
||||||
|
|
||||||
|
/* Drivers */
|
||||||
|
#include "driver/spi_master.h"
|
||||||
|
|
||||||
|
/* FreeRTOS */
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
|
||||||
|
/* Config */
|
||||||
|
#include "sdkconfig.h"
|
||||||
|
|
||||||
|
/* LCD */
|
||||||
|
#include "st7789_lcd.h"
|
||||||
|
|
||||||
|
#define APP_LOG_TAG "MAIN"
|
||||||
|
|
||||||
|
spi_device_handle_t lcd_impl_init(void);
|
||||||
|
st7789_lcd_ret_t lcd_impl_reset(void *pdev);
|
||||||
|
st7789_lcd_ret_t lcd_impl_delay(void *pdev, uint32_t msec);
|
||||||
|
st7789_lcd_ret_t lcd_impl_write_command(void *pdev, uint8_t *command, uint32_t len);
|
||||||
|
st7789_lcd_ret_t lcd_impl_write_data(void *pdev, uint8_t *data, uint32_t len);
|
||||||
|
|
||||||
|
void app_main(void) {
|
||||||
|
ESP_LOGI(APP_LOG_TAG, "MAIN");
|
||||||
|
|
||||||
|
st7789_lcd_t lcd = {
|
||||||
|
.cb =
|
||||||
|
{
|
||||||
|
.write_command_cb = lcd_impl_write_command,
|
||||||
|
.write_data_cb = lcd_impl_write_data,
|
||||||
|
.reset_cb = lcd_impl_reset,
|
||||||
|
.delay_cb = lcd_impl_delay,
|
||||||
|
},
|
||||||
|
.config =
|
||||||
|
{
|
||||||
|
.dir = ST7789_LCD_DIR_0,
|
||||||
|
.inverted = false,
|
||||||
|
.bgr_mode = false,
|
||||||
|
.pix_fmt = ST7789_LCD_PIXFMT_RGB565,
|
||||||
|
},
|
||||||
|
.user_data = lcd_impl_init(),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (lcd.user_data == NULL) {
|
||||||
|
ESP_LOGE(APP_LOG_TAG, "IMPL initialization failed");
|
||||||
|
vTaskSuspend(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (st7789_lcd_init(&lcd) != ST7789_SUCCESS) {
|
||||||
|
ESP_LOGE(APP_LOG_TAG, "LCD init failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
vTaskSuspend(NULL);
|
||||||
|
}
|
||||||
|
}
|
4
main/component.mk
Normal file
4
main/component.mk
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
#
|
||||||
|
# "main" pseudo-component makefile.
|
||||||
|
#
|
||||||
|
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
195
main/lib/st7789_lcd.c
Normal file
195
main/lib/st7789_lcd.c
Normal file
|
@ -0,0 +1,195 @@
|
||||||
|
#include "st7789_lcd.h"
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#define LCD_ASSERT(x) \
|
||||||
|
if (!(x)) \
|
||||||
|
for (;;) { /* ABORT. */ \
|
||||||
|
}
|
||||||
|
#define LCD_ERROR_CHECK(x) \
|
||||||
|
if (x != ST7789_SUCCESS) return ST7789_FAIL
|
||||||
|
|
||||||
|
static uint8_t st7789_lcd_init_sequence[] = {
|
||||||
|
0x05, 0xB2, 0x0C, 0x0C, 0x00, 0x33, 0x33, // Porch Setting
|
||||||
|
0x01, 0xB7, 0x35, // Gate Control
|
||||||
|
0x01, 0xBB, 0x19, // VCOM Setting // Factory 0x19 -> 0.725V
|
||||||
|
0x01, 0xC0, 0x2C, // LCM Control
|
||||||
|
0x01, 0xC2, 0x01, // VDV and VRH Command Enable
|
||||||
|
0x01, 0xC3, 0x12, // VRH Set // Factory 12H
|
||||||
|
0x01, 0xC4, 0x20, // VDV Set
|
||||||
|
0x01, 0xC6, 0x0F, // Frame Rate Control in Normal Mode
|
||||||
|
0x02, 0xD0, 0xA4, 0xA1, // Power Control 1
|
||||||
|
0x0E, 0xE0, 0xD0, 0x04, 0x0D, 0x11, 0x13, 0x2B, 0x3F, 0x54, 0x4C, 0x18, 0x0D, 0x0B, 0x1F,
|
||||||
|
0x23, // Positive Voltage Gamma Control
|
||||||
|
0x0E, 0xE1, 0xD0, 0x04, 0x0C, 0x11, 0x13, 0x2C, 0x3F, 0x44, 0x51, 0x2F, 0x1F, 0x1F, 0x20,
|
||||||
|
0x23, // Negative Voltage Gamma Control
|
||||||
|
0x00, 0x21, // Inversion On
|
||||||
|
};
|
||||||
|
|
||||||
|
static st7789_lcd_ret_t st7789_lcd_execute_sequence(st7789_lcd_cb_t *cb, void *user_data, uint8_t *seq,
|
||||||
|
uint32_t seq_len) {
|
||||||
|
LCD_ASSERT(cb->write_command_cb != NULL);
|
||||||
|
|
||||||
|
uint32_t i = 0;
|
||||||
|
while (i < seq_len) {
|
||||||
|
LCD_ERROR_CHECK(cb->write_command_cb(user_data, &seq[i + 1], seq[i] + 1));
|
||||||
|
i += seq[i] + 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ST7789_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static st7789_lcd_ret_t st7789_lcd_reset(st7789_lcd_t *lcd) {
|
||||||
|
return lcd->cb.reset_cb(lcd->user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static st7789_lcd_ret_t st7789_lcd_sleep(st7789_lcd_t *lcd, bool sleep) {
|
||||||
|
uint8_t tx_buf[1] = {0x11U};
|
||||||
|
if (sleep) {
|
||||||
|
tx_buf[0] = 0x10U;
|
||||||
|
}
|
||||||
|
|
||||||
|
return lcd->cb.write_command_cb(lcd->user_data, tx_buf, 0x01);
|
||||||
|
}
|
||||||
|
|
||||||
|
static st7789_lcd_ret_t st7789_lcd_config(st7789_lcd_t *lcd) {
|
||||||
|
/* PIXFMT */
|
||||||
|
uint8_t tx_buf[2] = {0x3AU, lcd->config.pix_fmt};
|
||||||
|
|
||||||
|
LCD_ERROR_CHECK(lcd->cb.write_command_cb(lcd->user_data, tx_buf, 0x02));
|
||||||
|
|
||||||
|
/* INVERSION */
|
||||||
|
if (lcd->config.inverted) {
|
||||||
|
tx_buf[0] = 0x20U;
|
||||||
|
} else {
|
||||||
|
tx_buf[0] = 0x21U;
|
||||||
|
}
|
||||||
|
|
||||||
|
LCD_ERROR_CHECK(lcd->cb.write_command_cb(lcd->user_data, tx_buf, 0x01));
|
||||||
|
|
||||||
|
tx_buf[0] = 0x36;
|
||||||
|
switch (lcd->config.dir) {
|
||||||
|
case ST7789_LCD_DIR_270:
|
||||||
|
tx_buf[1] = 0xA8;
|
||||||
|
break;
|
||||||
|
case ST7789_LCD_DIR_180:
|
||||||
|
tx_buf[1] = 0xC8;
|
||||||
|
break;
|
||||||
|
case ST7789_LCD_DIR_90:
|
||||||
|
tx_buf[1] = 0x68;
|
||||||
|
break;
|
||||||
|
case ST7789_LCD_DIR_0:
|
||||||
|
default:
|
||||||
|
tx_buf[1] = 0x08;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lcd->config.bgr_mode) {
|
||||||
|
tx_buf[1] &= ~(1 << 3U); /* RGB <-> BGR */
|
||||||
|
}
|
||||||
|
|
||||||
|
LCD_ERROR_CHECK(lcd->cb.write_command_cb(lcd->user_data, tx_buf, 0x02));
|
||||||
|
|
||||||
|
return ST7789_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static st7789_lcd_ret_t st7789_lcd_window(st7789_lcd_t *lcd, st7789_lcd_coord_t *coord) {
|
||||||
|
uint16_t real_x_start, real_x_end, real_y_start, real_y_end;
|
||||||
|
|
||||||
|
uint16_t x_offset, y_offset;
|
||||||
|
switch (lcd->config.dir) {
|
||||||
|
case ST7789_LCD_DIR_0:
|
||||||
|
case ST7789_LCD_DIR_90:
|
||||||
|
x_offset = 0;
|
||||||
|
y_offset = 0;
|
||||||
|
break;
|
||||||
|
case ST7789_LCD_DIR_180:
|
||||||
|
x_offset = 0;
|
||||||
|
y_offset = 80;
|
||||||
|
break;
|
||||||
|
case ST7789_LCD_DIR_270:
|
||||||
|
x_offset = 80;
|
||||||
|
y_offset = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
x_offset = 0;
|
||||||
|
y_offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
real_x_start = coord->x_start + x_offset;
|
||||||
|
real_x_end = coord->x_end + x_offset;
|
||||||
|
real_y_start = coord->y_start + y_offset;
|
||||||
|
real_y_end = coord->y_end + y_offset;
|
||||||
|
|
||||||
|
uint8_t tx_buf[5] = {
|
||||||
|
0x2A,
|
||||||
|
((uint8_t)(real_x_start >> 0x08U) & 0xFFU),
|
||||||
|
(real_x_start & 0xFFU),
|
||||||
|
((uint8_t)(real_x_end >> 0x08U) & 0xFFU),
|
||||||
|
(real_x_end & 0xFFU),
|
||||||
|
};
|
||||||
|
|
||||||
|
LCD_ERROR_CHECK(lcd->cb.write_command_cb(lcd->user_data, tx_buf, 0x05));
|
||||||
|
|
||||||
|
tx_buf[0] = 0x2BU;
|
||||||
|
tx_buf[1] = ((uint8_t)(real_y_start >> 0x08U) & 0xFFU);
|
||||||
|
tx_buf[2] = (real_y_start & 0xFFU);
|
||||||
|
tx_buf[3] = ((uint8_t)(real_y_end >> 0x08U) & 0xFFU);
|
||||||
|
tx_buf[4] = (real_y_end & 0xFFU);
|
||||||
|
|
||||||
|
LCD_ERROR_CHECK(lcd->cb.write_command_cb(lcd->user_data, tx_buf, 0x05));
|
||||||
|
|
||||||
|
return ST7789_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
st7789_lcd_ret_t st7789_lcd_init(st7789_lcd_t *lcd) {
|
||||||
|
LCD_ERROR_CHECK(st7789_lcd_reset(lcd));
|
||||||
|
LCD_ERROR_CHECK(st7789_lcd_sleep(lcd, false));
|
||||||
|
|
||||||
|
LCD_ERROR_CHECK(lcd->cb.delay_cb(lcd->user_data, 120));
|
||||||
|
|
||||||
|
LCD_ERROR_CHECK(st7789_lcd_execute_sequence(&lcd->cb, lcd->user_data, st7789_lcd_init_sequence,
|
||||||
|
sizeof(st7789_lcd_init_sequence)));
|
||||||
|
LCD_ERROR_CHECK(st7789_lcd_config(lcd));
|
||||||
|
LCD_ERROR_CHECK(st7789_lcd_power(lcd, true));
|
||||||
|
|
||||||
|
return ST7789_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
st7789_lcd_ret_t st7789_lcd_power(st7789_lcd_t *lcd, bool on) {
|
||||||
|
uint8_t tx_buf[1] = {0x28U};
|
||||||
|
if (on) {
|
||||||
|
tx_buf[0] = 0x29U;
|
||||||
|
}
|
||||||
|
|
||||||
|
LCD_ERROR_CHECK(lcd->cb.write_command_cb(lcd->user_data, tx_buf, 1));
|
||||||
|
|
||||||
|
return ST7789_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
st7789_lcd_ret_t st7789_lcd_upload(st7789_lcd_t *lcd, st7789_lcd_coord_t *coord, uint8_t *data) {
|
||||||
|
LCD_ERROR_CHECK(st7789_lcd_window(lcd, coord));
|
||||||
|
|
||||||
|
uint32_t data_size = (coord->y_end - coord->y_start + 1) * (coord->x_end - coord->x_start + 1);
|
||||||
|
|
||||||
|
switch (lcd->config.pix_fmt) {
|
||||||
|
case ST7789_LCD_PIXFMT_RGB444:
|
||||||
|
data_size = data_size * 3 / 2;
|
||||||
|
break;
|
||||||
|
case ST7789_LCD_PIXFMT_RGB565:
|
||||||
|
data_size = data_size * 2;
|
||||||
|
break;
|
||||||
|
case ST7789_LCD_PIXFMT_RGB666:
|
||||||
|
case ST7789_LCD_PIXFMT_RGB888:
|
||||||
|
default:
|
||||||
|
data_size = data_size * 3;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t tx_buf[1] = {0x2C};
|
||||||
|
|
||||||
|
LCD_ERROR_CHECK(lcd->cb.write_command_cb(lcd->user_data, tx_buf, 0x01));
|
||||||
|
LCD_ERROR_CHECK(lcd->cb.write_data_cb(lcd->user_data, data, data_size));
|
||||||
|
|
||||||
|
return ST7789_SUCCESS;
|
||||||
|
}
|
58
main/lib/st7789_lcd.h
Normal file
58
main/lib/st7789_lcd.h
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
#ifndef ST7789_LCD_H
|
||||||
|
#define ST7789_LCD_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
ST7789_SUCCESS,
|
||||||
|
ST7789_FAIL,
|
||||||
|
} st7789_lcd_ret_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
ST7789_LCD_DIR_0,
|
||||||
|
ST7789_LCD_DIR_90,
|
||||||
|
ST7789_LCD_DIR_180,
|
||||||
|
ST7789_LCD_DIR_270,
|
||||||
|
} st7789_lcd_dir_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
ST7789_LCD_PIXFMT_RGB444 = 3U,
|
||||||
|
ST7789_LCD_PIXFMT_RGB565 = 5U,
|
||||||
|
ST7789_LCD_PIXFMT_RGB666 = 6U,
|
||||||
|
ST7789_LCD_PIXFMT_RGB888 = 7U,
|
||||||
|
} st7789_lcd_pixfmt_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
st7789_lcd_ret_t (*write_command_cb)(void *handle, uint8_t *command, uint32_t len);
|
||||||
|
st7789_lcd_ret_t (*write_data_cb)(void *handle, uint8_t *data, uint32_t len);
|
||||||
|
st7789_lcd_ret_t (*reset_cb)(void *handle);
|
||||||
|
st7789_lcd_ret_t (*poll_busy_cb)(void *handle);
|
||||||
|
st7789_lcd_ret_t (*delay_cb)(void *handle, uint32_t msec);
|
||||||
|
} st7789_lcd_cb_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t x_start;
|
||||||
|
uint32_t x_end;
|
||||||
|
uint32_t y_start;
|
||||||
|
uint32_t y_end;
|
||||||
|
} st7789_lcd_coord_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
st7789_lcd_dir_t dir;
|
||||||
|
st7789_lcd_pixfmt_t pix_fmt;
|
||||||
|
bool inverted;
|
||||||
|
bool bgr_mode;
|
||||||
|
} st7789_lcd_config_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
st7789_lcd_cb_t cb;
|
||||||
|
st7789_lcd_config_t config;
|
||||||
|
void *user_data;
|
||||||
|
} st7789_lcd_t;
|
||||||
|
|
||||||
|
st7789_lcd_ret_t st7789_lcd_init(st7789_lcd_t *lcd);
|
||||||
|
st7789_lcd_ret_t st7789_lcd_power(st7789_lcd_t *lcd, bool on);
|
||||||
|
st7789_lcd_ret_t st7789_lcd_upload(st7789_lcd_t *lcd, st7789_lcd_coord_t *coord, uint8_t *data);
|
||||||
|
|
||||||
|
#endif
|
0
sdkconfig.ci
Normal file
0
sdkconfig.ci
Normal file
Loading…
Reference in New Issue
Block a user