ESP32_TV_Demo/main/app_lcd_impl.c

172 lines
4.4 KiB
C

/* 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;
}