diff options
| author | JF <jf@codingfield.com> | 2020-01-26 12:37:10 (GMT) |
|---|---|---|
| committer | JF <jf@codingfield.com> | 2020-01-26 12:37:10 (GMT) |
| commit | 5fa4f5abe0b752bb2d990378e02d6424a1d1b661 (patch) | |
| tree | bc2e731c488573d678aec1d388a00f754b24fb02 /src/Components/Gfx/Gfx.cpp | |
| parent | eb7a1b3ac9cbacb74afb7fcd1d40c51a18c90060 (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.cpp | 102 |
1 files changed, 77 insertions, 25 deletions
diff --git a/src/Components/Gfx/Gfx.cpp b/src/Components/Gfx/Gfx.cpp index 9410651..2f64596 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; +} + |
