diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 85c0f48..1950ad3 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -1,3 +1,3 @@ idf_component_register(SRCS "spincoat-plater-firmware.c" "dshot_esc_encoder.c" - PRIV_REQUIRES esp_driver_rmt esp_driver_gpio esp_driver_uart esp_driver_spi esp_lcd + PRIV_REQUIRES esp_driver_rmt esp_driver_gpio esp_driver_uart esp_driver_spi esp_lcd unity INCLUDE_DIRS ".") diff --git a/main/Kconfig b/main/Kconfig index 86e5efa..f9df9c7 100644 --- a/main/Kconfig +++ b/main/Kconfig @@ -49,5 +49,11 @@ menu "Pin Mapping Configuration" default 240 help This is the vertical resolution for the front-panel SPI LCD + config TFT_BPP + int "The bits per pixel of the TFT display" + default 16 + help + This is the bits per pixel for the TFT display and influences + how much memory the display buffer takes up endmenu diff --git a/main/spincoat-plater-firmware.c b/main/spincoat-plater-firmware.c index 87642ac..29eb3b5 100644 --- a/main/spincoat-plater-firmware.c +++ b/main/spincoat-plater-firmware.c @@ -8,6 +8,10 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" +#include "freertos/semphr.h" + +#include "unity.h" +#include "unity_test_runner.h" #include "esp_log.h" #include "driver/rmt_tx.h" @@ -18,6 +22,7 @@ #include "esp_lcd_panel_ops.h" #include "driver/spi_common.h" #include "esp_lcd_panel_io.h" +#include "esp_lcd_panel_commands.h" #include "esp_lcd_ili9341.h" #include "dshot_esc_encoder.h" @@ -41,11 +46,14 @@ #define GPIO_TFT_BL CONFIG_TFT_BL_PIN // Backlight #define TFT_HRES CONFIG_TFT_HRES #define TFT_VRES CONFIG_TFT_VRES +#define TFT_BPP CONFIG_TFT_BPP #define ESP_INTR_FLAG_DEFAULT 0 static const char *TAG = "spincoat-plater-firmware"; +static SemaphoreHandle_t refresh_finish = NULL; + static QueueHandle_t uart_queue = NULL; const int uart_buffer_size = (1024 * 2); @@ -122,6 +130,9 @@ void init_rmt_esc_tx(void) { initialize_esc_throttle(); } +/** + * Initialize the UART receive pin so that we can receive telemetry data from the connected ESC. + */ void init_telemetry_uart_rx(void) { uart_config_t uart_config = { .baud_rate = 115200, @@ -137,41 +148,49 @@ void init_telemetry_uart_rx(void) { ESP_ERROR_CHECK(uart_set_pin(UART_NUM, UART_PIN_NO_CHANGE, GPIO_ESC_RX, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE)); } -void spi_lcd_transfer_done(void) { - return; +/** + * Callback for the TFT LCD, notifying when the screen is ready for another chunk of data and + * releasing the drawing semaphore. + */ +IRAM_ATTR static bool notify_refresh_ready(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *edata, void *user_ctx) +{ + BaseType_t need_yield = pdFALSE; + + xSemaphoreGiveFromISR(refresh_finish, &need_yield); + return (need_yield == pdTRUE); } +/** + * Draws a test bitmap of stripes of colors to the LCD. + */ +static void test_draw_bitmap(esp_lcd_panel_handle_t panel_handle) +{ + refresh_finish = xSemaphoreCreateBinary(); + TEST_ASSERT_NOT_NULL(refresh_finish); + + uint16_t row_line = TFT_VRES / TFT_BPP; + uint8_t byte_per_pixel = TFT_BPP / 8; + uint8_t *color = (uint8_t *)heap_caps_calloc(1, row_line * TFT_VRES * byte_per_pixel, MALLOC_CAP_DMA); + TEST_ASSERT_NOT_NULL(color); + + for (int j = 0; j < TFT_BPP; j++) { + for (int i = 0; i < row_line * TFT_HRES ; i++) { + for (int k = 0; k < byte_per_pixel; k++) { + color[i * byte_per_pixel + k] = (SPI_SWAP_DATA_TX(BIT(j), TFT_BPP) >> (k * 8)) & 0xff; + } + } + TEST_ESP_OK(esp_lcd_panel_draw_bitmap(panel_handle, 0, j * row_line, TFT_HRES , (j + 1) * row_line, color)); + xSemaphoreTake(refresh_finish, portMAX_DELAY); + } + free(color); + vSemaphoreDelete(refresh_finish); +} + +/** + * Initializes the SPI LCD in preparation for writing graphics to it. + */ void init_spi_lcd(void) { - ESP_LOGI(TAG, "Initialize SPI bus"); - // TODO might need to replace with another config var - const spi_bus_config_t bus_config = ILI9341_PANEL_BUS_SPI_CONFIG(GPIO_TFT_SCKL, - GPIO_TFT_MOSI, - TFT_HRES * TFT_VRES * sizeof(uint16_t)); - ESP_ERROR_CHECK(spi_bus_initialize(LCD_SPI_HOST, &bus_config, SPI_DMA_CH_AUTO)); - - ESP_LOGI(TAG, "Install panel IO"); - esp_lcd_panel_io_handle_t io_handle = NULL; - const esp_lcd_panel_io_spi_config_t io_config = ILI9341_PANEL_IO_SPI_CONFIG(GPIO_TFT_CS, GPIO_TFT_DC, - NULL, NULL); - - ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)LCD_SPI_HOST, &io_config, &io_handle)); - - ESP_LOGI(TAG, "Install ILI9341 panel driver"); - esp_lcd_panel_handle_t panel_handle = NULL; - const esp_lcd_panel_dev_config_t panel_config = { - .reset_gpio_num = -1, - .rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB, - .bits_per_pixel = 16, - }; - - ESP_ERROR_CHECK(esp_lcd_new_panel_ili9341(io_handle, &panel_config, &panel_handle)); - ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle)); - ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle)); - ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_handle, true)); - - ESP_LOGI(TAG, "Turning on backlight"); - printf("Configured pin is reported as %d\n", CONFIG_TFT_BL_PIN); - // TODO: This pin isn't going high. Configure it properly. + ESP_LOGI(TAG, "Turn on backlight"); gpio_config_t io_conf = { .pin_bit_mask = (1ULL << GPIO_TFT_BL), @@ -182,11 +201,53 @@ void init_spi_lcd(void) { }; gpio_config(&io_conf); + gpio_set_level(GPIO_TFT_BL, 1); + + ESP_LOGI(TAG, "Initialize SPI bus"); + const spi_bus_config_t bus_config = ILI9341_PANEL_BUS_SPI_CONFIG(GPIO_TFT_SCKL, + GPIO_TFT_MOSI, TFT_HRES * 80 * TFT_BPP / 8); + TEST_ESP_OK(spi_bus_initialize(LCD_SPI_HOST, &bus_config, SPI_DMA_CH_AUTO)); + + ESP_LOGI(TAG, "Install panel IO"); + esp_lcd_panel_io_handle_t io_handle = NULL; + const esp_lcd_panel_io_spi_config_t io_config = ILI9341_PANEL_IO_SPI_CONFIG(GPIO_TFT_CS, GPIO_TFT_DC, + + TEST_ESP_OK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)LCD_SPI_HOST, &io_config, &io_handle)); + + ESP_LOGI(TAG, "Install ili9341 panel driver"); + esp_lcd_panel_handle_t panel_handle = NULL; + const esp_lcd_panel_dev_config_t panel_config = { + .reset_gpio_num = -1, // Shared with Touch reset +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) + .color_space = ESP_LCD_COLOR_SPACE_BGR, +#elif ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(6, 0, 0) + .rgb_endian = LCD_RGB_ENDIAN_BGR, +#else + .rgb_ele_order = LCD_RGB_ELEMENT_ORDER_BGR, +#endif + .bits_per_pixel = TFT_BPP, + }; + TEST_ESP_OK(esp_lcd_new_panel_ili9341(io_handle, &panel_config, &panel_handle)); + TEST_ESP_OK(esp_lcd_panel_reset(panel_handle)); + TEST_ESP_OK(esp_lcd_panel_init(panel_handle)); + TEST_ESP_OK(esp_lcd_panel_mirror(panel_handle, true, true)); +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) + TEST_ESP_OK(esp_lcd_panel_disp_off(panel_handle, false)); +#else + TEST_ESP_OK(esp_lcd_panel_disp_on_off(panel_handle, true)); +#endif - //gpio_reset_pin(GPIO_TFT_BL); - //gpio_set_direction(GPIO_TFT_BL, GPIO_MODE_OUTPUT); - ESP_ERROR_CHECK(gpio_set_level(GPIO_TFT_BL, 1)); ESP_LOGI(TAG, "Finished init of spi LCD."); + ESP_LOGI(TAG, "Drawing bitmap.");; + test_draw_bitmap(panel_handle); + vTaskDelay(pdMS_TO_TICKS(3000)); + + // Tear it back down, move this into a function to clean up after ourselves if it's ever needed. + ESP_LOGI(TAG, "Destroying and cleaning up LCD/SPI handles."); + gpio_reset_pin(GPIO_TFT_BL); + TEST_ESP_OK(esp_lcd_panel_del(panel_handle)); + TEST_ESP_OK(esp_lcd_panel_io_del(io_handle)); + TEST_ESP_OK(spi_bus_free(LCD_SPI_HOST)); } /**