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