If anyone is curious, I went ahead and combined every suggestion given. I created a label object that would only update characters if they had changed. Otherwise it would feed through a similar version of the "DrawFontChar" function which ended immediately after the cursor would be updated. Then I would draw a black character in it's place and redraw the new character. This was much better than redrawing the entire string (pretty obvious I think) but I still was not completely satisfied with this.
I went ahead and modified the drawFontBits function to take a buffer and the width of the buffer. I also redefined the #define that prevented the function from drawing individual pixels. Instead it would write to individual locations of memory within the buffer. After the drawFontBits was done filling the buffer (this could be as slow as it wants to for all I care) I sent the entire character over in one DMA. Using this the only "flicker" I notice is the flicker of the character itself changing. No more period of a completely black background.
Because I feel bad rubbing my DMA peripheral in everyones face I went ahead and switched it to using the FIFO to see how the performance was. As expected it was slower, though not by much. I think it would be perfectly acceptable to use this solution without a DMA controller. Although this solution is also using a 6.4k RAM buffer (80*80*2)
Here are changes I made to the code to facilitate this. As I said before I'm working on a pure C architecture so the code is slightly different from the official C++ source. Though the relevant lines should be completely agnostic, as well as easily portable.
The math below looks largely..well wrong. But it works perfectly fine for my applications. I'd be very interested to see if someone can come up with a "proper" form.
I also have yet to figure out the exact issue but this only works up on fonts up to 40 pt on my controller. It may be I'm running out of memory, or it's possible I'm running into a DMA limitation on the amount of bytes being sent.
https://gist.github.com/gregslomin/2c29d3e4ee6b65ad744d
If you wish to make the modifications yourself - I believe these are the steps I took
1. Add the buffer and buffer width parameter to "DrawFontBits"
Code:
void drawFontBits(Adafruit_ILI9340 *display, uint32_t bits, uint32_t numbits,
uint32_t x, uint32_t y, uint32_t repeat, uint16_t *buffer, uint16_t width)
2. Change the #defines in "DrawFontBits" so the first loop is defined and the second is not
3. Replace the "drawPixel" call with a write to the buffer passed into the function
Code:
#if 1 (Step 2)
do {
n--;
if (bits & (1 << n)) {
buffer[y*width+x1] = fontColor; (Step 3)
//drawPixel(display, x1, y, fontColor);
//Serial.printf(" pixel at %d,%d\n", x1, y);
}
x1++;
}while (n > 0);
#endif
#if 0 (Step 2)
4. Modify the "DrawFontChar" function where it calls "DrawFontBits" replacing the uint32_t y = origin_y with the line below.
5. Modify the "DrawFontBits" function call - removing "origin_x" as well as adding the buffer and width parameters
6. Set the drawing window as shown below
7. Send all bytes over SPI using your preferred method
Code:
int32_t y = 5+font->cap_height - height - yoffset;;//origin_y; (Step 4)
while (linecount) {
...snip...
uint32_t bits = fetchbits_unsigned(data, bitoffset, xsize);
if((x+xoffset) >= 0)
drawFontBits(display, bits, xsize, x+xoffset, y-1, n, (uint16_t*)buffer, display->cursor_x-oldX+1); (Step 5)
... more snip ...
} else {
...snip...
uint32_t bits = fetchbits_unsigned(data, bitoffset, xsize);
if((x+xoffset) >= 0)
drawFontBits(display, bits, xsize, x+xoffset, y-1, n, (uint16_t*)buffer, display->cursor_x-oldX+1); (Step 5)
... more snip ...
} while (x < width);
y += n;
linecount -= n;
}
}
// Set Display window to equal size of font character
setAddrWindow(display, oldX, oldY-5, display->cursor_x, origin_y+font->cap_height);
// enable DC
SET_BIT(display->dcPort, display->dc); (Step 6)
// Send all bytes over SPI
sspSend(LPC_SSP0, buffer, (delta+1)*(font->cap_height+6)*2; (Step 7)
// Disable DC
CLEAR_BIT(display->dcPort, display->dc);
Missed a step
Step 8. Add the following to the top of the "DrawFontChar" function
Code:
int oldX = display->cursor_x;
int oldY = display->cursor_y;
or more likely
int oldX = this->cursor_x;
int oldY = this->cursor_y;
Edit: Kerning fixed