diff --git a/components/esp_lcd/src/esp_lcd_panel_io_spi.c b/components/esp_lcd/src/esp_lcd_panel_io_spi.c index 6a355e08e1..0d8a4a7e0f 100644 --- a/components/esp_lcd/src/esp_lcd_panel_io_spi.c +++ b/components/esp_lcd/src/esp_lcd_panel_io_spi.c @@ -15,12 +15,15 @@ #endif #include "esp_lcd_panel_io_interface.h" #include "esp_lcd_panel_io.h" +#include "hal/spi_ll.h" #include "driver/spi_master.h" #include "driver/gpio.h" #include "esp_log.h" #include "esp_check.h" #include "esp_lcd_common.h" +#define LCD_SPI_MAX_DATA_SIZE (SPI_LL_DATA_MAX_BIT_LEN / 8) + static const char *TAG = "lcd_panel.io.spi"; static esp_err_t panel_io_spi_tx_param(esp_lcd_panel_io_t *io, int lcd_cmd, const void *param, size_t param_size); @@ -33,7 +36,7 @@ typedef struct { spi_transaction_t base; struct { unsigned int dc_gpio_level: 1; - unsigned int trans_is_color: 1; + unsigned int en_trans_done_cb: 1; } flags; } lcd_spi_trans_descriptor_t; @@ -250,18 +253,53 @@ static esp_err_t panel_io_spi_tx_color(esp_lcd_panel_io_t *io, int lcd_cmd, cons ret = spi_device_polling_transmit(spi_panel_io->spi_dev, &lcd_trans->base); ESP_GOTO_ON_ERROR(ret, err, TAG, "spi transmit (polling) command failed"); - // sending LCD color data - lcd_trans->flags.trans_is_color = 1; - lcd_trans->flags.dc_gpio_level = spi_panel_io->flags.dc_data_level; // set D/C line to data mode - lcd_trans->base.length = color_size * 8; // transaction length is in bits - lcd_trans->base.tx_buffer = color; - if (spi_panel_io->flags.dc_as_cmd_phase) { // encoding DC value to SPI command phase when necessary - lcd_trans->base.cmd = spi_panel_io->flags.dc_data_level; - } - // color data is usually large, using queue+blocking mode - ret = spi_device_queue_trans(spi_panel_io->spi_dev, &lcd_trans->base, portMAX_DELAY); - ESP_GOTO_ON_ERROR(ret, err, TAG, "spi transmit (queue) color failed"); - spi_panel_io->num_trans_inflight++; + // split to chunks if required: + // the SPI bus has a maximum transaction size determined by SPI_USR_MOSI_DBITLEN's bit width + do { + size_t chunk_size = color_size; + + if (spi_panel_io->num_trans_inflight < spi_panel_io->queue_size) { + // get the next available transaction + lcd_trans = &spi_panel_io->trans_pool[spi_panel_io->num_trans_inflight]; + } else { + // transaction pool has used up, recycle one transaction + ret = spi_device_get_trans_result(spi_panel_io->spi_dev, &spi_trans, portMAX_DELAY); + ESP_GOTO_ON_ERROR(ret, err, TAG, "recycle spi transactions failed"); + lcd_trans = __containerof(spi_trans, lcd_spi_trans_descriptor_t, base); + spi_panel_io->num_trans_inflight--; + } + memset(lcd_trans, 0, sizeof(lcd_spi_trans_descriptor_t)); + + // SPI per-transfer size has its limitation, if the color buffer is too big, we need to split it into multiple trunks + if (chunk_size > LCD_SPI_MAX_DATA_SIZE) { + // cap the transfer size to the maximum supported by the bus + chunk_size = LCD_SPI_MAX_DATA_SIZE; + } else { + // mark en_trans_done_cb only at the last round to avoid premature completion callback + lcd_trans->flags.en_trans_done_cb = 1; + } + + lcd_trans->base.user = spi_panel_io; + lcd_trans->flags.dc_gpio_level = spi_panel_io->flags.dc_data_level; // set D/C line to data mode + lcd_trans->base.length = chunk_size * 8; // transaction length is in bits + lcd_trans->base.tx_buffer = color; + if (spi_panel_io->flags.dc_as_cmd_phase) { // encoding DC value to SPI command phase when necessary + lcd_trans->base.cmd = spi_panel_io->flags.dc_data_level; + } + if (spi_panel_io->flags.octal_mode) { + // use 8 lines for transmitting command, address and data + lcd_trans->base.flags |= (SPI_TRANS_MULTILINE_CMD | SPI_TRANS_MULTILINE_ADDR | SPI_TRANS_MODE_OCT); + } + + // color data is usually large, using queue+blocking mode + ret = spi_device_queue_trans(spi_panel_io->spi_dev, &lcd_trans->base, portMAX_DELAY); + ESP_GOTO_ON_ERROR(ret, err, TAG, "spi transmit (queue) color failed"); + spi_panel_io->num_trans_inflight++; + + // move on to the next chunk + color = (const uint8_t *)color + chunk_size; + color_size -= chunk_size; + } while (color_size > 0); // continue while we have remaining data to transmit err: return ret; @@ -280,7 +318,7 @@ static void lcd_spi_post_trans_color_cb(spi_transaction_t *trans) { esp_lcd_panel_io_spi_t *spi_panel_io = trans->user; lcd_spi_trans_descriptor_t *lcd_trans = __containerof(trans, lcd_spi_trans_descriptor_t, base); - if (lcd_trans->flags.trans_is_color) { + if (lcd_trans->flags.en_trans_done_cb) { if (spi_panel_io->on_color_trans_done) { spi_panel_io->on_color_trans_done(&spi_panel_io->base, NULL, spi_panel_io->user_ctx); } diff --git a/components/esp_lcd/test_apps/spi_lcd/main/test_spi_lcd_panel.c b/components/esp_lcd/test_apps/spi_lcd/main/test_spi_lcd_panel.c index 6721605942..ea9514fbbd 100644 --- a/components/esp_lcd/test_apps/spi_lcd/main/test_spi_lcd_panel.c +++ b/components/esp_lcd/test_apps/spi_lcd/main/test_spi_lcd_panel.c @@ -71,9 +71,10 @@ void test_spi_lcd_common_initialize(esp_lcd_panel_io_handle_t *io_handle, esp_lc TEST_ESP_OK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)TEST_SPI_HOST_ID, &io_config, io_handle)); } +#define TEST_IMG_SIZE (200 * 200 * sizeof(uint16_t)) + static void lcd_panel_test(esp_lcd_panel_io_handle_t io_handle, esp_lcd_panel_handle_t panel_handle) { -#define TEST_IMG_SIZE (100 * 100 * sizeof(uint16_t)) uint8_t *img = heap_caps_malloc(TEST_IMG_SIZE, MALLOC_CAP_DMA); TEST_ASSERT_NOT_NULL(img); @@ -87,10 +88,10 @@ static void lcd_panel_test(esp_lcd_panel_io_handle_t io_handle, esp_lcd_panel_ha for (int i = 0; i < 200; i++) { uint8_t color_byte = esp_random() & 0xFF; - int x_start = esp_random() % (TEST_LCD_H_RES - 100); - int y_start = esp_random() % (TEST_LCD_V_RES - 100); + int x_start = esp_random() % (TEST_LCD_H_RES - 200); + int y_start = esp_random() % (TEST_LCD_V_RES - 200); memset(img, color_byte, TEST_IMG_SIZE); - esp_lcd_panel_draw_bitmap(panel_handle, x_start, y_start, x_start + 100, y_start + 100, img); + esp_lcd_panel_draw_bitmap(panel_handle, x_start, y_start, x_start + 200, y_start + 200, img); } // turn off screen esp_lcd_panel_disp_off(panel_handle, true); @@ -99,7 +100,6 @@ static void lcd_panel_test(esp_lcd_panel_io_handle_t io_handle, esp_lcd_panel_ha TEST_ESP_OK(spi_bus_free(TEST_SPI_HOST_ID)); TEST_ESP_OK(gpio_reset_pin(TEST_LCD_BK_LIGHT_GPIO)); free(img); -#undef TEST_IMG_SIZE } TEST_CASE("lcd_panel_spi_io_test", "[lcd]") diff --git a/components/hal/esp32/include/hal/spi_ll.h b/components/hal/esp32/include/hal/spi_ll.h index 89b4dedae3..63efb384eb 100644 --- a/components/hal/esp32/include/hal/spi_ll.h +++ b/components/hal/esp32/include/hal/spi_ll.h @@ -1,16 +1,8 @@ -// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at - -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/* + * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ /******************************************************************************* * NOTICE @@ -49,6 +41,8 @@ extern "C" { #define SPI_LL_PERIPH_CLK_FREQ (80 * 1000000) #define SPI_LL_GET_HW(ID) ((ID)==0? &SPI1:((ID)==1? &SPI2 : &SPI3)) +#define SPI_LL_DATA_MAX_BIT_LEN (1 << 24) + /** * The data structure holding calculated clock configuration. Since the * calculation needs long time, it should be calculated during initialization and diff --git a/components/hal/esp32c2/include/hal/spi_ll.h b/components/hal/esp32c2/include/hal/spi_ll.h index a356bc1595..13f5b6ed8d 100644 --- a/components/hal/esp32c2/include/hal/spi_ll.h +++ b/components/hal/esp32c2/include/hal/spi_ll.h @@ -40,6 +40,8 @@ extern "C" { #define SPI_LL_PERIPH_CLK_FREQ (80 * 1000000) #define SPI_LL_GET_HW(ID) ((ID)==0? ({abort();NULL;}):&GPSPI2) +#define SPI_LL_DATA_MAX_BIT_LEN (1 << 18) + /** * The data structure holding calculated clock configuration. Since the * calculation needs long time, it should be calculated during initialization and diff --git a/components/hal/esp32c3/include/hal/spi_ll.h b/components/hal/esp32c3/include/hal/spi_ll.h index 5aace3ffff..01070e918f 100644 --- a/components/hal/esp32c3/include/hal/spi_ll.h +++ b/components/hal/esp32c3/include/hal/spi_ll.h @@ -40,6 +40,8 @@ extern "C" { #define SPI_LL_PERIPH_CLK_FREQ (80 * 1000000) #define SPI_LL_GET_HW(ID) ((ID)==0? ({abort();NULL;}):&GPSPI2) +#define SPI_LL_DATA_MAX_BIT_LEN (1 << 18) + /** * The data structure holding calculated clock configuration. Since the * calculation needs long time, it should be calculated during initialization and diff --git a/components/hal/esp32h2/include/hal/spi_ll.h b/components/hal/esp32h2/include/hal/spi_ll.h index 764f3fd872..43893938fa 100644 --- a/components/hal/esp32h2/include/hal/spi_ll.h +++ b/components/hal/esp32h2/include/hal/spi_ll.h @@ -1,16 +1,8 @@ -// Copyright 2020 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at - -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/* + * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ /******************************************************************************* * NOTICE @@ -48,6 +40,8 @@ extern "C" { #define SPI_LL_PERIPH_CLK_FREQ (80 * 1000000) #define SPI_LL_GET_HW(ID) ((ID)==0? ({abort();NULL;}):&GPSPI2) +#define SPI_LL_DATA_MAX_BIT_LEN (1 << 18) + /** * The data structure holding calculated clock configuration. Since the * calculation needs long time, it should be calculated during initialization and diff --git a/components/hal/esp32s2/include/hal/spi_ll.h b/components/hal/esp32s2/include/hal/spi_ll.h index c6dac13154..b975206d0f 100644 --- a/components/hal/esp32s2/include/hal/spi_ll.h +++ b/components/hal/esp32s2/include/hal/spi_ll.h @@ -43,6 +43,8 @@ extern "C" { #define SPI_LL_PERIPH_CLK_FREQ (80 * 1000000) #define SPI_LL_GET_HW(ID) ((ID)==0? ({abort();NULL;}):((ID)==1? &GPSPI2 : &GPSPI3)) +#define SPI_LL_DATA_MAX_BIT_LEN (1 << 23) + /** * The data structure holding calculated clock configuration. Since the * calculation needs long time, it should be calculated during initialization and diff --git a/components/hal/esp32s3/include/hal/spi_ll.h b/components/hal/esp32s3/include/hal/spi_ll.h index a223b97600..c7dd96fa8c 100644 --- a/components/hal/esp32s3/include/hal/spi_ll.h +++ b/components/hal/esp32s3/include/hal/spi_ll.h @@ -42,6 +42,8 @@ extern "C" { #define SPI_LL_PERIPH_CLK_FREQ (80 * 1000000) #define SPI_LL_GET_HW(ID) ((ID)==0? ({abort();NULL;}):((ID)==1? &GPSPI2 : &GPSPI3)) +#define SPI_LL_DATA_MAX_BIT_LEN (1 << 18) + /** * The data structure holding calculated clock configuration. Since the * calculation needs long time, it should be calculated during initialization and diff --git a/tools/ci/check_copyright_ignore.txt b/tools/ci/check_copyright_ignore.txt index 2c4a2ffbd5..965ecac3df 100644 --- a/tools/ci/check_copyright_ignore.txt +++ b/tools/ci/check_copyright_ignore.txt @@ -834,7 +834,6 @@ components/hal/esp32/include/hal/sigmadelta_ll.h components/hal/esp32/include/hal/soc_ll.h components/hal/esp32/include/hal/spi_flash_encrypted_ll.h components/hal/esp32/include/hal/spi_flash_ll.h -components/hal/esp32/include/hal/spi_ll.h components/hal/esp32/include/hal/touch_sensor_hal.h components/hal/esp32/include/hal/touch_sensor_ll.h components/hal/esp32/include/hal/trace_ll.h @@ -879,7 +878,6 @@ components/hal/esp32h2/include/hal/sigmadelta_ll.h components/hal/esp32h2/include/hal/soc_ll.h components/hal/esp32h2/include/hal/spi_flash_encrypted_ll.h components/hal/esp32h2/include/hal/spi_flash_ll.h -components/hal/esp32h2/include/hal/spi_ll.h components/hal/esp32h2/include/hal/spimem_flash_ll.h components/hal/esp32h2/include/hal/twai_ll.h components/hal/esp32h2/include/hal/uhci_ll.h