Merge pull request #11892 from gemu2015/lvgl_dma

lvgl initial dma support
This commit is contained in:
Theo Arends 2021-04-26 11:59:44 +02:00 committed by GitHub
commit 0c29c74667
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 236 additions and 16 deletions

View File

@ -624,8 +624,8 @@ char *Renderer::devname(void) {
return (char*)dname;
}
uint16_t Renderer::lvgl_pars(void) {
return lvgl_param;
LVGL_PARAMS *Renderer::lvgl_pars(void) {
return &lvgl_param;
}
void VButton::xdrawButton(bool inverted) {

View File

@ -16,6 +16,23 @@
// a. in class GFX setCursor,setTextSize => virtual
// b. textcolor,textbgcolor => public;
typedef struct LVGL_PARAMS {
uint16_t fluslines;
union {
uint8_t data;
struct {
uint8_t resvd_0 : 1;
uint8_t resvd_1 : 1;
uint8_t resvd_2 : 1;
uint8_t resvd_3 : 1;
uint8_t resvd_4 : 1;
uint8_t resvd_5 : 1;
uint8_t resvd_6 : 1;
uint8_t use_dma : 1;
};
};
}LVGL_PARAMS;
typedef void (*pwr_cb)(uint8_t);
typedef void (*dim_cb)(uint8_t);
@ -51,7 +68,7 @@ public:
virtual int8_t color_type(void);
virtual void Splash(void);
virtual char *devname(void);
virtual uint16_t lvgl_pars(void);
virtual LVGL_PARAMS *lvgl_pars(void);
void setDrawMode(uint8_t mode);
uint8_t drawmode;
@ -60,7 +77,7 @@ public:
virtual uint8_t *allocate_framebuffer(uint32_t size);
pwr_cb pwr_cbp = 0;
dim_cb dim_cbp = 0;
uint16_t lvgl_param = 0;
LVGL_PARAMS lvgl_param;
private:
void DrawCharAt(int16_t x, int16_t y, char ascii_char,int16_t colored);
inline void drawFastVLineInternal(int16_t x, int16_t y, int16_t h, uint16_t color) __attribute__((always_inline));

View File

@ -283,7 +283,8 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) {
lut3time = next_val(&lp1);
break;
case 'B':
lvgl_param = next_val(&lp1);
lvgl_param.fluslines = next_val(&lp1);
lvgl_param.use_dma = next_val(&lp1);
break;
}
}
@ -462,9 +463,18 @@ Renderer *uDisplay::Init(void) {
if (spi_nr == 1) {
uspi = &SPI;
uspi->begin(spi_clk, spi_miso, spi_mosi, -1);
if (lvgl_param.use_dma) {
spi_host = VSPI_HOST;
initDMA(spi_cs);
}
} else if (spi_nr == 2) {
uspi = new SPIClass(HSPI);
uspi->begin(spi_clk, spi_miso, spi_mosi, -1);
if (lvgl_param.use_dma) {
spi_host = HSPI_HOST;
initDMA(spi_cs);
}
} else {
pinMode(spi_clk, OUTPUT);
digitalWrite(spi_clk, LOW);
@ -1018,6 +1028,8 @@ static inline uint8_t ulv_color_to1(uint16_t color) {
void uDisplay::pushColors(uint16_t *data, uint16_t len, boolean first) {
uint16_t color;
//Serial.printf("push %x - %d\n", (uint32_t)data, len);
if (bpp != 16) {
// stupid monchrome version
for (uint32_t y = seta_yp1; y < seta_yp2; y++) {
@ -1038,7 +1050,11 @@ void uDisplay::pushColors(uint16_t *data, uint16_t len, boolean first) {
uspi->write(*data++);
}
#else
uspi->writePixels(data, len * 2);
if (lvgl_param.use_dma) {
pushPixelsDMA(data, len );
} else {
uspi->writePixels(data, len * 2);
}
#endif
} else {
while (len--) {
@ -1758,3 +1774,164 @@ void uDisplay::drawFastHLine_EPD(int16_t x, int16_t y, int16_t w, uint16_t color
x++;
}
}
void uDisplay::beginTransaction(SPISettings s) {
#ifdef ESP32
if (lvgl_param.use_dma) {
dmaWait();
} else {
uspi->beginTransaction(s);
}
#else
uspi->beginTransaction(s);
#endif
}
void uDisplay::endTransaction(void) {
#ifdef ESP32
if (lvgl_param.use_dma) {
dmaBusy();
} else {
uspi->endTransaction();
}
#else
uspi->endTransaction();
#endif
}
// ESP 32 DMA section , derived from TFT_eSPI
#ifdef ESP32
/***************************************************************************************
** Function name: initDMA
** Description: Initialise the DMA engine - returns true if init OK
***************************************************************************************/
bool uDisplay::initDMA(bool ctrl_cs)
{
if (DMA_Enabled) return false;
esp_err_t ret;
spi_bus_config_t buscfg = {
.mosi_io_num = spi_mosi,
.miso_io_num = -1,
.sclk_io_num = spi_clk,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = width() * height() * 2 + 8, // TFT screen size
.flags = 0,
.intr_flags = 0
};
int8_t pin = -1;
if (ctrl_cs) pin = spi_cs;
spi_device_interface_config_t devcfg = {
.command_bits = 0,
.address_bits = 0,
.dummy_bits = 0,
.mode = SPI_MODE3,
.duty_cycle_pos = 0,
.cs_ena_pretrans = 0,
.cs_ena_posttrans = 0,
.clock_speed_hz = spi_speed*1000000,
.input_delay_ns = 0,
.spics_io_num = pin,
.flags = SPI_DEVICE_NO_DUMMY, //0,
.queue_size = 1,
.pre_cb = 0, //dc_callback, //Callback to handle D/C line
.post_cb = 0
};
ret = spi_bus_initialize(spi_host, &buscfg, 1);
ESP_ERROR_CHECK(ret);
ret = spi_bus_add_device(spi_host, &devcfg, &dmaHAL);
ESP_ERROR_CHECK(ret);
DMA_Enabled = true;
spiBusyCheck = 0;
return true;
}
/***************************************************************************************
** Function name: deInitDMA
** Description: Disconnect the DMA engine from SPI
***************************************************************************************/
void uDisplay::deInitDMA(void) {
if (!DMA_Enabled) return;
spi_bus_remove_device(dmaHAL);
spi_bus_free(spi_host);
DMA_Enabled = false;
}
/***************************************************************************************
** Function name: dmaBusy
** Description: Check if DMA is busy
***************************************************************************************/
bool uDisplay::dmaBusy(void) {
if (!DMA_Enabled || !spiBusyCheck) return false;
spi_transaction_t *rtrans;
esp_err_t ret;
uint8_t checks = spiBusyCheck;
for (int i = 0; i < checks; ++i) {
ret = spi_device_get_trans_result(dmaHAL, &rtrans, 0);
if (ret == ESP_OK) spiBusyCheck--;
}
//Serial.print("spiBusyCheck=");Serial.println(spiBusyCheck);
if (spiBusyCheck == 0) return false;
return true;
}
/***************************************************************************************
** Function name: dmaWait
** Description: Wait until DMA is over (blocking!)
***************************************************************************************/
void uDisplay::dmaWait(void) {
if (!DMA_Enabled || !spiBusyCheck) return;
spi_transaction_t *rtrans;
esp_err_t ret;
for (int i = 0; i < spiBusyCheck; ++i) {
ret = spi_device_get_trans_result(dmaHAL, &rtrans, portMAX_DELAY);
assert(ret == ESP_OK);
}
spiBusyCheck = 0;
}
/***************************************************************************************
** Function name: pushPixelsDMA
** Description: Push pixels to TFT (len must be less than 32767)
***************************************************************************************/
// This will byte swap the original image if setSwapBytes(true) was called by sketch.
void uDisplay::pushPixelsDMA(uint16_t* image, uint32_t len) {
if ((len == 0) || (!DMA_Enabled)) return;
dmaWait();
/*
if(_swapBytes) {
for (uint32_t i = 0; i < len; i++) (image[i] = image[i] << 8 | image[i] >> 8);
}*/
esp_err_t ret;
memset(&trans, 0, sizeof(spi_transaction_t));
trans.user = (void *)1;
trans.tx_buffer = image; //finally send the line data
trans.length = len * 16; //Data length, in bits
trans.flags = 0; //SPI_TRANS_USE_TXDATA flag
ret = spi_device_queue_trans(dmaHAL, &trans, portMAX_DELAY);
assert(ret == ESP_OK);
spiBusyCheck++;
}
#endif // ESP32

View File

@ -5,6 +5,9 @@
#include <renderer.h>
#include <Wire.h>
#include <SPI.h>
#ifdef ESP32
#include "driver/spi_master.h"
#endif
#define _UDSP_I2C 1
#define _UDSP_SPI 2
@ -58,8 +61,8 @@ enum uColorType { uCOLOR_BW, uCOLOR_COLOR };
#endif
#define SPI_BEGIN_TRANSACTION if (spi_nr <= 2) uspi->beginTransaction(spiSettings);
#define SPI_END_TRANSACTION if (spi_nr <= 2) uspi->endTransaction();
#define SPI_BEGIN_TRANSACTION if (spi_nr <= 2) beginTransaction(spiSettings);
#define SPI_END_TRANSACTION if (spi_nr <= 2) endTransaction();
#define SPI_CS_LOW if (spi_cs >= 0) GPIO_CLR(spi_cs);
#define SPI_CS_HIGH if (spi_cs >= 0) GPIO_SET(spi_cs);
#define SPI_DC_LOW if (spi_dc >= 0) GPIO_CLR(spi_dc);
@ -94,6 +97,8 @@ class uDisplay : public Renderer {
void SetDimCB(dim_cb cb) { dim_cbp = cb; };
private:
void beginTransaction(SPISettings s);
void endTransaction(void);
void setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1);
void drawPixel(int16_t x, int16_t y, uint16_t color);
void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
@ -209,6 +214,20 @@ class uDisplay : public Renderer {
uint16_t seta_xp2;
uint16_t seta_yp1;
uint16_t seta_yp2;
#ifdef ESP32
// dma section
bool DMA_Enabled = false;
uint8_t spiBusyCheck = 0;
spi_transaction_t trans;
spi_device_handle_t dmaHAL;
spi_host_device_t spi_host = VSPI_HOST;
// spi_host_device_t spi_host = VSPI_HOST;
bool initDMA(bool ctrl_cs);
void deInitDMA(void);
bool dmaBusy(void);
void dmaWait(void);
void pushPixelsDMA(uint16_t* image, uint32_t len);
#endif // ESP32
};

View File

@ -482,8 +482,8 @@ void RA8876::DisplayInit(int8_t p,int8_t size,int8_t rot,int8_t font) {
bool RA8876::initDisplay() {
lvgl_param = 10;
lvgl_param.fluslines = 10;
SPI.beginTransaction(m_spiSettings);
// Set chip config register

View File

@ -61,7 +61,7 @@ int32_t Epd47::Init(void) {
epd_init(EPD_LUT_1K);
hl = epd_hl_init(WAVEFORM);
epd47_buffer = epd_hl_get_framebuffer(&hl);
lvgl_param = 10;
lvgl_param.fluslines = 10;
return 0;
}

View File

@ -198,8 +198,6 @@ LvGLStatus Adafruit_LvGL_Glue::begin(Renderer *tft, bool debug) {
LvGLStatus Adafruit_LvGL_Glue::begin(Renderer *tft, void *touch, bool debug) {
lv_init();
// Allocate LvGL display buffer (x2 because DMA double buffering)
@ -209,9 +207,17 @@ LvGLStatus Adafruit_LvGL_Glue::begin(Renderer *tft, void *touch, bool debug) {
uint32_t lvgl_buffer_size;
//lvgl_buffer_size = LV_HOR_RES_MAX * LV_BUFFER_ROWS;
uint8_t flushlines = tft->lvgl_pars();
uint8_t flushlines = tft->lvgl_pars()->fluslines;
lvgl_buffer_size = tft->width() * (flushlines ? flushlines:LV_BUFFER_ROWS);
//Serial.printf("%d\n", lvgl_buffer_size);
if (tft->lvgl_pars()->use_dma) {
lvgl_buffer_size /= 2;
lv_pixel_buf2 = new lv_color_t[lvgl_buffer_size];
if (!lv_pixel_buf2) {
return status;
}
} else {
lv_pixel_buf2 = nullptr;
}
if ((lv_pixel_buf = new lv_color_t[lvgl_buffer_size])) {
@ -227,7 +233,7 @@ LvGLStatus Adafruit_LvGL_Glue::begin(Renderer *tft, void *touch, bool debug) {
// Initialize LvGL display buffers
lv_disp_buf_init(
&lv_disp_buf, lv_pixel_buf, // 1st half buf
nullptr, // 2nd half buf
lv_pixel_buf2, // 2nd half buf
lvgl_buffer_size);
// Initialize LvGL display driver

View File

@ -44,6 +44,7 @@ private:
lv_disp_drv_t lv_disp_drv;
lv_disp_buf_t lv_disp_buf;
lv_color_t *lv_pixel_buf;
lv_color_t *lv_pixel_buf2;
lv_indev_drv_t lv_indev_drv;
lv_indev_t *lv_input_dev_ptr;
Ticker tick;

View File

View File

View File

View File

View File