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:
parent
aabce8ed15
commit
a13312d9a9
14
clock.c
14
clock.c
|
|
@ -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() {
|
void clock() {
|
||||||
ifclock(clock_flag_10ms) {
|
ifclock(clock_flag_10ms) {
|
||||||
clock_10ms();
|
clock_10ms();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef DISPLAY
|
||||||
|
display_tick();
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef SIMULATOR
|
#ifdef SIMULATOR
|
||||||
sim_time_warp();
|
sim_time_warp();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
37
display.c
37
display.c
|
|
@ -9,12 +9,47 @@
|
||||||
|
|
||||||
#include "display.h"
|
#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
|
#define TEACUP_C_INCLUDE
|
||||||
#include "display_ssd1306.c"
|
#include "display_ssd1306.c"
|
||||||
#undef TEACUP_C_INCLUDE
|
#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) {
|
void display_writestr_P(PGM_P data_P) {
|
||||||
uint8_t r, i = 0;
|
uint8_t r, i = 0;
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,11 @@
|
||||||
#endif /* DISPLAY_BUS */
|
#endif /* DISPLAY_BUS */
|
||||||
|
|
||||||
|
|
||||||
|
#define DISPLAY_BUFFER_SIZE 128
|
||||||
|
|
||||||
|
|
||||||
void display_init(void);
|
void display_init(void);
|
||||||
|
void display_tick(void);
|
||||||
void display_clear(void);
|
void display_clear(void);
|
||||||
|
|
||||||
void display_clock(void);
|
void display_clock(void);
|
||||||
|
|
|
||||||
|
|
@ -116,12 +116,18 @@ void display_clock(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Prints a character at the current cursor position.
|
Forwards a character from the display queue to the I2C queue.
|
||||||
|
|
||||||
\param data The character to be displayed.
|
|
||||||
*/
|
*/
|
||||||
void display_writechar(uint8_t data) {
|
void display_tick() {
|
||||||
uint8_t i, index = data - 0x20;
|
uint8_t i, data, index;
|
||||||
|
|
||||||
|
if (displaybus_busy()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buf_canread(display)) {
|
||||||
|
buf_pop(display, data);
|
||||||
|
index = data - 0x20;
|
||||||
|
|
||||||
// Write pixels command.
|
// Write pixels command.
|
||||||
displaybus_write(0x40, 0);
|
displaybus_write(0x40, 0);
|
||||||
|
|
@ -136,12 +142,9 @@ void display_writechar(uint8_t data) {
|
||||||
}
|
}
|
||||||
// Send space between characters.
|
// Send space between characters.
|
||||||
for (i = 0; i < FONT_SYMBOL_SPACE; i++) {
|
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));
|
displaybus_write(0x00, (i == FONT_SYMBOL_SPACE - 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* TEACUP_C_INCLUDE && DISPLAY_TYPE_SSD1306 */
|
#endif /* TEACUP_C_INCLUDE && DISPLAY_TYPE_SSD1306 */
|
||||||
|
|
|
||||||
12
i2c.h
12
i2c.h
|
|
@ -65,11 +65,15 @@
|
||||||
|
|
||||||
Size of send buffer. MUST be a \f$2^n\f$ value, maximum is 512.
|
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
|
This buffer can be rather small, because there is another queue on the
|
||||||
speed operations up. An exhaused buffer doesn't mean data gets lost, writing
|
display level. Transmissions can be large, e.g. 514 bytes when clearing the
|
||||||
to the buffer then waits until sufficient previous data is sent.
|
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
|
#ifdef I2C_SLAVE_MODE
|
||||||
#define I2C_SLAVE_RX_BUFFER_SIZE 1
|
#define I2C_SLAVE_RX_BUFFER_SIZE 1
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue