I currently work with the u8g2 library. Everything works fine, but when I render a new frame the old content and the new content blend into each other (only the pixels that change between the two frame) instead of having a clear/crisp instant transition.
Is there something I need to tweak in the u8g2 library or can it be a limitation of my LCD display (cheap AliExpress display, with a ST7565R / STM32F030F4P6 driver). Or a limitation of my MCU, a Trinket M0. Maybe there's a more efficient constructor I could use?
I also measured time and parsing the JSON in my sketch below doesn't take even 1 millisecond. But just sending the buffer (u8g2.sendBuffer();
) takes 129ms. The whole render()
function takes 134ms.
I also tried to tweak the bus clock of the library but that didn't change a lot. I bumped it up from 1000000
(default) to 1500000
.
Here my sketch:
#include <Arduino.h>
#include <U8g2lib.h>
#include <SerialCommands.h>
#include <Base64.h>
#include <ArduinoJson.h>
const int SCREEN_WIDTH = 128;
const int SCREEN_HEIGHT = 64;
U8G2_ST7565_ERC12864_F_4W_SW_SPI u8g2(U8G2_R0,/* clock=*/ 2, /* data=*/ 1, /* cs=*/ 3, /* dc=*/ 0, /* reset=*/ 4);
char serial_command_buffer[2048];
SerialCommands serialCommands(&Serial, serial_command_buffer, sizeof(serial_command_buffer), "\n", " ");
String currentContent = "";
typedef struct font_map_entry { const char* name; const uint8_t* font_ref; } font_map_entry;
font_map_entry font_map[] = {
{ "impact11", u8g2_font_ImpactBits_tr },
{ "mono5x8", u8g2_font_5x8_tf },
{ "fur42", u8g2_font_fur42_tf }
};
int font_map_size = sizeof(font_map) / sizeof(struct font_map_entry);
void setup()
{
u8g2.begin();
u8g2.setBusClock(1500000);
u8g2.setContrast(0);
// Sort the array so that binary search can be used
qsort(font_map, font_map_size, sizeof(struct font_map_entry), font_entry_cmp);
// Add commands
serialCommands.SetDefaultHandler(commandUnrecognized);
serialCommands.AddCommand(new SerialCommand("set-content", commandSetContent));
Serial.begin(9600);
}
void loop()
{
serialCommands.ReadSerial();
}
void commandUnrecognized(SerialCommands* sender, const char* cmd)
{
serial_printf(sender->GetSerial(), "Unrecognized command [%s]\n", cmd);
}
void commandSetContent(SerialCommands* sender) {
char* base64ContentStr = sender->Next();
if (base64ContentStr == NULL) {
sender->GetSerial()->println("content_param_missing\n");
return;
}
int base64ContentStrLength = strlen(base64ContentStr);
int decodedLength = Base64.decodedLength(base64ContentStr, base64ContentStrLength);
char decodedString[decodedLength + 1];
Base64.decode(decodedString, base64ContentStr, base64ContentStrLength);
// Render display
render(sender, decodedString);
currentContent = base64ContentStr;
serial_printf(sender->GetSerial(), "successful\n\n", base64ContentStr);
}
void render(SerialCommands* sender, const char* content)
{
StaticJsonDocument<2048> doc;
DeserializationError error = deserializeJson(doc, content, strlen(content));
if (error) {
serial_printf(sender->GetSerial(), "deserialization_failed,reason:%s\n", error.c_str());
return;
}
JsonArray arr = doc.as<JsonArray>();
u8g2.clearBuffer();
unsigned long allStart = millis();
for (JsonVariant value : arr) {
unsigned long jsonStart = millis();
JsonObject root = value.as<JsonObject>();
unsigned long jsonEnd = millis();
Serial.printf("JSON parse array element: start->%d, end->%d, total->%d\n", jsonStart, jsonEnd, (jsonEnd-jsonStart));
const char* font = root["font"];
const char* posX = root["posX"];
const char* posY = root["posY"];
const char* text = root["text"];
if (text == NULL) { continue; }
if (posY == NULL) { posY = 0; }
if (posX == NULL) { posX = 0; }
const uint8_t* u8g2_font = find_font(font);
u8g2.setFont(u8g2_font);
int strWidth = u8g2.getStrWidth(text);
int strHeight = u8g2.getAscent();
int screenX;
int screenY;
if (strcmp(posX, "center") == 0) {
screenX = (SCREEN_WIDTH/2)-(strWidth/2);
} else if (strcmp(posX, "left") == 0) {
screenX = 0;
} else if (strcmp(posX, "right") == 0) {
screenX = SCREEN_WIDTH-strWidth;
} else {
screenX = atoi(posX);
if (screenX < 0) {
// Support negative placement
screenX += SCREEN_WIDTH-strWidth;
}
}
if (strcmp(posY, "top") == 0) {
screenY = u8g2.getAscent();
} else if (strcmp(posY, "center") == 0) {
screenY = (SCREEN_HEIGHT/2)+(strHeight/2);
} else if (strcmp(posY, "bottom") == 0) {
screenY = SCREEN_HEIGHT+u8g2.getDescent();
} else {
screenY = atoi(posY);
if (screenY < 0) {
// Support negative placement
screenY += SCREEN_HEIGHT;
} else {
screenY += strHeight;
}
}
u8g2.setDrawColor(1);
u8g2.drawStr(screenX,screenY,text);
}
unsigned long sendBufferStart = millis();
u8g2.sendBuffer();
unsigned long allStop = millis();
Serial.printf("Send buffer: start->%d, stop->%d, total->%d\n", sendBufferStart, allStop, (allStop-sendBufferStart));
Serial.printf("Complete drawing: start->%d, stop->%d, total->%d\n", allStart, allStop, (allStop-allStart));
}
const uint8_t* find_font(const char* input)
{
font_map_entry* result = (font_map_entry*) bsearch(&input, font_map, font_map_size, sizeof(struct font_map_entry), font_entry_cmp);
return (result != NULL) ? result->font_ref : u8g2_font_ncenB08_tr;
}
int font_entry_cmp(const void *v1, const void *v2)
{
const font_map_entry* entry1 = (const font_map_entry*)v1;
const font_map_entry* entry2 = (const font_map_entry*)v2;
return strcmp(entry1->name, entry2->name);
}