1. Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.
    Dismiss Notice

Oled spi in C

Discussion in 'Microcontrollers' started by be80be, Jul 12, 2018 at 10:34 AM.

  1. be80be

    be80be Well-Known Member

    Joined:
    Aug 23, 2008
    Messages:
    5,265
    Likes:
    159
    Location:
    morristown,tn
    Does anyone have any Oled spi code I love to see some google turns up lots for i2c but nothing for spi.
    Thanks
     
  2. Ian Rogers

    Ian Rogers User Extraordinaire Forum Supporter Most Helpful Member

    Joined:
    Mar 28, 2011
    Messages:
    9,821
    Likes:
    958
    Location:
    Rochdale UK
    Is this the ssd1306/8 controller per chance????
     
  3. Nigel Goodwin

    Nigel Goodwin Super Moderator Most Helpful Member

    Joined:
    Nov 17, 2003
    Messages:
    39,702
    Likes:
    708
    Location:
    Derbyshire, UK
    Look for Arduino code, it will be in C++, but easily converts to C.

    As far as I remember?, all my OLED modules are I2C - probably because I specifically bought them that way.
     
  4. dave miyares

    Dave New Member

    Joined:
    Jan 12, 1997
    Messages:
    2
    Likes:
    -10


     
  5. be80be

    be80be Well-Known Member

    Joined:
    Aug 23, 2008
    Messages:
    5,265
    Likes:
    159
    Location:
    morristown,tn
    Mine said i2c but there both spi and no really good doc's on how to change the jumpers that you solder on them

    Like this one
    [​IMG]
    ssd1306
     
    Last edited: Jul 12, 2018 at 11:07 AM
  6. Nigel Goodwin

    Nigel Goodwin Super Moderator Most Helpful Member

    Joined:
    Nov 17, 2003
    Messages:
    39,702
    Likes:
    708
    Location:
    Derbyshire, UK
  7. be80be

    be80be Well-Known Member

    Joined:
    Aug 23, 2008
    Messages:
    5,265
    Likes:
    159
    Location:
    morristown,tn
    Yall if there wasn't all the adafruit code in there to makes a lot too weed threw
     
  8. dave miyares

    Dave New Member

    Joined:
    Jan 12, 1997
    Messages:
    2
    Likes:
    -10


     
  9. Ian Rogers

    Ian Rogers User Extraordinaire Forum Supporter Most Helpful Member

    Joined:
    Mar 28, 2011
    Messages:
    9,821
    Likes:
    958
    Location:
    Rochdale UK
  10. Mickster

    Mickster Well-Known Member

    Joined:
    Feb 24, 2008
    Messages:
    1,310
    Likes:
    105
    Location:
    BDA
    Dunno if yours is the same, but check the silkscreen on the rear of the PCB here:
    https://www.banggood.com/3Pcs-7-Pin...-p-1144443.html?rmmds=search&cur_warehouse=CN
    For I2C, populate R1 R4 R6 R7 R8
    For 4SPI populate R3 R4
    For 3SPI populate R2 R3
    The pic shows it set up for 4SPI, but there are resistors on R6 & R7 too.
    I have some on the way from China on a slow boat, so will have to wait before I can try changing the PCB config.
     
  11. be80be

    be80be Well-Known Member

    Joined:
    Aug 23, 2008
    Messages:
    5,265
    Likes:
    159
    Location:
    morristown,tn
    Mine has For 4SPI populate R3 R4 but it shows you remove r3 and add the rest but are they just jummpers or smt resistors there 472 on the smt resistor on the R3 And R4
     
  12. Mike - K8LH

    Mike - K8LH Well-Known Member

    Joined:
    Jan 22, 2005
    Messages:
    3,701
    Likes:
    126
    Location:
    Michigan, USA
    I have that same 0.96" SPI 128x64 SSD1306 OLED display. When I received it a few months ago I tested it to make sure it worked using Arduino code.

    Since I have working I2C (xc8) code for a little 0.91" SSD1306 128x32 OLED display, I'll attempt a version for the 0.96" SPI display, if you'd like.

    Mike
     

    Attached Files:

  13. be80be

    be80be Well-Known Member

    Joined:
    Aug 23, 2008
    Messages:
    5,265
    Likes:
    159
    Location:
    morristown,tn
    I tried out the adafruit code it works But I'd like to use with a pic something to play with LOL I found some code I could make sense of LOL
    Just it's for a click more pins on the click
    https://mplabxpress.microchip.com/mplabcloud/example/details/103
    Code (text):

    /*
     *   Basic OLED SSD1306 display driver
     */
    #include "oled.h"
    // oled click mapping
    #define OLED_CS_LAT         CS_LAT
    #define OLED_DC_LAT         PWM_LAT
    #define OLED_RST_LAT        RST_LAT
    void OLED_Command( uint8_t temp){
      OLED_CS_LAT = 0;
      OLED_DC_LAT = 0;
      SPI_Write( temp);
      OLED_CS_LAT = 1;
    }
    void OLED_Data( uint8_t temp){
      OLED_CS_LAT = 0;
      OLED_DC_LAT = 1;
      SPI_Write( temp);
      OLED_CS_LAT = 1;
    }
    void OLED_Initialize( void)
    {
        OLED_RST_LAT = 0;
        __delay_ms(1000);
        OLED_RST_LAT = 1;
        __delay_ms(1000);
        OLED_Command(SSD1306_DISPLAYOFF);             //0xAE  Set OLED Display Off
        OLED_Command(SSD1306_SETDISPLAYCLOCKDIV);     //0xD5  Set Display Clock Divide Ratio/Oscillator Frequency
        OLED_Command(0x80);
        OLED_Command(SSD1306_SETMULTIPLEX);           //0xA8  Set Multiplex Ratio
        OLED_Command(39);
     
        OLED_Command(SSD1306_SETSEGMENTREMAP);        //0xA1  Set Segment Remap Inv
        OLED_Command(SSD1306_COMSCANDEC);             //0xC8  Set COM Output Scan Inv
        OLED_Command(SSD1306_SETSTARTLINE);           //0x40  Set Display Start Line
     
        OLED_Command(SSD1306_SETDISPLAYOFFSET);       //0xD3  Set Display Offset
        OLED_Command(0x00);
        OLED_Command(SSD1306_CHARGEPUMP);             //0x8D  Set Charge Pump
        OLED_Command(0x14);                           //0x14  Enable Charge Pump
        OLED_Command(SSD1306_SETCOMPINS);             //0xDA  Set COM Pins Hardware Configuration
        OLED_Command(0x12);
        OLED_Command(SSD1306_SETCONTRAST);            //0x81   Set Contrast Control
        OLED_Command(0xAF);
        OLED_Command(SSD1306_SETPRECHARGE);           //0xD9   Set Pre-Charge Period
        OLED_Command(0x25);
        OLED_Command(SSD1306_SETVCOMDETECT);          //0xDB   Set VCOMH Deselect Level
        OLED_Command(0x20);
        OLED_Command(SSD1306_DISPLAYALLON_RESUME);    //0xA4   Set Entire Display On/Off
        OLED_Command(SSD1306_NORMALDISPLAY);          //0xA6   Set Normal/Inverse Display
        OLED_Command(SSD1306_DISPLAYON);              //0xAF   Set OLED Display On
    } // OLED_Initialize
    void OLED_SetRow( uint8_t add)
    {
        add = 0xB0 | add;
        OLED_Command( add);
    }
    void OLED_SetColumn( uint8_t add)
    {
        add += 32;
        OLED_Command(( SSD1306_SETHIGHCOLUMN | (add >> 4))); // SET_HIGH_COLUMN
        OLED_Command(( 0x0f & add));        // SET LOW_COLUMN
    }
    void OLED_PutPicture( const uint8_t *pic)
    {
        unsigned char i,j;
        for( i=0; i<5; i++) // 5*8=40 pixel rows (actually 39)
        {
            OLED_SetRow( i);
            OLED_SetColumn( 0);
            for( j=0; j<96; j++)  // 96 pixel columns
            {
                OLED_Data( *pic++);
            }
        }
    }
    void OLED_SetContrast( uint8_t temp)
    {
        OLED_Command( SSD1306_SETCONTRAST);
        OLED_Command( temp);                  // contrast step 1 to 256
    }
    const uint8_t font[] = {
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x5F,0x00,0x00,0x00,0x07,0x00,0x07,0x00, //    'sp,!,"
        0x14,0x7F,0x14,0x7F,0x14, // #
        0x24,0x2A,0x7F,0x2A,0x12,0x23,0x13,0x08,0x64,0x62,0x36,0x49,0x56,0x20,0x50, //    '$,%,&
        0x00,0x08,0x07,0x03,0x00,0x00,0x1C,0x22,0x41,0x00,0x00,0x41,0x22,0x1C,0x00, //    '',(,)
        0x2A,0x1C,0x7F,0x1C,0x2A,0x08,0x08,0x3E,0x08,0x08,0x00,0x00,0x70,0x30,0x00, //    '*,+,,
        0x08,0x08,0x08,0x08,0x08,0x00,0x00,0x60,0x60,0x00,0x20,0x10,0x08,0x04,0x02, //    '-,.,/
        0x3E,0x51,0x49,0x45,0x3E,0x00,0x42,0x7F,0x40,0x00,0x72,0x49,0x49,0x49,0x46, //    '0,1,2
        0x21,0x41,0x49,0x4D,0x33,0x18,0x14,0x12,0x7F,0x10,0x27,0x45,0x45,0x45,0x39, //    '3,4,5
        0x3C,0x4A,0x49,0x49,0x31,0x41,0x21,0x11,0x09,0x07,0x36,0x49,0x49,0x49,0x36, //    '6,7,8
        0x46,0x49,0x49,0x29,0x1E,0x00,0x00,0x14,0x00,0x00,0x00,0x40,0x34,0x00,0x00, //    '9,:,;
        0x00,0x08,0x14,0x22,0x41,0x14,0x14,0x14,0x14,0x14,0x00,0x41,0x22,0x14,0x08, //    '<,=,>
        0x02,0x01,0x59,0x09,0x06,0x3E,0x41,0x5D,0x59,0x4E,                          //  '?,@
        0x7C,0x12,0x11,0x12,0x7C,                                                   //    'A
        0x7F,0x49,0x49,0x49,0x36,0x3E,0x41,0x41,0x41,0x22,0x7F,0x41,0x41,0x41,0x3E, //    'B,C,D
        0x7F,0x49,0x49,0x49,0x41,0x7F,0x09,0x09,0x09,0x01,0x3E,0x41,0x41,0x51,0x73, //    'E,F,G
        0x7F,0x08,0x08,0x08,0x7F,0x00,0x41,0x7F,0x41,0x00,0x20,0x40,0x41,0x3F,0x01, //    'H,I,J
        0x7F,0x08,0x14,0x22,0x41,0x7F,0x40,0x40,0x40,0x40,0x7F,0x02,0x1C,0x02,0x7F, //    'K,L,M
        0x7F,0x04,0x08,0x10,0x7F,0x3E,0x41,0x41,0x41,0x3E,0x7F,0x09,0x09,0x09,0x06, //    'N,O,P
        0x3E,0x41,0x51,0x21,0x5E,0x7F,0x09,0x19,0x29,0x46,0x26,0x49,0x49,0x49,0x32, //    'Q,R,S
        0x03,0x01,0x7F,0x01,0x03,0x3F,0x40,0x40,0x40,0x3F,0x1F,0x20,0x40,0x20,0x1F, //    'T,U,V
        0x3F,0x40,0x38,0x40,0x3F,0x63,0x14,0x08,0x14,0x63,0x03,0x04,0x78,0x04,0x03, //    'W,X,Y
        0x61,0x59,0x49,0x4D,0x43,                                                   //  'Z
        0x00,0x7F,0x41,0x41,0x41,0x02,0x04,0x08,0x10,0x20,                          //    '[,\
        0x00,0x41,0x41,0x41,0x7F,0x04,0x02,0x01,0x02,0x04,0x40,0x40,0x40,0x40,0x40, //    '],^,_
        0x00,0x03,0x07,0x08,0x00,0x20,0x54,0x54,0x38,0x40,0x7F,0x28,0x44,0x44,0x38, //    '`,a,b
        0x38,0x44,0x44,0x44,0x28,0x38,0x44,0x44,0x28,0x7F,0x38,0x54,0x54,0x54,0x18, //    'c,d,e
        0x00,0x08,0x7E,0x09,0x02,0x0C,0x52,0x52,0x4A,0x3C,0x7F,0x08,0x04,0x04,0x78, //    'f,g,h
        0x00,0x44,0x7D,0x40,0x00,0x20,0x40,0x40,0x3D,0x00,0x7F,0x10,0x28,0x44,0x00, //    'i,j,k
        0x00,0x41,0x7F,0x40,0x00,0x7C,0x04,0x78,0x04,0x78,0x7C,0x08,0x04,0x04,0x78, //    'l,m,n
        0x38,0x44,0x44,0x44,0x38,0x7C,0x18,0x24,0x24,0x18,0x18,0x24,0x24,0x18,0x7C, //    'o,p,q
        0x7C,0x08,0x04,0x04,0x08,0x48,0x54,0x54,0x54,0x24,0x04,0x04,0x3F,0x44,0x24, //    'r,s,t
        0x3C,0x40,0x40,0x20,0x7C,0x1C,0x20,0x40,0x20,0x1C,0x3C,0x40,0x30,0x40,0x3C, //    'u,v,w
        0x44,0x28,0x10,0x28,0x44,0x4C,0x50,0x50,0x50,0x3C,0x44,0x64,0x54,0x4C,0x44, //    'x,y,z
        0x00,0x08,0x36,0x41,0x00,0x00,0x00,0x77,0x00,0x00,0x00,0x41,0x36,0x08,0x00, //    '{,|,}
        0x02,0x01,0x02,0x04,0x02                                                    //  '~
        };
    uint8_t _x, _y;
    void OLED_Clear( void)
    {
        unsigned char i,j;
        for( i=0; i<5; i++) // 5*8=40 pixel rows (actually 39)
        {
            OLED_SetRow( i);
            OLED_SetColumn( 0);
            for( j=0; j<96; j++)  OLED_Data( 0);
        }
        _x = 0; _y = 0;
        OLED_SetRow(0);
        OLED_SetColumn(0);
    }
    void OLED_Putchar( char ch)
    {
        uint8_t i;
        const uint8_t *f = &font[(ch-' ')*5];
        for( i=0; i<5; i++)
            OLED_Data( *f++ << 1);
        OLED_Data( 0);
        _x++;
        if (_x >= 16) { // wrap x
            _x = 0; OLED_SetColumn(0);
            _y++;  
            if (_y >= 5) { // wrap y
                _y = 0;
            }
            OLED_SetRow(_y);
        }
    }
    void OLED_Puts( char x, char y, char *s)
    {
        _y = y; _x = x;
        OLED_SetRow( _y);
        OLED_SetColumn( _x *6);  
        while( *s) {
            OLED_Putchar( *s++);
            _x++;
        }
    }
     
    Code (text):

    /*
     * File: oled.h
    */
    #include "mcc_generated_files/mcc.h"
    #define OLED_WIDTH             96
    #define OLED_HEIGHT            39
    #define SSD1306_DISPLAYOFF          0xAE
    #define SSD1306_SETDISPLAYCLOCKDIV  0xD5
    #define SSD1306_SETMULTIPLEX        0xA8
    #define SSD1306_SETDISPLAYOFFSET    0xD3
    #define SSD1306_SETSTARTLINE        0x40
    #define SSD1306_CHARGEPUMP          0x8D
    #define SSD1306_SETSEGMENTREMAP     0xA1
    #define SSD1306_SEGREMAP            0xA0
    #define SSD1306_COMSCANDEC          0xC8
    #define SSD1306_SETCOMPINS          0xDA
    #define SSD1306_SETCONTRAST         0x81
    #define SSD1306_SETPRECHARGE        0xD9
    #define SSD1306_SETVCOMDETECT       0xDB
    #define SSD1306_DISPLAYALLON_RESUME 0xA4
    #define SSD1306_NORMALDISPLAY       0xA6
    #define SSD1306_DISPLAYON           0xAF
    #define SSD1306_DISPLAYALLON        0xA5
    #define SSD1306_INVERTDISPLAY       0xA7
    #define SSD1306_SETLOWCOLUMN        0x00
    #define SSD1306_SETHIGHCOLUMN       0x10
    #define SSD1306_MEMORYMODE          0x20
    #define SSD1306_COLUMNADDR          0x21
    #define SSD1306_PAGEADDR            0x22
    #define SSD1306_COMSCANINC          0xC0
    #define SSD1306_SEGREMAP            0xA0
    #define SSD1306_EXTERNALVCC         0x1
    #define SSD1306_SWITCHCAPVCC        0x2
    #define SSD1306_ACTIVATE_SCROLL                         0x2F
    #define SSD1306_DEACTIVATE_SCROLL                       0x2E
    #define SSD1306_SET_VERTICAL_SCROLL_AREA                0xA3
    #define SSD1306_RIGHT_HORIZONTAL_SCROLL                 0x26
    #define SSD1306_LEFT_HORIZONTAL_SCROLL                  0x27
    #define SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL    0x29
    #define SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL     0x2A
    #define SPI_Write( x)       SPI1_Exchange8bit( x)
    void OLED_Command( uint8_t);
    void OLED_Data( uint8_t);
    void OLED_Initialize( void);
    // Set row
    void OLED_SetRow( uint8_t);
    // Set column
    void OLED_SetColumn( uint8_t);
    // Display picture form array in memory
    void OLED_PutPicture( const uint8_t *);
    // control contrast in steps  from 1 to 256
    void OLED_SetContrast( uint8_t);
    void OLED_Putchar( char ch);
    void OLED_Puts( char x, char y, char *s);
    void OLED_Clear( void);
     
     
  14. nsaspook

    nsaspook Well-Known Member

    Joined:
    Mar 24, 2010
    Messages:
    1,216
    Likes:
    233
    Location:
    Fairview, Or
  15. DirtyLude

    DirtyLude Well-Known Member

    Joined:
    Aug 5, 2003
    Messages:
    1,916
    Likes:
    60
    Location:
    Toronto, Canada
    That Adafruit code looks like it would take about 15 minutes to convert to regular C and some other SPI layer. Doesn't look all that complicated. Get rid of all the functions you don't want like the contrast and scrolling if it's over complicating things for you.

    10 years ago if I wanted code for anything I used to google 'PIC chipX library' to convert that to whatever chip I was working on, now I google for the Arduino library. Converting Arduino libraries to whatever platform your working on is a good skill to have, just because there are so many of them out there and the common ones are usually well tested.
     
  16. be80be

    be80be Well-Known Member

    Joined:
    Aug 23, 2008
    Messages:
    5,265
    Likes:
    159
    Location:
    morristown,tn
    What get's me is they use wire.h and spi.h
     
  17. DirtyLude

    DirtyLude Well-Known Member

    Joined:
    Aug 5, 2003
    Messages:
    1,916
    Likes:
    60
    Location:
    Toronto, Canada
    There's is probably 4 or 5 library calls in it that you don't have direct access to. That you just replace with your own SPI code.

    Here, I looked through it. This is what you need to do:

    pinMode() //changes pins to input/outputs replace with your code
    digitalwrite() //sets output pin level - replace with your code
    spi.transfer() //transfers 8 bits on the SPI bus, replace with your code
    delay //Arduino has its own delay functions, replace with your own.

    These are SPI setup code, replace with your own. Actually there's a whole lot of #if def crap, get rid of the whole lot and replace with a regular SPI setup.
    SPI.begin()
    SPI.beginTransaction(SPISettings(8000000, MSBFIRST, SPI_MODE0))

    all wire. calls are I2C, you are getting rid of all that code.
    Wire.beginTransmission()
    Wire.write()
    Wire.endTransmission()

    Other than that you just need to change the names of all the functions so they are regular C library names and get rid of the constructor.
     
  18. DirtyLude

    DirtyLude Well-Known Member

    Joined:
    Aug 5, 2003
    Messages:
    1,916
    Likes:
    60
    Location:
    Toronto, Canada
    Here, I C'ified the library and removed everything hardware wise that was irrelevant. I don't think this need much more other than putting in your SPI code. Update the header file to remove all the hardware stuff at the beginning and update the function definitions with their new names. I put //be80be anywhere that needs to be updated.

    Code (text):

    /*********************************************************************
    This is a library for our Monochrome OLEDs based on SSD1306 drivers

      Pick one up today in the adafruit shop!
      ------> http://www.adafruit.com/category/63_98

    These displays use SPI to communicate, 4 or 5 pins are required to
    interface

    Adafruit invests time and resources providing this open source code,
    please support Adafruit and open-source hardware by purchasing
    products from Adafruit!

    Written by Limor Fried/Ladyada  for Adafruit Industries.
    BSD license, check license.txt for more information
    All text above, and the splash screen below must be included in any redistribution
    *********************************************************************/

    #include "Adafruit_SSD1306.h"

    // the memory buffer for the LCD

    static uint8_t buffer[SSD1306_LCDHEIGHT * SSD1306_LCDWIDTH / 8] = {
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
    0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x80, 0x80, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xF8, 0xE0, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80,
    0x80, 0x80, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0xFF,
    #if (SSD1306_LCDHEIGHT * SSD1306_LCDWIDTH > 96*16)
    0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00,
    0x80, 0xFF, 0xFF, 0x80, 0x80, 0x00, 0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x80, 0x80,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x8C, 0x8E, 0x84, 0x00, 0x00, 0x80, 0xF8,
    0xF8, 0xF8, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xE0, 0xE0, 0xC0, 0x80,
    0x00, 0xE0, 0xFC, 0xFE, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xC7, 0x01, 0x01,
    0x01, 0x01, 0x83, 0xFF, 0xFF, 0x00, 0x00, 0x7C, 0xFE, 0xC7, 0x01, 0x01, 0x01, 0x01, 0x83, 0xFF,
    0xFF, 0xFF, 0x00, 0x38, 0xFE, 0xC7, 0x83, 0x01, 0x01, 0x01, 0x83, 0xC7, 0xFF, 0xFF, 0x00, 0x00,
    0x01, 0xFF, 0xFF, 0x01, 0x01, 0x00, 0xFF, 0xFF, 0x07, 0x01, 0x01, 0x01, 0x00, 0x00, 0x7F, 0xFF,
    0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0xFF,
    0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x03, 0x0F, 0x3F, 0x7F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xC7, 0xC7, 0x8F,
    0x8F, 0x9F, 0xBF, 0xFF, 0xFF, 0xC3, 0xC0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFC, 0xFC,
    0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xF8, 0xF8, 0xF0, 0xF0, 0xE0, 0xC0, 0x00, 0x01, 0x03, 0x03, 0x03,
    0x03, 0x03, 0x01, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x03, 0x03, 0x01, 0x01,
    0x03, 0x01, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x03, 0x03, 0x01, 0x01, 0x03, 0x03, 0x00, 0x00,
    0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
    0x03, 0x03, 0x03, 0x03, 0x03, 0x01, 0x00, 0x00, 0x00, 0x01, 0x03, 0x01, 0x00, 0x00, 0x00, 0x03,
    0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    #if (SSD1306_LCDHEIGHT == 64)
    0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x1F, 0x0F,
    0x87, 0xC7, 0xF7, 0xFF, 0xFF, 0x1F, 0x1F, 0x3D, 0xFC, 0xF8, 0xF8, 0xF8, 0xF8, 0x7C, 0x7D, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x3F, 0x0F, 0x07, 0x00, 0x30, 0x30, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xC0, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0xC0, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x7F, 0x3F, 0x1F,
    0x0F, 0x07, 0x1F, 0x7F, 0xFF, 0xFF, 0xF8, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xF8, 0xE0,
    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0x00, 0x00,
    0x00, 0xFC, 0xFE, 0xFC, 0x0C, 0x06, 0x06, 0x0E, 0xFC, 0xF8, 0x00, 0x00, 0xF0, 0xF8, 0x1C, 0x0E,
    0x06, 0x06, 0x06, 0x0C, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFE, 0xFE, 0x00, 0x00, 0x00, 0x00, 0xFC,
    0xFE, 0xFC, 0x00, 0x18, 0x3C, 0x7E, 0x66, 0xE6, 0xCE, 0x84, 0x00, 0x00, 0x06, 0xFF, 0xFF, 0x06,
    0x06, 0xFC, 0xFE, 0xFC, 0x0C, 0x06, 0x06, 0x06, 0x00, 0x00, 0xFE, 0xFE, 0x00, 0x00, 0xC0, 0xF8,
    0xFC, 0x4E, 0x46, 0x46, 0x46, 0x4E, 0x7C, 0x78, 0x40, 0x18, 0x3C, 0x76, 0xE6, 0xCE, 0xCC, 0x80,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x01, 0x07, 0x0F, 0x1F, 0x1F, 0x3F, 0x3F, 0x3F, 0x3F, 0x1F, 0x0F, 0x03,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00,
    0x00, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x03, 0x07, 0x0E, 0x0C,
    0x18, 0x18, 0x0C, 0x06, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x01, 0x0F, 0x0E, 0x0C, 0x18, 0x0C, 0x0F,
    0x07, 0x01, 0x00, 0x04, 0x0E, 0x0C, 0x18, 0x0C, 0x0F, 0x07, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00,
    0x00, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x07,
    0x07, 0x0C, 0x0C, 0x18, 0x1C, 0x0C, 0x06, 0x06, 0x00, 0x04, 0x0E, 0x0C, 0x18, 0x0C, 0x0F, 0x07,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    #endif
    #endif
    };

    #define ssd1306_swap(a, b) { int16_t t = a; a = b; b = t; }

    // the most basic function, set a single pixel
    void SSD1306_drawPixel(int16_t x, int16_t y, uint16_t color) {
      if ((x < 0) || (x >= width()) || (y < 0) || (y >= height()))
        return;

      // check rotation, move pixel around if necessary
      switch (getRotation()) {
      case 1:
        ssd1306_swap(x, y);
        x = WIDTH - x - 1;
        break;
      case 2:
        x = WIDTH - x - 1;
        y = HEIGHT - y - 1;
        break;
      case 3:
        ssd1306_swap(x, y);
        y = HEIGHT - y - 1;
        break;
      }

      // x is which column
        switch (color)
        {
          case WHITE:   buffer[x+ (y/8)*SSD1306_LCDWIDTH] |=  (1 << (y&7)); break;
          case BLACK:   buffer[x+ (y/8)*SSD1306_LCDWIDTH] &= ~(1 << (y&7)); break;
          case INVERSE: buffer[x+ (y/8)*SSD1306_LCDWIDTH] ^=  (1 << (y&7)); break;
        }

    }

    void SSD1306_begin(uint8_t vccstate, uint8_t i2caddr, bool reset) {
    //be80be - REPLACE ALL THIS - YOUR SPI SETUP CODE HERE
        pinMode(dc, OUTPUT);
        pinMode(cs, OUTPUT);
        SPI.begin();
        SPI.beginTransaction(SPISettings(8000000, MSBFIRST, SPI_MODE0));

    //be80be - REPLACE ALL THIS - LOOKS LIKE toggling the reset pin with delay
    //I think this was optional in the original code and the reset may just be tied to a rail
      if ((reset) && (rst >= 0)) {
        // Setup reset pin direction (used by both SPI and I2C)
        pinMode(rst, OUTPUT);
        digitalWrite(rst, HIGH);
        // VDD (3.3V) goes high at start, lets just chill for a ms
    //be80be - REPLACE THIS - YOUR DELAY function here
        delay(1);
        // bring reset low
        digitalWrite(rst, LOW);
        // wait 10ms
    //be80be - REPLACE THIS - YOUR DELAY function here
        delay(10);
        // bring out of reset
        digitalWrite(rst, HIGH);
        // turn on VCC (9V?)
      }

      // Init sequence
      ssd1306_command(SSD1306_DISPLAYOFF);                    // 0xAE
      ssd1306_command(SSD1306_SETDISPLAYCLOCKDIV);            // 0xD5
      ssd1306_command(0x80);                                  // the suggested ratio 0x80

      ssd1306_command(SSD1306_SETMULTIPLEX);                  // 0xA8
      ssd1306_command(SSD1306_LCDHEIGHT - 1);

      ssd1306_command(SSD1306_SETDISPLAYOFFSET);              // 0xD3
      ssd1306_command(0x0);                                   // no offset
      ssd1306_command(SSD1306_SETSTARTLINE | 0x0);            // line #0
      ssd1306_command(SSD1306_CHARGEPUMP);                    // 0x8D
      if (vccstate == SSD1306_EXTERNALVCC)
        { ssd1306_command(0x10); }
      else
        { ssd1306_command(0x14); }
      ssd1306_command(SSD1306_MEMORYMODE);                    // 0x20
      ssd1306_command(0x00);                                  // 0x0 act like ks0108
      ssd1306_command(SSD1306_SEGREMAP | 0x1);
      ssd1306_command(SSD1306_COMSCANDEC);

     #if defined SSD1306_128_32
      ssd1306_command(SSD1306_SETCOMPINS);                    // 0xDA
      ssd1306_command(0x02);
      ssd1306_command(SSD1306_SETCONTRAST);                   // 0x81
      ssd1306_command(0x8F);

    #elif defined SSD1306_128_64
      ssd1306_command(SSD1306_SETCOMPINS);                    // 0xDA
      ssd1306_command(0x12);
      ssd1306_command(SSD1306_SETCONTRAST);                   // 0x81
      if (vccstate == SSD1306_EXTERNALVCC)
        { ssd1306_command(0x9F); }
      else
        { ssd1306_command(0xCF); }

    #elif defined SSD1306_96_16
      ssd1306_command(SSD1306_SETCOMPINS);                    // 0xDA
      ssd1306_command(0x2);   //ada x12
      ssd1306_command(SSD1306_SETCONTRAST);                   // 0x81
      if (vccstate == SSD1306_EXTERNALVCC)
        { ssd1306_command(0x10); }
      else
        { ssd1306_command(0xAF); }

    #endif

      ssd1306_command(SSD1306_SETPRECHARGE);                  // 0xd9
      if (vccstate == SSD1306_EXTERNALVCC)
        { ssd1306_command(0x22); }
      else
        { ssd1306_command(0xF1); }
      ssd1306_command(SSD1306_SETVCOMDETECT);                 // 0xDB
      ssd1306_command(0x40);
      ssd1306_command(SSD1306_DISPLAYALLON_RESUME);           // 0xA4
      ssd1306_command(SSD1306_NORMALDISPLAY);                 // 0xA6

      ssd1306_command(SSD1306_DEACTIVATE_SCROLL);

      ssd1306_command(SSD1306_DISPLAYON);//--turn on oled panel
    }


    void SSD1306_invertDisplay(uint8_t i) {
      if (i) {
        ssd1306_command(SSD1306_INVERTDISPLAY);
      } else {
        ssd1306_command(SSD1306_NORMALDISPLAY);
      }
    }

    void ssd1306_command(uint8_t c) {
    //be80be - REPLACE THIS - YOUR SPI TRANSFER CODE HERE
    //  Note that the CS and DC pin are being pulled high and low in a specific order before/after the call

        // SPI
        digitalWrite(cs, HIGH);
        digitalWrite(dc, LOW);
        digitalWrite(cs, LOW);
        fastSPIwrite(c);
        digitalWrite(cs, HIGH);
    }

    // startscrollright
    // Activate a right handed scroll for rows start through stop
    // Hint, the display is 16 rows tall. To scroll the whole display, run:
    // display.scrollright(0x00, 0x0F)
    void SSD1306_startscrollright(uint8_t start, uint8_t stop){
      ssd1306_command(SSD1306_RIGHT_HORIZONTAL_SCROLL);
      ssd1306_command(0X00);
      ssd1306_command(start);
      ssd1306_command(0X00);
      ssd1306_command(stop);
      ssd1306_command(0X00);
      ssd1306_command(0XFF);
      ssd1306_command(SSD1306_ACTIVATE_SCROLL);
    }

    // startscrollleft
    // Activate a right handed scroll for rows start through stop
    // Hint, the display is 16 rows tall. To scroll the whole display, run:
    // display.scrollright(0x00, 0x0F)
    void SSD1306_startscrollleft(uint8_t start, uint8_t stop){
      ssd1306_command(SSD1306_LEFT_HORIZONTAL_SCROLL);
      ssd1306_command(0X00);
      ssd1306_command(start);
      ssd1306_command(0X00);
      ssd1306_command(stop);
      ssd1306_command(0X00);
      ssd1306_command(0XFF);
      ssd1306_command(SSD1306_ACTIVATE_SCROLL);
    }

    // startscrolldiagright
    // Activate a diagonal scroll for rows start through stop
    // Hint, the display is 16 rows tall. To scroll the whole display, run:
    // display.scrollright(0x00, 0x0F)
    void SSD1306_startscrolldiagright(uint8_t start, uint8_t stop){
      ssd1306_command(SSD1306_SET_VERTICAL_SCROLL_AREA);
      ssd1306_command(0X00);
      ssd1306_command(SSD1306_LCDHEIGHT);
      ssd1306_command(SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL);
      ssd1306_command(0X00);
      ssd1306_command(start);
      ssd1306_command(0X00);
      ssd1306_command(stop);
      ssd1306_command(0X01);
      ssd1306_command(SSD1306_ACTIVATE_SCROLL);
    }

    // startscrolldiagleft
    // Activate a diagonal scroll for rows start through stop
    // Hint, the display is 16 rows tall. To scroll the whole display, run:
    // display.scrollright(0x00, 0x0F)
    void SSD1306_startscrolldiagleft(uint8_t start, uint8_t stop){
      ssd1306_command(SSD1306_SET_VERTICAL_SCROLL_AREA);
      ssd1306_command(0X00);
      ssd1306_command(SSD1306_LCDHEIGHT);
      ssd1306_command(SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL);
      ssd1306_command(0X00);
      ssd1306_command(start);
      ssd1306_command(0X00);
      ssd1306_command(stop);
      ssd1306_command(0X01);
      ssd1306_command(SSD1306_ACTIVATE_SCROLL);
    }

    void SSD1306_stopscroll(void){
      ssd1306_command(SSD1306_DEACTIVATE_SCROLL);
    }

    // Dim the display
    // dim = true: display is dimmed
    // dim = false: display is normal
    void SSD1306_dim(boolean dim) {
      uint8_t contrast;

      if (dim) {
        contrast = 0; // Dimmed display
      } else {
        if (_vccstate == SSD1306_EXTERNALVCC) {
          contrast = 0x9F;
        } else {
          contrast = 0xCF;
        }
      }
      // the range of contrast to too small to be really useful
      // it is useful to dim the display
      ssd1306_command(SSD1306_SETCONTRAST);
      ssd1306_command(contrast);
    }

    void SSD1306_display(void) {
      ssd1306_command(SSD1306_COLUMNADDR);
      ssd1306_command(0);   // Column start address (0 = reset)
      ssd1306_command(SSD1306_LCDWIDTH-1); // Column end address (127 = reset)

      ssd1306_command(SSD1306_PAGEADDR);
      ssd1306_command(0); // Page start address (0 = reset)
      #if SSD1306_LCDHEIGHT == 64
        ssd1306_command(7); // Page end address
      #endif
      #if SSD1306_LCDHEIGHT == 32
        ssd1306_command(3); // Page end address
      #endif
      #if SSD1306_LCDHEIGHT == 16
        ssd1306_command(1); // Page end address
      #endif

    //be80be - REPLACE THIS - YOUR SPI TRANSFER CODE HERE
    //  Note that the CS and DC pin are being pulled high and low in a specific order before/after the call

      digitalWrite(cs, HIGH);
      digitalWrite(dc, HIGH);
      digitalWrite(cs, LOW);

      for (uint16_t i=0; i<(SSD1306_LCDWIDTH*SSD1306_LCDHEIGHT/8); i++) {
        fastSPIwrite(buffer[i]);
      }
      digitalWrite(cs, HIGH);
    }

    // clear everything
    void SSD1306_clearDisplay(void) {
      memset(buffer, 0, (SSD1306_LCDWIDTH*SSD1306_LCDHEIGHT/8));
    }

    inline void SSD1306_fastSPIwrite(uint8_t d) {
    //be80be - REPLACE THIS - YOUR SPI TRANSFER CODE HERE

        (void)SPI.transfer(d);
    }

    void SSD1306_drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) {
      boolean bSwap = false;
      switch(rotation) {
        case 0:
          // 0 degree rotation, do nothing
          break;
        case 1:
          // 90 degree rotation, swap x & y for rotation, then invert x
          bSwap = true;
          ssd1306_swap(x, y);
          x = WIDTH - x - 1;
          break;
        case 2:
          // 180 degree rotation, invert x and y - then shift y around for height.
          x = WIDTH - x - 1;
          y = HEIGHT - y - 1;
          x -= (w-1);
          break;
        case 3:
          // 270 degree rotation, swap x & y for rotation, then invert y  and adjust y for w (not to become h)
          bSwap = true;
          ssd1306_swap(x, y);
          y = HEIGHT - y - 1;
          y -= (w-1);
          break;
      }

      if(bSwap) {
        SSD1306_drawFastVLineInternal(x, y, w, color);
      } else {
        SSD1306_drawFastHLineInternal(x, y, w, color);
      }
    }

    void SSD1306_drawFastHLineInternal(int16_t x, int16_t y, int16_t w, uint16_t color) {
      // Do bounds/limit checks
      if(y < 0 || y >= HEIGHT) { return; }

      // make sure we don't try to draw below 0
      if(x < 0) {
        w += x;
        x = 0;
      }

      // make sure we don't go off the edge of the display
      if( (x + w) > WIDTH) {
        w = (WIDTH - x);
      }

      // if our width is now negative, punt
      if(w <= 0) { return; }

      // set up the pointer for  movement through the buffer
      register uint8_t *pBuf = buffer;
      // adjust the buffer pointer for the current row
      pBuf += ((y/8) * SSD1306_LCDWIDTH);
      // and offset x columns in
      pBuf += x;

      register uint8_t mask = 1 << (y&7);

      switch (color)
      {
      case WHITE:         while(w--) { *pBuf++ |= mask; }; break;
        case BLACK: mask = ~mask;   while(w--) { *pBuf++ &= mask; }; break;
      case INVERSE:         while(w--) { *pBuf++ ^= mask; }; break;
      }
    }

    void SSD1306_drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) {
      bool bSwap = false;
      switch(rotation) {
        case 0:
          break;
        case 1:
          // 90 degree rotation, swap x & y for rotation, then invert x and adjust x for h (now to become w)
          bSwap = true;
          ssd1306_swap(x, y);
          x = WIDTH - x - 1;
          x -= (h-1);
          break;
        case 2:
          // 180 degree rotation, invert x and y - then shift y around for height.
          x = WIDTH - x - 1;
          y = HEIGHT - y - 1;
          y -= (h-1);
          break;
        case 3:
          // 270 degree rotation, swap x & y for rotation, then invert y
          bSwap = true;
          ssd1306_swap(x, y);
          y = HEIGHT - y - 1;
          break;
      }

      if(bSwap) {
        SSD1306_drawFastHLineInternal(x, y, h, color);
      } else {
        SSD1306_drawFastVLineInternal(x, y, h, color);
      }
    }


    void SSD1306_drawFastVLineInternal(int16_t x, int16_t __y, int16_t __h, uint16_t color) {

      // do nothing if we're off the left or right side of the screen
      if(x < 0 || x >= WIDTH) { return; }

      // make sure we don't try to draw below 0
      if(__y < 0) {
        // __y is negative, this will subtract enough from __h to account for __y being 0
        __h += __y;
        __y = 0;

      }

      // make sure we don't go past the height of the display
      if( (__y + __h) > HEIGHT) {
        __h = (HEIGHT - __y);
      }

      // if our height is now negative, punt
      if(__h <= 0) {
        return;
      }

      // this display doesn't need ints for coordinates, use local byte registers for faster juggling
      register uint8_t y = __y;
      register uint8_t h = __h;


      // set up the pointer for fast movement through the buffer
      register uint8_t *pBuf = buffer;
      // adjust the buffer pointer for the current row
      pBuf += ((y/8) * SSD1306_LCDWIDTH);
      // and offset x columns in
      pBuf += x;

      // do the first partial byte, if necessary - this requires some masking
      register uint8_t mod = (y&7);
      if(mod) {
        // mask off the high n bits we want to set
        mod = 8-mod;

        // note - lookup table results in a nearly 10% performance improvement in fill* functions
        // register uint8_t mask = ~(0xFF >> (mod));
        static uint8_t premask[8] = {0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE };
        register uint8_t mask = premask[mod];

        // adjust the mask if we're not going to reach the end of this byte
        if( h < mod) {
          mask &= (0XFF >> (mod-h));
        }

      switch (color)
        {
        case WHITE:   *pBuf |=  mask;  break;
        case BLACK:   *pBuf &= ~mask;  break;
        case INVERSE: *pBuf ^=  mask;  break;
        }

        // fast exit if we're done here!
        if(h<mod) { return; }

        h -= mod;

        pBuf += SSD1306_LCDWIDTH;
      }


      // write solid bytes while we can - effectively doing 8 rows at a time
      if(h >= 8) {
        if (color == INVERSE)  {          // separate copy of the code so we don't impact performance of the black/white write version with an extra comparison per loop
          do  {
          *pBuf=~(*pBuf);

            // adjust the buffer forward 8 rows worth of data
            pBuf += SSD1306_LCDWIDTH;

            // adjust h & y (there's got to be a faster way for me to do this, but this should still help a fair bit for now)
            h -= 8;
          } while(h >= 8);
          }
        else {
          // store a local value to work with
          register uint8_t val = (color == WHITE) ? 255 : 0;

          do  {
            // write our value in
          *pBuf = val;

            // adjust the buffer forward 8 rows worth of data
            pBuf += SSD1306_LCDWIDTH;

            // adjust h & y (there's got to be a faster way for me to do this, but this should still help a fair bit for now)
            h -= 8;
          } while(h >= 8);
          }
        }

      // now do the final partial byte, if necessary
      if(h) {
        mod = h & 7;
        // this time we want to mask the low bits of the byte, vs the high bits we did above
        // register uint8_t mask = (1 << mod) - 1;
        // note - lookup table results in a nearly 10% performance improvement in fill* functions
        static uint8_t postmask[8] = {0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F };
        register uint8_t mask = postmask[mod];
        switch (color)
        {
          case WHITE:   *pBuf |=  mask;  break;
          case BLACK:   *pBuf &= ~mask;  break;
          case INVERSE: *pBuf ^=  mask;  break;
        }
      }
    }

     
    Edit: Probably some boolean types in there you'll have to make uint8_t.
     
    • Like Like x 2
  19. Mike - K8LH

    Mike - K8LH Well-Known Member

    Joined:
    Jan 22, 2005
    Messages:
    3,701
    Likes:
    126
    Location:
    Michigan, USA
    I just converted my 'minimal' XC8 (16F1823) demo program for the little 0.91" 128x32 I2C OLED display to a "minimal" version for the 0.96" 128x64 SPI OLED display. It's a single file, a little over 300 lines, and uses just over 400 words of program memory, including the 240 word 96 character 'packed' 5x7 font table... I'll try to run this on real hardware tomorrow...

    The I2C program for the 128x32 0.91" display is a bit longer and larger due to all of the I2C functions but I really like the 2-pin I2C interface (you could use it on an 8-pin PIC) and I'm kind of tickled to be running the I2C interface at 1-MHz without any problems.
     
    Last edited: Jul 12, 2018 at 7:34 PM
  20. be80be

    be80be Well-Known Member

    Joined:
    Aug 23, 2008
    Messages:
    5,265
    Likes:
    159
    Location:
    morristown,tn
    Thanks DirtyLude And mike if you don't care id like to see your code as well
     
  21. Mike - K8LH

    Mike - K8LH Well-Known Member

    Joined:
    Jan 22, 2005
    Messages:
    3,701
    Likes:
    126
    Location:
    Michigan, USA
    Happy to share but even though it's an XC8 program, it has a bunch of assembly language. Sorry! I try to use straight C code but I can't help myself when I look at the code XC8 generates and so my programs seem to end up being assembly language programs in a C wrapper.

    Caveat! The program is "untested". It's for an "enhanced mid-range" 16F1823 running on INTOSC at 8-MHz, hardware SPI (500-kHz clock), and Vdd = 5v. Hope to test it on real hardware soon.

    Mike
     

    Attached Files:

    Last edited: Jul 15, 2018 at 8:59 AM
    • Like Like x 1
  22. Mike - K8LH

    Mike - K8LH Well-Known Member

    Joined:
    Jan 22, 2005
    Messages:
    3,701
    Likes:
    126
    Location:
    Michigan, USA
    With minor tweaks to the SSD1306 config settings the program runs on real hardware and I've updated the source file in the previous post. It's very "minimal" and probably not a very good example but it's a good starting point (for me) for that Key-chain Domino Calculator (grin)...

    Cheerful regards, Mike

    OLED 0.96 SPI.png
     
    Last edited: Jul 15, 2018 at 9:01 AM
    • Like Like x 1

Share This Page

  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice