mirror of
https://github.com/MarlinFirmware/Marlin.git
synced 2026-01-05 14:17:42 -07:00
⚡️ Optimize Graphical TFT (#28103)
This commit is contained in:
parent
5e1a1fffcf
commit
23e7905b20
6 changed files with 80 additions and 74 deletions
|
|
@ -132,6 +132,9 @@ void TFT_FSMC::init() {
|
|||
DMAtx.Init.Priority = DMA_PRIORITY_HIGH;
|
||||
|
||||
LCD = (LCD_CONTROLLER_TypeDef *)controllerAddress;
|
||||
|
||||
DMAtx.Init.PeriphInc = DMA_PINC_DISABLE;
|
||||
HAL_DMA_Init(&DMAtx);
|
||||
}
|
||||
|
||||
uint32_t TFT_FSMC::getID() {
|
||||
|
|
@ -179,15 +182,19 @@ void TFT_FSMC::abort() {
|
|||
}
|
||||
|
||||
void TFT_FSMC::transmitDMA(uint32_t memoryIncrease, uint16_t *data, uint16_t count) {
|
||||
DMAtx.Init.PeriphInc = memoryIncrease;
|
||||
HAL_DMA_Init(&DMAtx);
|
||||
if (DMAtx.Init.PeriphInc != memoryIncrease) {
|
||||
DMAtx.Init.PeriphInc = memoryIncrease;
|
||||
HAL_DMA_Init(&DMAtx);
|
||||
}
|
||||
HAL_DMA_Start(&DMAtx, (uint32_t)data, (uint32_t)&(LCD->RAM), count);
|
||||
TERN_(TFT_SHARED_IO, while (isBusy()));
|
||||
}
|
||||
|
||||
void TFT_FSMC::transmit(uint32_t memoryIncrease, uint16_t *data, uint16_t count) {
|
||||
DMAtx.Init.PeriphInc = memoryIncrease;
|
||||
HAL_DMA_Init(&DMAtx);
|
||||
if (DMAtx.Init.PeriphInc != memoryIncrease) {
|
||||
DMAtx.Init.PeriphInc = memoryIncrease;
|
||||
HAL_DMA_Init(&DMAtx);
|
||||
}
|
||||
dataTransferBegin();
|
||||
HAL_DMA_Start(&DMAtx, (uint32_t)data, (uint32_t)&(LCD->RAM), count);
|
||||
HAL_DMA_PollForTransfer(&DMAtx, HAL_DMA_FULL_TRANSFER, HAL_MAX_DELAY);
|
||||
|
|
|
|||
|
|
@ -86,7 +86,6 @@ __attribute__((always_inline)) __STATIC_INLINE void __DSB() {
|
|||
#define FSMC_ADDRESS_SETUP_TIME 15 // AddressSetupTime
|
||||
#define FSMC_DATA_SETUP_TIME 15 // DataSetupTime
|
||||
|
||||
static uint8_t fsmcInit = 0;
|
||||
void TFT_FSMC::init() {
|
||||
uint8_t cs = FSMC_CS_PIN, rs = FSMC_RS_PIN;
|
||||
uint32_t controllerAddress;
|
||||
|
|
@ -99,8 +98,9 @@ void TFT_FSMC::init() {
|
|||
|
||||
struct fsmc_nor_psram_reg_map* fsmcPsramRegion;
|
||||
|
||||
static bool fsmcInit = false;
|
||||
if (fsmcInit) return;
|
||||
fsmcInit = 1;
|
||||
fsmcInit = true;
|
||||
|
||||
switch (cs) {
|
||||
case FSMC_CS_NE1: controllerAddress = (uint32_t)FSMC_NOR_PSRAM_REGION1; fsmcPsramRegion = FSMC_NOR_PSRAM1_BASE; break;
|
||||
|
|
|
|||
|
|
@ -107,19 +107,17 @@ void Canvas::addImage(int16_t x, int16_t y, MarlinImage image, uint16_t *colors)
|
|||
|
||||
if (color_mode == HIGHCOLOR) {
|
||||
// HIGHCOLOR - 16 bits per pixel
|
||||
int16_t line = y;
|
||||
for (int16_t i = 0; i < image_height; i++, line++) {
|
||||
if (WITHIN(line, startLine, endLine - 1)) {
|
||||
uint16_t *pixel = buffer + x + (line - startLine) * width;
|
||||
uint16_t cx = x;
|
||||
for (int16_t j = 0; j < image_width; j++, cx++) {
|
||||
if (WITHIN(cx, 0, width - 1)) {
|
||||
uint16_t color = ENDIAN_COLOR(*data);
|
||||
if (color == 0x0001) color = COLOR_BACKGROUND;
|
||||
*pixel = color;
|
||||
}
|
||||
pixel++;
|
||||
data++;
|
||||
uint16_t yc = y <= startLine ? 0 : (y - startLine) * width;
|
||||
for (int16_t i = 0; i < image_height && y < endLine; i++, y++) {
|
||||
if (y >= startLine) {
|
||||
uint16_t *pixel = buffer + x + yc;
|
||||
yc += width;
|
||||
int16_t cx = x;
|
||||
for (int16_t j = 0; j < image_width && cx < width; j++, cx++, pixel++, data++) {
|
||||
if (cx < 0) continue;
|
||||
uint16_t color = ENDIAN_COLOR(*data);
|
||||
if (color == 0x0001) color = COLOR_BACKGROUND;
|
||||
*pixel = color;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -214,63 +212,60 @@ void Canvas::addImage(int16_t x, int16_t y, uint8_t image_width, uint8_t image_h
|
|||
case GREYSCALE4: bitsPerPixel = 4; break;
|
||||
default: return;
|
||||
}
|
||||
const uint8_t obase = 8 - bitsPerPixel, mask = 0xFF >> obase, pixelsPerByte = 8 / bitsPerPixel;
|
||||
const uintptr_t span = (image_width + pixelsPerByte - 1) / pixelsPerByte;
|
||||
|
||||
uint8_t mask = 0xFF >> (8 - bitsPerPixel),
|
||||
pixelsPerByte = 8 / bitsPerPixel;
|
||||
colors--; // Color 1 is at index 0
|
||||
|
||||
colors--;
|
||||
|
||||
for (int16_t i = 0; i < image_height; i++) {
|
||||
const int16_t line = y + i;
|
||||
if (WITHIN(line, startLine, endLine - 1)) {
|
||||
uint16_t *pixel = buffer + x + (line - startLine) * width;
|
||||
uint8_t offset = 8 - bitsPerPixel;
|
||||
for (int16_t j = 0; j < image_width; j++) {
|
||||
if (offset > 8) {
|
||||
data++;
|
||||
offset = 8 - bitsPerPixel;
|
||||
uint16_t yc = y <= startLine ? 0 : (y - startLine) * width; // Multiple of width as y offset
|
||||
for (int16_t i = 0; i < image_height && y < endLine; i++, y++) { // Loop through image lines
|
||||
if (y >= startLine) { // Within the canvas?
|
||||
uint16_t *pixel = buffer + x + yc; // Pixel address of line at x pos
|
||||
yc += width; // + is faster than *
|
||||
int8_t offset = obase; // Bit offset of incoming pixel
|
||||
for (int16_t j = 0; j < image_width; j++, pixel++) { // Loop through image pixels
|
||||
if (offset < 0) { data++; offset = obase; } // Got all pixels in the byte? next byte.
|
||||
if (WITHIN(x + j, 0, width - 1)) { // Within the canvas?
|
||||
const uint8_t ci = ((*data) >> offset) & mask; // Shift the color index to low bits
|
||||
if (ci) *pixel = colors[ci]; // Draw a solid pixel with the indexed color
|
||||
}
|
||||
if (WITHIN(x + j, 0, width - 1)) {
|
||||
const uint8_t color = ((*data) >> offset) & mask;
|
||||
if (color) *pixel = *(colors + color);
|
||||
}
|
||||
pixel++;
|
||||
offset -= bitsPerPixel;
|
||||
offset -= bitsPerPixel; // Subtract bits used for the pixel
|
||||
}
|
||||
data++;
|
||||
data++; // New line, so new set of pixels
|
||||
}
|
||||
else
|
||||
data += (image_width + pixelsPerByte - 1) / pixelsPerByte;
|
||||
data += span; // Skip line outside the canvas
|
||||
}
|
||||
}
|
||||
|
||||
void Canvas::addRect(uint16_t x, uint16_t y, uint16_t rectangleWidth, uint16_t rectangleHeight, uint16_t color) {
|
||||
if (endLine < y || startLine > y + rectangleHeight) return;
|
||||
if (endLine < y || startLine > y + rectangleHeight) return; // Nothing to draw?
|
||||
|
||||
for (uint16_t i = 0; i < rectangleHeight; i++) {
|
||||
const uint16_t line = y + i;
|
||||
if (WITHIN(line, startLine, endLine - 1)) {
|
||||
uint16_t *pixel = buffer + x + (line - startLine) * width;
|
||||
if (i == 0 || i == rectangleHeight - 1) {
|
||||
for (uint16_t j = 0; j < rectangleWidth; j++) *pixel++ = color;
|
||||
uint16_t yc = y <= startLine ? 0 : (y - startLine) * width; // Multiple of width as y offset
|
||||
for (uint16_t i = 0; i < rectangleHeight && y < endLine; i++, y++) { // Loop over the rect height
|
||||
if (y >= startLine) { // Within the canvas?
|
||||
uint16_t *pixel = buffer + x + yc; // Pixel address of line at x pos
|
||||
yc += width; // + is faster than *
|
||||
if (i == 0 || i == rectangleHeight - 1) { // Top or bottom line?
|
||||
for (uint16_t j = 0; j < rectangleWidth; j++) *pixel++ = color; // Fill the width. (No transparency)
|
||||
}
|
||||
else {
|
||||
*pixel = color;
|
||||
pixel += rectangleWidth - 1;
|
||||
*pixel = color;
|
||||
pixel[0] = color; // Left line
|
||||
pixel[rectangleWidth - 1] = color; // Right line
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Canvas::addBar(uint16_t x, uint16_t y, uint16_t barWidth, uint16_t barHeight, uint16_t color) {
|
||||
if (endLine < y || startLine > y + barHeight) return;
|
||||
if (endLine < y || startLine > y + barHeight) return; // Nothing to draw?
|
||||
|
||||
for (uint16_t i = 0; i < barHeight; i++) {
|
||||
const uint16_t line = y + i;
|
||||
if (WITHIN(line, startLine, endLine - 1)) {
|
||||
uint16_t *pixel = buffer + x + (line - startLine) * width;
|
||||
for (uint16_t j = 0; j < barWidth; j++) *pixel++ = color;
|
||||
uint16_t yc = y <= startLine ? 0 : (y - startLine) * width; // Multiple of width as y offset
|
||||
for (uint16_t i = 0; i < barHeight && y < endLine; i++, y++) { // Loop over the bar height
|
||||
if (y >= startLine) { // Within the canvas?
|
||||
uint16_t *pixel = buffer + x + yc; // Pixel address of line at x pos
|
||||
yc += width; // + is faster than *
|
||||
for (uint16_t j = 0; j < barWidth; j++) *pixel++ = color; // Fill the width. (No transparency)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ class TFT {
|
|||
|
||||
static bool is_busy() { return io.isBusy(); }
|
||||
static void abort() { io.abort(); }
|
||||
static void write_multiple(uint16_t data, uint16_t count) { io.WriteMultipleDMA(data, count); }
|
||||
static void write_multiple(uint16_t data, uint16_t count) { io.writeMultipleDMA(data, count); }
|
||||
static void write_sequence(uint16_t *data, uint16_t count) { io.writeSequenceDMA(data, count); }
|
||||
static void set_window(uint16_t xMin, uint16_t yMin, uint16_t xMax, uint16_t yMax) { io.set_window(xMin, yMin, xMax, yMax); }
|
||||
|
||||
|
|
|
|||
|
|
@ -116,25 +116,29 @@ void TFT_Queue::canvas(queueTask_t *task) {
|
|||
case CANVAS_SET_BACKGROUND:
|
||||
tftCanvas.setBackground(((parametersCanvasBackground_t *)item)->color);
|
||||
break;
|
||||
case CANVAS_ADD_TEXT:
|
||||
tftCanvas.addText(((parametersCanvasText_t *)item)->x, ((parametersCanvasText_t *)item)->y, ((parametersCanvasText_t *)item)->color, (uint16_t*)(item + sizeof(parametersCanvasText_t)), ((parametersCanvasText_t *)item)->maxWidth);
|
||||
break;
|
||||
|
||||
case CANVAS_ADD_IMAGE:
|
||||
MarlinImage image;
|
||||
uint16_t *colors;
|
||||
case CANVAS_ADD_TEXT: {
|
||||
parametersCanvasText_t *p_text = (parametersCanvasText_t *)item;
|
||||
uint16_t *str = (uint16_t*)(item + sizeof(parametersCanvasText_t));
|
||||
tftCanvas.addText(p_text->x, p_text->y, p_text->color, str, p_text->maxWidth);
|
||||
} break;
|
||||
|
||||
image = ((parametersCanvasImage_t *)item)->image;
|
||||
colors = (uint16_t *)(item + sizeof(parametersCanvasImage_t));
|
||||
tftCanvas.addImage(((parametersCanvasImage_t *)item)->x, ((parametersCanvasImage_t *)item)->y, image, colors);
|
||||
break;
|
||||
case CANVAS_ADD_IMAGE: {
|
||||
parametersCanvasImage_t *p_img = (parametersCanvasImage_t *)item;
|
||||
MarlinImage image = p_img->image;
|
||||
uint16_t *colors = (uint16_t *)(item + sizeof(parametersCanvasImage_t));
|
||||
tftCanvas.addImage(p_img->x, p_img->y, image, colors);
|
||||
} break;
|
||||
|
||||
case CANVAS_ADD_BAR:
|
||||
tftCanvas.addBar(((parametersCanvasBar_t *)item)->x, ((parametersCanvasBar_t *)item)->y, ((parametersCanvasBar_t *)item)->width, ((parametersCanvasBar_t *)item)->height, ((parametersCanvasBar_t *)item)->color);
|
||||
break;
|
||||
case CANVAS_ADD_RECT:
|
||||
tftCanvas.addRect(((parametersCanvasRectangle_t *)item)->x, ((parametersCanvasRectangle_t *)item)->y, ((parametersCanvasRectangle_t *)item)->width, ((parametersCanvasRectangle_t *)item)->height, ((parametersCanvasRectangle_t *)item)->color);
|
||||
break;
|
||||
case CANVAS_ADD_BAR: {
|
||||
parametersCanvasBar_t *p_bar = (parametersCanvasBar_t *)item;
|
||||
tftCanvas.addBar(p_bar->x, p_bar->y, p_bar->width, p_bar->height, p_bar->color);
|
||||
} break;
|
||||
|
||||
case CANVAS_ADD_RECT: {
|
||||
parametersCanvasRectangle_t *p_rect = (parametersCanvasRectangle_t *)item;
|
||||
tftCanvas.addRect(p_rect->x, p_rect->y, p_rect->width, p_rect->height, p_rect->color);
|
||||
} break;
|
||||
}
|
||||
item = ((parametersCanvasBackground_t *)item)->nextParameter;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ public:
|
|||
// Non-blocking DMA-based IO used by TFT_COLOR_UI only
|
||||
// These functions start data transfer using DMA and do NOT wait for data transfer completion
|
||||
inline static void writeSequenceDMA(uint16_t *data, uint16_t count) { io.writeSequence_DMA(data, count); }
|
||||
inline static void WriteMultipleDMA(uint16_t color, uint16_t count) { io.writeMultiple_DMA(color, count); }
|
||||
inline static void writeMultipleDMA(uint16_t color, uint16_t count) { io.writeMultiple_DMA(color, count); }
|
||||
|
||||
// Non-blocking DMA-based IO with IRQ callback used by TFT_LVGL_UI only
|
||||
// This function starts data transfer using DMA and does NOT wait for data transfer completion
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue