diff --git a/drivers/gdisp/SSD1306/SSD1306.h b/drivers/gdisp/SSD1306/SSD1306.h index d1c59fe44464..7d7010e8b2c3 100644 --- a/drivers/gdisp/SSD1306/SSD1306.h +++ b/drivers/gdisp/SSD1306/SSD1306.h @@ -33,10 +33,11 @@ #define SSD1306_HV_PAGE_ADDRESS 0x22 #define SSD1306_PAM_PAGE_START 0xB0 -#define SSD1306_COMSCANINC 0xC0 -#define SSD1306_COMSCANDEC 0xC8 +#define SSD1306_ROWSCANINC 0xC0 +#define SSD1306_ROWSCANDEC 0xC8 -#define SSD1306_SEGREMAP 0xA0 +#define SSD1306_COLSCANINC 0xA0 +#define SSD1306_COLSCANDEC 0xA1 #define SSD1306_CHARGEPUMP 0x8D diff --git a/drivers/gdisp/SSD1306/gdisp_lld_SSD1306.c b/drivers/gdisp/SSD1306/gdisp_lld_SSD1306.c index 2386c2d4d6de..a13b82a84955 100644 --- a/drivers/gdisp/SSD1306/gdisp_lld_SSD1306.c +++ b/drivers/gdisp/SSD1306/gdisp_lld_SSD1306.c @@ -105,8 +105,8 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { write_cmd(g, SSD1306_SETSTARTLINE | 0); write_cmd2(g, SSD1306_ENABLE_CHARGE_PUMP, 0x14); write_cmd2(g, SSD1306_MEMORYMODE, 0); - write_cmd(g, SSD1306_SEGREMAP+1); - write_cmd(g, SSD1306_COMSCANDEC); + write_cmd(g, SSD1306_COLSCANDEC); + write_cmd(g, SSD1306_ROWSCANDEC); #if GDISP_SCREEN_HEIGHT == 64 write_cmd2(g, SSD1306_SETCOMPINS, 0x12); #else @@ -159,35 +159,60 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { #if GDISP_HARDWARE_CLEARS LLDSPEC void gdisp_lld_clear(GDisplay *g) { - uint8_t fill = (g->p.color == Black) ? 0 : 0xff; + uint8_t fill = (gdispColor2Native(g->p.color) == Black) ? 0 : 0xff; int bytes = GDISP_SCREEN_WIDTH * GDISP_SCREEN_HEIGHT/8; memset(RAM(g), fill, bytes); g->flags |= GDISP_FLG_NEEDFLUSH; } #endif +#if GDISP_HARDWARE_FILLS + LLDSPEC void gdisp_lld_fill_area(GDisplay *g) { + coord_t sy = g->p.y; + coord_t ey = sy + g->p.cy - 1; + coord_t sx = g->p.x; + coord_t ex = g->p.x + g->p.cx - 1; + if (g->g.Orientation == GDISP_ROTATE_90 || g->g.Orientation == GDISP_ROTATE_270) { + coord_t tmp; + tmp = sx; sx = sy; sy = tmp; + tmp = ex; ex = ey; ey = tmp; + } + unsigned spage = sy / 8; + uint8_t * base = RAM(g) + GDISP_SCREEN_WIDTH * spage; + uint8_t mask = 0xff << (sy&7); + unsigned zpages = (ey / 8) - spage; + coord_t col; + if (gdispColor2Native(g->p.color)==Black) { + while (zpages--) { + for (col = sx; col <= ex; col++) + base[col] &= ~mask; + mask = 0xff; + base += GDISP_SCREEN_WIDTH; + } + mask &= (0xff >> (7 - (ey&7))); + for (col = sx; col <= ex; col++) + base[col] &= ~mask; + } else { + while (zpages--) { + for (col = sx; col <= ex; col++) + base[col] |= mask; + mask = 0xff; + base += GDISP_SCREEN_WIDTH; + } + mask &= (0xff >> (7 - (ey&7))); + for (col = sx; col <= ex; col++) + base[col] |= mask; + } + } +#endif + #if GDISP_HARDWARE_DRAWPIXEL LLDSPEC void gdisp_lld_draw_pixel(GDisplay *g) { - coord_t x, y; - - switch(g->g.Orientation) { - default: - case GDISP_ROTATE_0: - x = g->p.x; - y = g->p.y; - break; - case GDISP_ROTATE_90: - x = g->p.y; - y = GDISP_SCREEN_HEIGHT-1 - g->p.x; - break; - case GDISP_ROTATE_180: - x = GDISP_SCREEN_WIDTH-1 - g->p.x; - y = GDISP_SCREEN_HEIGHT-1 - g->p.y; - break; - case GDISP_ROTATE_270: - x = GDISP_SCREEN_WIDTH-1 - g->p.y; - y = g->p.x; - break; + coord_t x = g->p.x; + coord_t y = g->p.y; + if (g->g.Orientation == GDISP_ROTATE_90 || g->g.Orientation == GDISP_ROTATE_270) { + coord_t tmp; + tmp = x; x = y; y = tmp; } if (gdispColor2Native(g->p.color) != Black) RAM(g)[xyaddr(x, y)] |= xybit(y); @@ -199,26 +224,11 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { #if GDISP_HARDWARE_PIXELREAD LLDSPEC color_t gdisp_lld_get_pixel_color(GDisplay *g) { - coord_t x, y; - - switch(g->g.Orientation) { - default: - case GDISP_ROTATE_0: - x = g->p.x; - y = g->p.y; - break; - case GDISP_ROTATE_90: - x = g->p.y; - y = GDISP_SCREEN_HEIGHT-1 - g->p.x; - break; - case GDISP_ROTATE_180: - x = GDISP_SCREEN_WIDTH-1 - g->p.x; - y = GDISP_SCREEN_HEIGHT-1 - g->p.y; - break; - case GDISP_ROTATE_270: - x = GDISP_SCREEN_WIDTH-1 - g->p.y; - y = g->p.x; - break; + coord_t x = g->p.x; + coord_t y = g->p.y; + if (g->g.Orientation == GDISP_ROTATE_90 || g->g.Orientation == GDISP_ROTATE_270) { + coord_t tmp; + tmp = x; x = y; y = tmp; } return (RAM(g)[xyaddr(x, y)] & xybit(y)) ? White : Black; } @@ -252,8 +262,8 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { case GDISP_CONTROL_ORIENTATION: if (g->g.Orientation == (orientation_t)g->p.ptr) return; - switch((orientation_t)g->p.ptr) { - /* Rotation is handled by the drawing routines */ + orientation_t orient = (orientation_t)g->p.ptr; + switch(orient) { case GDISP_ROTATE_0: case GDISP_ROTATE_180: g->g.Height = GDISP_SCREEN_HEIGHT; @@ -267,7 +277,33 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { default: return; } - g->g.Orientation = (orientation_t)g->p.ptr; + // Remap the rows and columns according to orientation. This just + // eliminates the need to reverse x or y directions in the drawing + // routines. There is still the need to swap x and y for 90 and 270. + // However, without these, the hardware fill routine would be much + // more complicated. + acquire_bus(g); + switch(orient) { + default: + case GDISP_ROTATE_0: + write_cmd(g, SSD1306_COLSCANDEC); + write_cmd(g, SSD1306_ROWSCANDEC); + break; + case GDISP_ROTATE_180: + write_cmd(g, SSD1306_COLSCANINC); + write_cmd(g, SSD1306_ROWSCANINC); + break; + case GDISP_ROTATE_90: + write_cmd(g, SSD1306_COLSCANDEC); + write_cmd(g, SSD1306_ROWSCANINC); + break; + case GDISP_ROTATE_270: + write_cmd(g, SSD1306_COLSCANINC); + write_cmd(g, SSD1306_ROWSCANDEC); + break; + } + release_bus(g); + g->g.Orientation = orient; return; case GDISP_CONTROL_CONTRAST: diff --git a/drivers/gdisp/SSD1306/gdisp_lld_config.h b/drivers/gdisp/SSD1306/gdisp_lld_config.h index 9c5021577dd5..a0961dcfc4c5 100644 --- a/drivers/gdisp/SSD1306/gdisp_lld_config.h +++ b/drivers/gdisp/SSD1306/gdisp_lld_config.h @@ -19,6 +19,7 @@ #define GDISP_HARDWARE_PIXELREAD TRUE #define GDISP_HARDWARE_CONTROL TRUE #define GDISP_HARDWARE_CLEARS TRUE +#define GDISP_HARDWARE_FILLS TRUE #define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_MONO