diff --git a/Marlin/src/HAL/STM32/tft/tft_fsmc.cpp b/Marlin/src/HAL/STM32/tft/tft_fsmc.cpp index bb011ec6f4..faf7d2b048 100644 --- a/Marlin/src/HAL/STM32/tft/tft_fsmc.cpp +++ b/Marlin/src/HAL/STM32/tft/tft_fsmc.cpp @@ -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); diff --git a/Marlin/src/HAL/STM32F1/tft/tft_fsmc.cpp b/Marlin/src/HAL/STM32F1/tft/tft_fsmc.cpp index 51f70b9365..73b0e7efb9 100644 --- a/Marlin/src/HAL/STM32F1/tft/tft_fsmc.cpp +++ b/Marlin/src/HAL/STM32F1/tft/tft_fsmc.cpp @@ -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; diff --git a/Marlin/src/lcd/tft/canvas.cpp b/Marlin/src/lcd/tft/canvas.cpp index d10ca626ec..68b6f2eea8 100644 --- a/Marlin/src/lcd/tft/canvas.cpp +++ b/Marlin/src/lcd/tft/canvas.cpp @@ -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) } } } diff --git a/Marlin/src/lcd/tft/tft.h b/Marlin/src/lcd/tft/tft.h index 94dd547844..5781115086 100644 --- a/Marlin/src/lcd/tft/tft.h +++ b/Marlin/src/lcd/tft/tft.h @@ -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); } diff --git a/Marlin/src/lcd/tft/tft_queue.cpp b/Marlin/src/lcd/tft/tft_queue.cpp index 06de651287..6599fdd197 100644 --- a/Marlin/src/lcd/tft/tft_queue.cpp +++ b/Marlin/src/lcd/tft/tft_queue.cpp @@ -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; } diff --git a/Marlin/src/lcd/tft_io/tft_io.h b/Marlin/src/lcd/tft_io/tft_io.h index efbd79b7c1..73214baacf 100644 --- a/Marlin/src/lcd/tft_io/tft_io.h +++ b/Marlin/src/lcd/tft_io/tft_io.h @@ -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