Display: introduce display queue.

Now we shouldn't experience wait cycles in i2c_write() during
typical display writes any longer. It should also distribute CPU
load of display writes a lot better.

Previously writing a line of text to the display would take
almost as long as it took to actually send it to the display,
because the I2C queue could hold only one transmission, which
effectively meant only one character. This could hold the main
loop for several milliseconds.

Now we queue characters, send them one by one, and return to the
main loop in between.

This costs 160 bytes program memory. Only 18 bytes RAM, because
the I2C queue was reduced accordingly. Now:

  Program:  24456 bytes
     Data:   1543 bytes
   EEPROM:     32 bytes
This commit is contained in:
Markus Hitter 2016-04-26 18:52:14 +02:00
parent aabce8ed15
commit a13312d9a9
5 changed files with 83 additions and 31 deletions

14
clock.c
View File

@ -127,17 +127,23 @@ static void clock_10ms(void) {
}
}
/*! do reoccuring stuff
/**
Do reoccuring stuff. Call it occasionally in busy loops.
call it occasionally in busy loops
Other than clock_tick() above, which is called at a constant interval, this
is called from the main loop. So it can be called very often on an idle
printer, but rather rarely on one running full speed.
*/
void clock() {
ifclock(clock_flag_10ms) {
clock_10ms();
}
#ifdef DISPLAY
display_tick();
#endif
#ifdef SIMULATOR
sim_time_warp();
#endif
}

View File

@ -9,12 +9,47 @@
#include "display.h"
#ifdef DISPLAY
// Ringbuffer logic for buffer 'display'.
#define BUFSIZE DISPLAY_BUFFER_SIZE
volatile uint8_t displayhead = 0;
volatile uint8_t displaytail = 0;
volatile uint8_t displaybuf[BUFSIZE];
#include "ringbuffer.h"
#define TEACUP_C_INCLUDE
#include "display_ssd1306.c"
#undef TEACUP_C_INCLUDE
#ifdef DISPLAY
#include "delay.h"
/**
Prints a character at the current cursor position.
\param data The character to be displayed.
This code is identical for all display buses and display types, because it
just queues up the character.
In case the buffer is full already it waits for a millisecond to allow
data to be sent to the display, then it tries again. If it still fails then,
it drops the character. This way we're fairly protected against data loss,
still we guarantee to not hang forever.
*/
void display_writechar(uint8_t data) {
if ( ! buf_canwrite(display)) {
delay_ms(1);
}
if (buf_canwrite(display)) {
buf_push(display, data);
}
}
void display_writestr_P(PGM_P data_P) {
uint8_t r, i = 0;

View File

@ -32,7 +32,11 @@
#endif /* DISPLAY_BUS */
#define DISPLAY_BUFFER_SIZE 128
void display_init(void);
void display_tick(void);
void display_clear(void);
void display_clock(void);

View File

@ -116,12 +116,18 @@ void display_clock(void) {
}
/**
Prints a character at the current cursor position.
\param data The character to be displayed.
Forwards a character from the display queue to the I2C queue.
*/
void display_writechar(uint8_t data) {
uint8_t i, index = data - 0x20;
void display_tick() {
uint8_t i, data, index;
if (displaybus_busy()) {
return;
}
if (buf_canread(display)) {
buf_pop(display, data);
index = data - 0x20;
// Write pixels command.
displaybus_write(0x40, 0);
@ -136,12 +142,9 @@ void display_writechar(uint8_t data) {
}
// Send space between characters.
for (i = 0; i < FONT_SYMBOL_SPACE; i++) {
// TODO: we finalise a I2C (or other) bus message after each character
// here because we have no idea on how many more are following. This
// is highly inefficient and makes the displaybus buffer almost
// pointless.
displaybus_write(0x00, (i == FONT_SYMBOL_SPACE - 1));
}
}
}
#endif /* TEACUP_C_INCLUDE && DISPLAY_TYPE_SSD1306 */

12
i2c.h
View File

@ -65,11 +65,15 @@
Size of send buffer. MUST be a \f$2^n\f$ value, maximum is 512.
A larger buffer allows to store more display data immediately, so it can
speed operations up. An exhaused buffer doesn't mean data gets lost, writing
to the buffer then waits until sufficient previous data is sent.
This buffer can be rather small, because there is another queue on the
display level. Transmissions can be large, e.g. 514 bytes when clearing the
display, but typically it's only some 3 to 10 bytes ( = sending one
character).
An exhausted buffer doesn't mean data loss, writing to the buffer then waits
until sufficient previous data is sent.
*/
#define I2C_BUFFER_SIZE 128
#define I2C_BUFFER_SIZE 16
#ifdef I2C_SLAVE_MODE
#define I2C_SLAVE_RX_BUFFER_SIZE 1