Description
Hi,
As we've discussed before there's the desire to abstract the communication interface (SPI, I2C, Parallel, etc.) in the display drivers.
Current implementation
We only have support for SPI and I2C. Here's how currently (develop branch) a command and data are being sent over SPI (ili9341):
static inline void set_cmd_mode(lv_disp_drv_t * drv)
{
display_port_gpio_dc(drv, 0);
}
static inline void set_data_mode(lv_disp_drv_t * drv)
{
display_port_gpio_dc(drv, 1);
}
static void ili9341_send_cmd(lv_disp_drv_t * drv, uint8_t cmd)
{
disp_wait_for_pending_transactions();
set_cmd_mode(drv);
disp_spi_send_data(&cmd, 1);
}
static void ili9341_send_data(lv_disp_drv_t *drv, void * data, uint16_t length)
{
disp_wait_for_pending_transactions();
set_data_mode(drv);
disp_spi_send_data(data, length);
}
static void ili9341_send_color(lv_disp_drv_t *drv, void * data, uint16_t length)
{
disp_wait_for_pending_transactions();
set_data_mode(drv);
disp_spi_send_colors(data, length);
}
Here's how they're sent over I2C:
static uint8_t send_data(lv_disp_drv_t *disp_drv, void *bytes, size_t bytes_len)
{
(void) disp_drv;
uint8_t *data = (uint8_t *) bytes;
return lvgl_i2c_write(OLED_I2C_PORT, OLED_I2C_ADDRESS, data[0], data + 1, bytes_len - 1 );
}
static uint8_t send_pixels(lv_disp_drv_t *disp_drv, void *color_buffer, size_t buffer_len)
{
(void) disp_drv;
return lvgl_i2c_write(OLED_I2C_PORT, OLED_I2C_ADDRESS, OLED_CONTROL_BYTE_DATA_STREAM, color_buffer, buffer_len);
}
In the SPI case we have two functions to send data: disp_spi_send_data
and disp_spi_send_colors
, defined in disp_spi.h
:
static inline void disp_spi_send_data(uint8_t *data, size_t length) {
disp_spi_transaction(data, length, DISP_SPI_SEND_POLLING, NULL, 0, 0);
}
static inline void disp_spi_send_colors(uint8_t *data, size_t length) {
disp_spi_transaction(data, length,
DISP_SPI_SEND_QUEUED | DISP_SPI_SIGNAL_FLUSH,
NULL, 0, 0);
}
The difference between them is that the latest will be sent using DMA, and when the transmission is done an interrupt is generated and we call lv_disp_flush_ready
.
What we need?
Communication interface shouldn't matter to the display driver, it only cares to send data in polling or async mode (and knowing when it's done).
Proposal
We could initiate by adding some functions to the lv_port API (names are long, but descriptive, suggestions are very welcomed)
display_send_data
: Will send data in polling mode.display_send_data_async
: Will send data in async mode.display_send_cmd
: Will send commands in polling mode.
Here's the proposed implementation, I think it's a good first step (arguments and names to be improved):
void display_send_data(lv_disp_drv_t *drv, void * data, uint16_t length)
{
#if defined CONFIG_LV_TFT_DISPLAY_PROTOCOL_SPI
set_data_mode(drv);
disp_spi_send_data(drv, data, length);
#elif defined CONFIG_LV_TFT_DISPLAY_PROTOCOL_I2C
lvgl_i2c_write(OLED_I2C_PORT, OLED_I2C_ADDRESS, OLED_CONTROL_BYTE_DATA_STREAM, data, length);
#endif
}
void display_send_data_async(lv_disp_drv_t *drv, void * data, uint16_t length)
{
#if defined CONFIG_LV_TFT_DISPLAY_PROTOCOL_SPI
set_data_mode(drv);
disp_spi_send_colors(drv, data, length);
#elif defined CONFIG_LV_TFT_DISPLAY_PROTOCOL_I2C
/* TBD */
#endif
}
void display_send_cmd(lv_disp_drv_t *drv, uint8_t cmd, void * args, uint16_t args_len)
{
#if defined CONFIG_LV_TFT_DISPLAY_PROTOCOL_SPI
set_cmd_mode(drv);
disp_spi_send_data(drv, cmd, args, args_len);
#elif defined CONFIG_LV_TFT_DISPLAY_PROTOCOL_I2C
lvgl_i2c_write(OLED_I2C_PORT, OLED_I2C_ADDRESS, cmd, args, args_len);
#endif
}
What do you think @kisvegabor @tore-espressif