summaryrefslogtreecommitdiffstats
path: root/drivers/oled
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/oled')
-rw-r--r--drivers/oled/oled_driver.h4
-rw-r--r--drivers/oled/ssd1306_sh1106.c91
2 files changed, 49 insertions, 46 deletions
diff --git a/drivers/oled/oled_driver.h b/drivers/oled/oled_driver.h
index e9b8c5b4e8..291049e36b 100644
--- a/drivers/oled/oled_driver.h
+++ b/drivers/oled/oled_driver.h
@@ -170,6 +170,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
# define OLED_UPDATE_INTERVAL 50
#endif
+#if !defined(OLED_UPDATE_PROCESS_LIMIT)
+# define OLED_UPDATE_PROCESS_LIMIT 1
+#endif
+
typedef struct __attribute__((__packed__)) {
uint8_t *current_element;
uint16_t remaining_element_count;
diff --git a/drivers/oled/ssd1306_sh1106.c b/drivers/oled/ssd1306_sh1106.c
index 30cfeb5648..342920572e 100644
--- a/drivers/oled/ssd1306_sh1106.c
+++ b/drivers/oled/ssd1306_sh1106.c
@@ -291,65 +291,64 @@ static void rotate_90(const uint8_t *src, uint8_t *dest) {
}
void oled_render(void) {
- if (!oled_initialized) {
- return;
- }
-
// Do we have work to do?
oled_dirty &= OLED_ALL_BLOCKS_MASK;
- if (!oled_dirty || oled_scrolling) {
+ if (!oled_dirty || !oled_initialized || oled_scrolling) {
return;
}
- // Find first dirty block
- uint8_t update_start = 0;
- while (!(oled_dirty & ((OLED_BLOCK_TYPE)1 << update_start))) {
- ++update_start;
- }
-
- // Set column & page position
- static uint8_t display_start[] = {I2C_CMD, COLUMN_ADDR, 0, OLED_DISPLAY_WIDTH - 1, PAGE_ADDR, 0, OLED_DISPLAY_HEIGHT / 8 - 1};
- if (!HAS_FLAGS(oled_rotation, OLED_ROTATION_90)) {
- calc_bounds(update_start, &display_start[1]); // Offset from I2C_CMD byte at the start
- } else {
- calc_bounds_90(update_start, &display_start[1]); // Offset from I2C_CMD byte at the start
- }
-
- // Send column & page position
- if (I2C_TRANSMIT(display_start) != I2C_STATUS_SUCCESS) {
- print("oled_render offset command failed\n");
- return;
- }
+ // Turn on display if it is off
+ oled_on();
- if (!HAS_FLAGS(oled_rotation, OLED_ROTATION_90)) {
- // Send render data chunk as is
- if (I2C_WRITE_REG(I2C_DATA, &oled_buffer[OLED_BLOCK_SIZE * update_start], OLED_BLOCK_SIZE) != I2C_STATUS_SUCCESS) {
- print("oled_render data failed\n");
- return;
+ uint8_t update_start = 0;
+ uint8_t num_processed = 0;
+ while (oled_dirty && num_processed++ < OLED_UPDATE_PROCESS_LIMIT) { // render all dirty blocks (up to the configured limit)
+ // Find next dirty block
+ while (!(oled_dirty & ((OLED_BLOCK_TYPE)1 << update_start))) {
+ ++update_start;
}
- } else {
- // Rotate the render chunks
- const static uint8_t source_map[] = OLED_SOURCE_MAP;
- const static uint8_t target_map[] = OLED_TARGET_MAP;
-
- static uint8_t temp_buffer[OLED_BLOCK_SIZE];
- memset(temp_buffer, 0, sizeof(temp_buffer));
- for (uint8_t i = 0; i < sizeof(source_map); ++i) {
- rotate_90(&oled_buffer[OLED_BLOCK_SIZE * update_start + source_map[i]], &temp_buffer[target_map[i]]);
+
+ // Set column & page position
+ static uint8_t display_start[] = {I2C_CMD, COLUMN_ADDR, 0, OLED_DISPLAY_WIDTH - 1, PAGE_ADDR, 0, OLED_DISPLAY_HEIGHT / 8 - 1};
+ if (!HAS_FLAGS(oled_rotation, OLED_ROTATION_90)) {
+ calc_bounds(update_start, &display_start[1]); // Offset from I2C_CMD byte at the start
+ } else {
+ calc_bounds_90(update_start, &display_start[1]); // Offset from I2C_CMD byte at the start
}
- // Send render data chunk after rotating
- if (I2C_WRITE_REG(I2C_DATA, &temp_buffer[0], OLED_BLOCK_SIZE) != I2C_STATUS_SUCCESS) {
- print("oled_render90 data failed\n");
+ // Send column & page position
+ if (I2C_TRANSMIT(display_start) != I2C_STATUS_SUCCESS) {
+ print("oled_render offset command failed\n");
return;
}
- }
- // Turn on display if it is off
- oled_on();
+ if (!HAS_FLAGS(oled_rotation, OLED_ROTATION_90)) {
+ // Send render data chunk as is
+ if (I2C_WRITE_REG(I2C_DATA, &oled_buffer[OLED_BLOCK_SIZE * update_start], OLED_BLOCK_SIZE) != I2C_STATUS_SUCCESS) {
+ print("oled_render data failed\n");
+ return;
+ }
+ } else {
+ // Rotate the render chunks
+ const static uint8_t source_map[] = OLED_SOURCE_MAP;
+ const static uint8_t target_map[] = OLED_TARGET_MAP;
+
+ static uint8_t temp_buffer[OLED_BLOCK_SIZE];
+ memset(temp_buffer, 0, sizeof(temp_buffer));
+ for (uint8_t i = 0; i < sizeof(source_map); ++i) {
+ rotate_90(&oled_buffer[OLED_BLOCK_SIZE * update_start + source_map[i]], &temp_buffer[target_map[i]]);
+ }
- // Clear dirty flag
- oled_dirty &= ~((OLED_BLOCK_TYPE)1 << update_start);
+ // Send render data chunk after rotating
+ if (I2C_WRITE_REG(I2C_DATA, &temp_buffer[0], OLED_BLOCK_SIZE) != I2C_STATUS_SUCCESS) {
+ print("oled_render90 data failed\n");
+ return;
+ }
+ }
+
+ // Clear dirty flag of just rendered block
+ oled_dirty &= ~((OLED_BLOCK_TYPE)1 << update_start);
+ }
}
void oled_set_cursor(uint8_t col, uint8_t line) {