nrf5/drivers: Moving oled ssd1306 driver over to new framebuffer layout. Moving some of the draw algorithms into the object in order to optimize the speed on writing data from the framebuffer.

This commit is contained in:
Glenn Ruben Bakke 2017-01-15 19:06:48 +01:00
parent 2b383b4ede
commit 4c06455105
3 changed files with 101 additions and 40 deletions

View File

@ -32,6 +32,8 @@
#include "hal_spi.h"
#include "hal_time.h"
#include "framebuffer.h"
#if MICROPY_PY_DISPLAY_OLED_SSD1306
static pin_obj_t * mp_cs_pin;
@ -146,14 +148,14 @@ void driver_ssd1306_init(NRF_SPI_Type * p_instance, pin_obj_t * p_cs_pin, pin_ob
static void set_col(uint16_t start_col, uint16_t end_col)
{
cmd_write(SET_COL_ADDR); /* Column Command address */
cmd_write(SET_COL_ADDR); // column command address
cmd_write(start_col & 0xFF );
cmd_write(end_col & 0xFF);
}
static void set_page(uint16_t start_page, uint16_t end_page)
{
cmd_write(SET_PAGE_ADDR); /* Column Command address */
cmd_write(SET_PAGE_ADDR); // page command address
cmd_write(start_page & 0xFF);
cmd_write(end_page & 0xFF);
}
@ -188,8 +190,19 @@ void driver_ssd1306_clear(uint16_t color)
mp_hal_pin_high(mp_cs_pin);
}
void driver_ssd1306_update_line(uint16_t line, fb_byte_t * p_bytes, uint16_t len, bool compressed) {
void driver_ssd1306_update_line(uint16_t line, framebuffer_byte_t * p_bytes, uint16_t len) {
set_col(line, line);
set_page(0, 63);
mp_hal_pin_high(mp_dc_pin);
mp_hal_pin_low(mp_cs_pin);
for (uint8_t i = 0; i < len; i++) {
uint8_t byte = (uint8_t)((uint8_t *)p_bytes)[i];
raw_write(byte);
}
mp_hal_pin_high(mp_cs_pin);
}
#endif

View File

@ -30,12 +30,12 @@
#include "py/mphal.h"
#include "hal_spi.h"
#include "lcd_mono_fb.h"
#include "framebuffer.h"
void driver_ssd1306_init(NRF_SPI_Type * p_instance, pin_obj_t * cs_pin, pin_obj_t * dc_pin, pin_obj_t * reset_pin);
void driver_ssd1306_clear(uint16_t color);
void driver_ssd1306_update_line(uint16_t line, fb_byte_t * p_bytes, uint16_t len, bool compressed);
void driver_ssd1306_update_line(uint16_t line, framebuffer_byte_t * p_bytes, uint16_t len);
#endif // OLED_SSD1306_DRIVER_H__

View File

@ -24,8 +24,6 @@
* THE SOFTWARE.
*/
#include <stdio.h>
#include "py/obj.h"
#include "py/runtime.h"
#include "py/mphal.h"
@ -38,27 +36,35 @@
/// \moduleref display
/// \class SSD1306 - SSD1306 TFT LCD display driver.
#include "moddisplay.h"
#include "framebuffer.h"
#include "pin.h"
#include "spi.h"
#include "lcd_mono_fb.h"
typedef struct _oled_ssd1306_obj_t {
mp_obj_base_t base;
display_draw_callbacks_t draw_callbacks;
framebuffer_t * framebuffer;
machine_hard_spi_obj_t *spi;
pin_obj_t * pin_cs;
pin_obj_t * pin_dc;
pin_obj_t * pin_reset;
mp_obj_framebuf_t * framebuffer;
} oled_ssd1306_obj_t;
static void dirty_line_update_cb(mp_obj_framebuf_t * p_framebuffer,
uint16_t line,
fb_byte_t * p_new,
fb_byte_t * p_old) {
// the lcd does not have double buffer needs, skip it.
(void)p_old;
#define OLED_SSD1306_COLOR_BLACK 0
#define OLED_SSD1306_COLOR_WHITE 1
driver_ssd1306_update_line(line, p_new, p_framebuffer->bytes_stride, true);
static void set_pixel(void * p_display,
uint16_t x,
uint16_t y,
uint16_t color) {
oled_ssd1306_obj_t *self = (oled_ssd1306_obj_t *)p_display;
if (color == OLED_SSD1306_COLOR_BLACK) {
framebuffer_pixel_clear(self->framebuffer, x, y);
} else {
framebuffer_pixel_set(self->framebuffer, x, y);
}
}
/// \method __str__()
@ -83,9 +89,12 @@ STATIC void oled_ssd1306_print(const mp_print_t *print, mp_obj_t o, mp_print_kin
self->pin_reset->port,
self->pin_reset->pin);
mp_printf(print, " FB(width=%u, height=%u, dir=%u))\n",
self->framebuffer->width,
self->framebuffer->height);
mp_printf(print, " FB(width=%u, height=%u, dir=%u, fb_stride=%u, fb_dirty_stride=%u))\n",
self->framebuffer->screen_width,
self->framebuffer->screen_height,
self->framebuffer->line_orientation,
self->framebuffer->fb_stride,
self->framebuffer->fb_dirty_stride);
}
// for make_new
@ -100,6 +109,18 @@ enum {
/*
Example for nrf51822 / pca10028:
from machine import Pin, SPI
from display import SSD1306
cs = Pin("A14", mode=Pin.OUT, pull=Pin.PULL_UP)
reset = Pin("A13", mode=Pin.OUT, pull=Pin.PULL_UP)
dc = Pin("A12", mode=Pin.OUT, pull=Pin.PULL_UP)
spi = SPI(0, baudrate=8000000)
d = SSD1306(128, 64, spi, cs, dc, reset)
d.text("Hello World!", 32, 32)
d.show()
Example for nrf52832 / pca10040:
from machine import Pin, SPI
@ -107,7 +128,7 @@ from display import SSD1306
cs = Pin("A13", mode=Pin.OUT, pull=Pin.PULL_UP)
reset = Pin("A12", mode=Pin.OUT, pull=Pin.PULL_UP)
dc = Pin("A11", mode=Pin.OUT, pull=Pin.PULL_UP)
spi = SPI(0, baudrate=4000000)
spi = SPI(0, baudrate=8000000)
d = SSD1306(128, 64, spi, cs, dc, reset)
d.text("Hello World!", 32, 32)
d.show()
@ -141,6 +162,7 @@ STATIC mp_obj_t oled_ssd1306_make_new(const mp_obj_type_t *type, size_t n_args,
oled_ssd1306_obj_t *s = m_new_obj_with_finaliser(oled_ssd1306_obj_t);
s->base.type = type;
s->draw_callbacks.pixel_set = set_pixel;
mp_int_t width;
mp_int_t height;
@ -187,15 +209,22 @@ STATIC mp_obj_t oled_ssd1306_make_new(const mp_obj_type_t *type, size_t n_args,
"Display Reset Pin not set"));
}
// direction arg not yet configurable
mp_int_t vertical = true;
s->framebuffer = lcd_mono_fb_helper_make_new(width, height, vertical);
framebuffer_init_t init_conf = {
.width = width,
.height = height,
.line_orientation = FRAMEBUFFER_LINE_DIR_VERTICAL,
.double_buffer = false
};
s->framebuffer = m_new(framebuffer_t, sizeof(framebuffer_t));
framebuffer_init(s->framebuffer, &init_conf);
driver_ssd1306_init(s->spi->pyb->spi->instance, s->pin_cs, s->pin_dc, s->pin_reset);
// Default to black background
driver_ssd1306_clear(0);
// display_clear_screen(s->framebuffer, 0x0);
framebuffer_clear(s->framebuffer);
return MP_OBJ_FROM_PTR(s);
}
@ -207,20 +236,40 @@ STATIC mp_obj_t oled_ssd1306_make_new(const mp_obj_type_t *type, size_t n_args,
STATIC mp_obj_t oled_ssd1306_fill(mp_obj_t self_in, mp_obj_t color) {
oled_ssd1306_obj_t *self = MP_OBJ_TO_PTR(self_in);
driver_ssd1306_clear((uint8_t)mp_obj_get_int(color));
display_clear_screen(self->framebuffer, (uint8_t)mp_obj_get_int(color));
if (color == MP_OBJ_NEW_SMALL_INT(OLED_SSD1306_COLOR_BLACK)) {
framebuffer_clear(self->framebuffer);
} else {
framebuffer_fill(self->framebuffer);
}
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(oled_ssd1306_fill_obj, oled_ssd1306_fill);
static void render(framebuffer_t * p_framebuffer) {
for (uint16_t i = 0; i < p_framebuffer->fb_dirty_stride; i++) {
if (p_framebuffer->fb_dirty[i].byte != 0) {
for (uint16_t b = 0; b < 8; b++) {
if ((((p_framebuffer->fb_dirty[i].byte >> b) & 0x01) == 1)) {
uint16_t line_num = (i * 8) + b;
driver_ssd1306_update_line(line_num,
&p_framebuffer->fb_new[line_num * p_framebuffer->fb_stride],
p_framebuffer->fb_stride);
}
}
p_framebuffer->fb_dirty[i].byte = 0x00;
}
}
}
/// \method show()
/// Display content in framebuffer.
STATIC mp_obj_t oled_ssd1306_show(size_t n_args, const mp_obj_t *args) {
oled_ssd1306_obj_t *self = MP_OBJ_TO_PTR(args[0]);
display_update(self->framebuffer, false, dirty_line_update_cb);
render(self->framebuffer);
framebuffer_flip(self->framebuffer);
return mp_const_none;
}
@ -250,18 +299,13 @@ STATIC mp_obj_t oled_ssd1306_pixel(size_t n_args, const mp_obj_t *args) {
oled_ssd1306_obj_t *self = MP_OBJ_TO_PTR(args[0]);
mp_int_t x = mp_obj_get_int(args[1]);
mp_int_t y = mp_obj_get_int(args[2]);
mp_int_t color;
if (n_args >= 3) {
color = mp_obj_get_int(args[3]);
}
(void)self;
(void)x;
(void)y;
(void)color;
mp_int_t color = mp_obj_get_int(args[3]);
set_pixel(self, x, y, color);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(oled_ssd1306_pixel_obj, 3, 4, oled_ssd1306_pixel);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(oled_ssd1306_pixel_obj, 4, 4, oled_ssd1306_pixel);
/// \method pixel(text, x, y, [color])
/// Write one pixel in framebuffer.
@ -278,8 +322,12 @@ STATIC mp_obj_t oled_ssd1306_text(size_t n_args, const mp_obj_t *args) {
color = mp_obj_get_int(args[3]);
}
display_print_string(self->framebuffer, x, y, str);
//display_print_string(self->framebuffer, x, y, str);
(void)x;
(void)y;
(void)self;
(void)str;
(void)color;
return mp_const_none;
@ -304,8 +352,8 @@ STATIC const mp_map_elem_t oled_ssd1306_locals_dict_table[] = {
#if 0
{ MP_OBJ_NEW_QSTR(MP_QSTR_bitmap), (mp_obj_t)(&oled_ssd1306_bitmap_obj) },
#endif
{ MP_OBJ_NEW_QSTR(MP_QSTR_COLOR_BLACK), MP_OBJ_NEW_SMALL_INT(LCD_BLACK) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_COLOR_WHITE), MP_OBJ_NEW_SMALL_INT(LCD_WHITE) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_COLOR_BLACK), MP_OBJ_NEW_SMALL_INT(OLED_SSD1306_COLOR_BLACK) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_COLOR_WHITE), MP_OBJ_NEW_SMALL_INT(OLED_SSD1306_COLOR_WHITE) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_VERTICAL), MP_OBJ_NEW_SMALL_INT(0) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_HORIZONTAL), MP_OBJ_NEW_SMALL_INT(1) },
};