From e0b2406da613b02fce6af8aead160e43301a3852 Mon Sep 17 00:00:00 2001 From: inmarket Date: Fri, 25 Oct 2013 14:39:56 +1000 Subject: [PATCH] Fix SSD1306 driver and board files to allow for seamless transfer of the command byte with the page line data without copying the data on to the stack. --- drivers/gdisp/SSD1306/board_SSD1306_i2c.h | 9 +++---- drivers/gdisp/SSD1306/board_SSD1306_spi.h | 9 +++---- .../gdisp/SSD1306/board_SSD1306_template.h | 6 ++--- drivers/gdisp/SSD1306/gdisp_lld.c | 26 ++++++++++++++++--- 4 files changed, 32 insertions(+), 18 deletions(-) diff --git a/drivers/gdisp/SSD1306/board_SSD1306_i2c.h b/drivers/gdisp/SSD1306/board_SSD1306_i2c.h index 69c054f5..449d47ba 100644 --- a/drivers/gdisp/SSD1306/board_SSD1306_i2c.h +++ b/drivers/gdisp/SSD1306/board_SSD1306_i2c.h @@ -13,7 +13,8 @@ #ifndef _GDISP_LLD_BOARD_H #define _GDISP_LLD_BOARD_H -#define GDISP_BUS_MAX_TRANSFER_SIZE 64 +// The command byte to put on the front of each page line +#define SSD1306_PAGE_PREFIX 0x40 // Co = 0, D/C = 1 // For a multiple display configuration we would put all this in a structure and then // set g->board to that structure. @@ -116,14 +117,10 @@ static inline void write_cmd(GDisplay *g, uint8_t cmd) { } static inline void write_data(GDisplay *g, uint8_t* data, uint16_t length) { - uint8_t command[1]; (void) g; - command[0] = 0x40; // Co = 0, D/C = 1 - i2cStart(&I2CD1, &i2cconfig); - i2cMasterTransmitTimeout(&I2CD1, SSD1306_I2C_ADDRESS, command, 1, NULL, 0, MS2ST(10)); - i2cMasterTransmitTimeout(&I2CD1, SSD1306_I2C_ADDRESS, command, data, NULL, length, MS2ST(10)); + i2cMasterTransmitTimeout(&I2CD1, SSD1306_I2C_ADDRESS, data, length, NULL, 0, MS2ST(10)); i2cStop(&I2CD1); } diff --git a/drivers/gdisp/SSD1306/board_SSD1306_spi.h b/drivers/gdisp/SSD1306/board_SSD1306_spi.h index 476c51bf..5b481630 100644 --- a/drivers/gdisp/SSD1306/board_SSD1306_spi.h +++ b/drivers/gdisp/SSD1306/board_SSD1306_spi.h @@ -13,7 +13,8 @@ #ifndef _GDISP_LLD_BOARD_H #define _GDISP_LLD_BOARD_H -#define GDISP_BUS_MAX_TRANSFER_SIZE 64 +// The command byte to put on the front of each page line +#define SSD1306_PAGE_PREFIX 0x40 // Co = 0, D/C = 1 // For a multiple display configuration we would put all this in a structure and then // set g->board to that structure. @@ -49,10 +50,12 @@ static const SPIConfig spi1config = { #endif static inline void init_board(GDisplay *g) { + unsigned i; // As we are not using multiple displays we set g->board to NULL as we don't use it. g->board = 0; + switch(g->controllerdisplay) { case 0: // Set up for Display 0 // RESET pin. @@ -115,14 +118,10 @@ static inline void write_cmd(GDisplay *g, uint8_t cmd) { } static inline void write_data(GDisplay *g, uint8_t* data, uint16_t length) { - uint8_t command[1]; (void) g; - command[0] = 0x40; // Co = 0, D/C = 1 - spiStart(&SPID1, &spi1config); spiSelect(&SPID1); - spiStartSend(&SPID1, 1, command); spiStartSend(&SPID1, length, data); spiUnselect(&SPID1); spiStop(&SPID1); diff --git a/drivers/gdisp/SSD1306/board_SSD1306_template.h b/drivers/gdisp/SSD1306/board_SSD1306_template.h index ec7f44f5..5b4bd05c 100644 --- a/drivers/gdisp/SSD1306/board_SSD1306_template.h +++ b/drivers/gdisp/SSD1306/board_SSD1306_template.h @@ -17,12 +17,12 @@ #define _GDISP_LLD_BOARD_H /** - * @brief How many bytes to write in one operation when updating the display. - * @note The screen size (in bytes) must evenly divide by this number. + * @brief Optional: A byte to prefix on each display page line. + * @note If not defined then no byte is prefixed on each page line. * * @notapi */ -#define GDISP_BUS_MAX_TRANSFER_SIZE 64 +//#define SSD1306_PAGE_PREFIX 0x40 /** * @brief Initialise the board for the display. diff --git a/drivers/gdisp/SSD1306/gdisp_lld.c b/drivers/gdisp/SSD1306/gdisp_lld.c index 81b3b692..390a9282 100644 --- a/drivers/gdisp/SSD1306/gdisp_lld.c +++ b/drivers/gdisp/SSD1306/gdisp_lld.c @@ -36,6 +36,13 @@ #ifndef GDISP_INITIAL_BACKLIGHT #define GDISP_INITIAL_BACKLIGHT 100 #endif +#ifdef SSD1306_PAGE_PREFIX + #define SSD1306_PAGE_WIDTH (GDISP_SCREEN_WIDTH+1) + #define SSD1306_PAGE_OFFSET 1 +#else + #define SSD1306_PAGE_WIDTH GDISP_SCREEN_WIDTH + #define SSD1306_PAGE_OFFSET 0 +#endif #define GDISP_FLG_NEEDFLUSH (GDISP_FLG_DRIVER<<0) @@ -54,7 +61,7 @@ #define delay(us) gfxSleepMicroseconds(us) #define delayms(ms) gfxSleepMilliseconds(ms) -#define xyaddr(x, y) ((x) + ((y)>>3)*GDISP_SCREEN_WIDTH) +#define xyaddr(x, y) (SSD1306_PAGE_OFFSET + (x) + ((y)>>3)*SSD1306_PAGE_WIDTH) #define xybit(y) (1<<((y)&7)) /*===========================================================================*/ @@ -70,7 +77,18 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { // The private area is the display surface. - g->priv = gfxAlloc(GDISP_SCREEN_HEIGHT * GDISP_SCREEN_WIDTH / 8); + g->priv = gfxAlloc(GDISP_SCREEN_HEIGHT/8 * SSD1306_PAGE_WIDTH); + + // Fill in the prefix command byte on each page line of the display buffer + // We can do it during initialisation as this byte is never overwritten. + #ifdef SSD1306_PAGE_PREFIX + { + unsigned i; + + for(i=0; i < GDISP_SCREEN_HEIGHT/8 * SSD1306_PAGE_WIDTH; i+=SSD1306_PAGE_WIDTH) + RAM(g)[i] = SSD1306_PAGE_PREFIX; + } + #endif // Initialise the board interface init_board(g); @@ -131,8 +149,8 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { write_cmd(g, SSD1306_SETSTARTLINE | 0); - for(i=0; i < GDISP_SCREEN_WIDTH * GDISP_SCREEN_HEIGHT/8; i+=GDISP_BUS_MAX_TRANSFER_SIZE) - write_data(g, RAM(g)+i, GDISP_BUS_MAX_TRANSFER_SIZE); + for(i=0; i < GDISP_SCREEN_HEIGHT/8 * SSD1306_PAGE_WIDTH; i+=SSD1306_PAGE_WIDTH) + write_data(g, RAM(g)+i, SSD1306_PAGE_WIDTH); } #endif