aboutsummaryrefslogtreecommitdiffstats
path: root/src/Components/Gfx/Gfx.cpp
diff options
context:
space:
mode:
authorJF <jf@codingfield.com>2020-01-26 13:37:10 +0100
committerJF <jf@codingfield.com>2020-01-26 13:37:10 +0100
commit5fa4f5abe0b752bb2d990378e02d6424a1d1b661 (patch)
treebc2e731c488573d678aec1d388a00f754b24fb02 /src/Components/Gfx/Gfx.cpp
parenteb7a1b3ac9cbacb74afb7fcd1d40c51a18c90060 (diff)
Better integration of SPI with DMA and IRQ. Using only 'End' IRQ. Perf could be improved by using 'Started' IRQ to prepare the next buffer while the current one is beeing sent.
Diffstat (limited to 'src/Components/Gfx/Gfx.cpp')
-rw-r--r--src/Components/Gfx/Gfx.cpp102
1 files changed, 77 insertions, 25 deletions
diff --git a/src/Components/Gfx/Gfx.cpp b/src/Components/Gfx/Gfx.cpp
index 94106513..2f64596c 100644
--- a/src/Components/Gfx/Gfx.cpp
+++ b/src/Components/Gfx/Gfx.cpp
@@ -7,23 +7,33 @@ Gfx::Gfx(Pinetime::Drivers::St7789 &lcd) : lcd{lcd} {
}
void Gfx::Init() {
- lcd.Init();
+
}
void Gfx::ClearScreen() {
SetBackgroundColor(0x0000);
+
+ state.remainingIterations = 240 + 1;
+ state.currentIteration = 0;
+ state.busy = true;
+ state.action = Action::FillRectangle;
+
lcd.BeginDrawBuffer(0, 0, width, height);
- for(int i = 0; i < height; i++) {
- lcd.NextDrawBuffer(reinterpret_cast<const uint8_t *>(buffer), width * 2);
- }
- lcd.EndDrawBuffer();
+ lcd.NextDrawBuffer(reinterpret_cast<const uint8_t *>(buffer), width * 2);
+ while(state.busy) {} // TODO wait on an event/queue/... instead of polling
}
-void Gfx::FillRectangle(uint8_t x, uint8_t y, uint8_t width, uint8_t height, uint16_t color) {
+void Gfx::FillRectangle(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint16_t color) {
SetBackgroundColor(color);
- lcd.BeginDrawBuffer(0, 0, width, height);
- lcd.NextDrawBuffer(reinterpret_cast<const uint8_t *>(buffer), width * 2, 240);
- lcd.EndDrawBuffer();
+
+ state.remainingIterations = 240 + 1;
+ state.currentIteration = 0;
+ state.busy = true;
+ state.action = Action::FillRectangle;
+
+ lcd.BeginDrawBuffer(x, y, w, h);
+ lcd.NextDrawBuffer(reinterpret_cast<const uint8_t *>(buffer), width * 2);
+ while(state.busy) {} // TODO wait on an event/queue/... instead of polling
}
void Gfx::DrawString(uint8_t x, uint8_t y, uint16_t color, const char *text, const FONT_INFO *p_font, bool wrap) {
@@ -64,31 +74,37 @@ void Gfx::DrawString(uint8_t x, uint8_t y, uint16_t color, const char *text, con
void Gfx::DrawChar(const FONT_INFO *font, uint8_t c, uint8_t *x, uint8_t y, uint16_t color) {
uint8_t char_idx = c - font->startChar;
uint16_t bytes_in_line = CEIL_DIV(font->charInfo[char_idx].widthBits, 8);
+ uint16_t bg = 0x0000;
if (c == ' ') {
*x += font->height / 2;
return;
}
- // TODO For now, LCD and SPI driver start a new transfer (cs pin + set address windows + write byte) FOR EACH PIXEL!
- // This could be improved by setting CS pin, DC pin and address window ONLY ONCE for the whole character
-
- lcd.BeginDrawBuffer(*x, y, bytes_in_line*8, font->height);
- uint16_t bg = 0x0000;
- for (uint16_t i = 0; i < font->height; i++) {
- for (uint16_t j = 0; j < bytes_in_line; j++) {
- for (uint8_t k = 0; k < 8; k++) {
- if ((1 << (7 - k)) & font->data[font->charInfo[char_idx].offset + i * bytes_in_line + j]) {
- buffer[(j*8)+k] = color;
- }
- else {
- buffer[(j*8)+k] = bg;
- }
+ // Build first line
+ for (uint16_t j = 0; j < bytes_in_line; j++) {
+ for (uint8_t k = 0; k < 8; k++) {
+ if ((1 << (7 - k)) & font->data[font->charInfo[char_idx].offset + j]) {
+ buffer[(j*8)+k] = color;
+ }
+ else {
+ buffer[(j*8)+k] = bg;
}
}
- lcd.NextDrawBuffer(reinterpret_cast<uint8_t *>(&buffer), bytes_in_line*8*2);
}
- lcd.EndDrawBuffer();
+
+ state.remainingIterations = font->height + 0;
+ state.currentIteration = 0;
+ state.busy = true;
+ state.action = Action::DrawChar;
+ state.font = const_cast<FONT_INFO *>(font);
+ state.character = c;
+ state.color = color;
+
+ lcd.BeginDrawBuffer(*x, y, bytes_in_line*8, font->height);
+ lcd.NextDrawBuffer(reinterpret_cast<const uint8_t *>(&buffer), bytes_in_line*8*2);
+ while(state.busy) {} // TODO wait on an event/queue/... instead of polling
+
*x += font->charInfo[char_idx].widthBits + font->spacePixels;
}
@@ -110,4 +126,40 @@ void Gfx::SetBackgroundColor(uint16_t color) {
}
}
+bool Gfx::GetNextBuffer(uint8_t **data, size_t &size) {
+ if(!state.busy) return false;
+ state.remainingIterations--;
+ if (state.remainingIterations == 0) {
+ state.busy = false;
+ return false;
+ }
+
+ if(state.action == Action::FillRectangle) {
+ *data = reinterpret_cast<uint8_t *>(buffer);
+ size = width * 2;
+ } else if(state.action == Action::DrawChar) {
+ uint16_t bg = 0x0000;
+ uint8_t char_idx = state.character - state.font->startChar;
+ uint16_t bytes_in_line = CEIL_DIV(state.font->charInfo[char_idx].widthBits, 8);
+
+ for (uint16_t j = 0; j < bytes_in_line; j++) {
+ for (uint8_t k = 0; k < 8; k++) {
+ if ((1 << (7 - k)) & state.font->data[state.font->charInfo[char_idx].offset + ((state.currentIteration+1) * bytes_in_line) + j]) {
+ buffer[(j*8)+k] = state.color;
+ }
+ else {
+ buffer[(j*8)+k] = bg;
+ }
+ }
+ }
+
+ *data = reinterpret_cast<uint8_t *>(buffer);
+ size = bytes_in_line*8*2;
+ }
+
+ state.currentIteration++;
+
+ return true;
+}
+