Menu

SSD1306 OLED not working

Help
2017-07-22
2017-08-03
  • Joseph Realmuto

    Joseph Realmuto - 2017-07-22

    I've been using GCBasic for the last 8 years. Thus far it's been able to do everything I wanted. I recently purchased several I2C OLED displays on eBay which use the SSD1306 controller. I'm using a PIC18F2420 for testing purposes. I slightly modified one of the demo programs. I know the 18F2420 doesn't have enough RAM, so I reduced the buffer size to 400 bytes. I had read elsewhere that this will at least allow some lines on the display to work. Unfortunately, nothing works. I'm getting a sine wave on the crystal but all the other outputs are inactive. I even put some test LEDs which should light up if the main program is running but they don't. The I2C lines remain high all the time. Basically, it looks like the PIC isn't running the program at all (or it's locking up beforehand). I even tried it using the internal oscillator instead of the crystal. Same result. The microcontroller works fine when I load other programs.

    Any insight would be appreciated. The program compiled with no errors. Here is the full program:

    ; ----- Configuration
    #chip 18F2420,16.777216
    #config OSC=HSPLL, BOREN=OFF, MCLR=ON
        #include <glcd.h>
    
    ; ----- Define Hardware settings
      ' Define I2C settings
      #define HI2C_DATA PORTC.4
      #define HI2C_CLOCK PORTC.3
      Dir HI2C_DATA in
      Dir HI2C_CLOCK in
      #define HI2C_BAUD_RATE 400
      HI2CMode Master
    
      dir PORTB.1 out
      dir PORTC.7 out
    
    ; ----- Define GLCD Hardware settings
      #define GLCD_TYPE GLCD_TYPE_SSD1306
      #define GLCD_I2C_Address 0x78
    
    ; ----- Define variables
    
      Dim BYTENUMBER, CCOUNT as Byte
    
      CCount = 0
      dim longNumber as long
      longNumber = 123456 ' max value = 4294967290
      dim wordNumber as Word
      dim outstring as string
      wordNumber = 0
      byteNumber = 0
    
    ; ----- Main program
    
      set LATB.1 on
      set LATC.7 off
    
      GLCDCLS
      GLCDPrint 0, 0, "Great Cow Basic"
      GLCDPrint (0, 16, "Anobium 2015")
    
      wait 3 s
      GLCDCLS
    
      ' Prepare the static components of the screen
      GLCDPrint ( 0,   0, "PrintStr")                                ; Print some text
      GLCDPrint ( 64,  0, "@")                                    ; Print some more text
      GLCDPrint ( 72,  0, ChipMhz)                                   ; Print chip speed
      GLCDPrint ( 86, 0, "Mhz")                                     ; Print some text
      GLCDDrawString( 0,8,"DrawStr")                                 ; Draw some text
      box 0,0,GLCD_WIDTH-1, GLCD_HEIGHT-1                            ; Draw a box
      box GLCD_WIDTH-5, GLCD_HEIGHT-5,GLCD_WIDTH-1, GLCD_HEIGHT-1    ; Draw a box
      Circle( 44,41,15)                                              ; Draw a circle
      line 64,31,0,31                                                ; Draw a line
    
      DO forever
         for CCount = 31 to 127
              GLCDPrint ( 64 ,  36,  hex(longNumber_E ) )                 ; Print a HEX string
              GLCDPrint ( 76 ,  36,  hex(longNumber_U ) )                 ; Print a HEX string
              GLCDPrint ( 88 ,  36,  hex(longNumber_H ) )                 ; Print a HEX string
              GLCDPrint ( 100 ,  36, hex(longNumber   ) )                 ; Print a HEX string
              GLCDPrint ( 112 ,  36, "h" )                                ; Print a HEX string
    
              GLCDPrint ( 64 ,  44, pad(str(wordNumber), 5 ) )           ; Print a padded string
              GLCDPrint ( 64 ,  52, pad(str(byteNumber), 3 ) )           ; Print a padded string
    
              box (46,9,56,19)                                           ; Draw a Box
              GLCDDrawChar(48, 9, CCount )                               ; Draw a character
              outString = str( CCount )                                  ; Prepare a string
              GLCDDrawString(64, 9, pad(outString,3) )                   ; Draw a string
    
              filledbox 3,43,11,51, wordNumber                           ; Draw a filled box
    
              FilledCircle( 44,41,9, longNumber xor 1)                   ; Draw a filled box
              line 0,63,64,31                                            ; Draw a line
    
                                                                         ; Do some simple maths
              longNumber = longNumber + 7 : wordNumber = wordNumber + 3 : byteNumber++
          NEXT
      LOOP
      end
    
     

    Last edit: Joseph Realmuto 2017-07-22
  • kent_twt4

    kent_twt4 - 2017-07-22

    GCB needs to know what the final Mhz value of the clock is including the PLL. So for say a 10Mhz ext osc it would be #config 18f2420, 10 or #config 18f2420, 40 with the 4x PLL. Values over 10Mhz with the PLL enabled seem to be operating outside the 18f2420 parameters. This is the case with the more vintage 18f's, while the 18fxxk20 and 18fxxk22 devices can go up to 16Mhz with the PLL for a 64Mhz clock.

     
  • Joseph Realmuto

    Joseph Realmuto - 2017-07-22

    I'm using a 4.194304MHz crystal, so the final clock value with the 4x PLL is 16.777216 MHz.

     

    Last edit: Joseph Realmuto 2017-07-22
  • kent_twt4

    kent_twt4 - 2017-07-23

    OK then, thought it might be a timing problem. I do not have the I2C model of the SSD1306, so can't test the reduced ram example.

     
  • Joseph Realmuto

    Joseph Realmuto - 2017-07-23

    For what it's worth I not only tried it with the internal oscillator, but I also tried software I2C, and both slave addresses (0x78 and 0x7A). Same results each time. The I2C lines remained high and it looked like the PIC was either locked up or just not initializing.

     
  • Joseph Realmuto

    Joseph Realmuto - 2017-07-23

    I made some progress. I determined that hardware I2C isn't working properly with the 18F2420 for some reason so I tried software I2C (I forgot to set the ports as inputs last time I tried software I2C). This time instead of limiting the buffer in the SSD1306.h file I changed the chip number to PIC18F2520 which has 1536 bytes of RAM. Surprising, the resulting hex file worked mostly OK when loaded into an 18F2420. It looks like some dots are missing but at least the display is doing something. In the long run I plan to use a chip with enough RAM. I just wanted to see if I can get the display working.

    Here's the program which worked (more or less):

    ; ----- Configuration
      #chip 18F2520,16.777216
      #config OSC=HSPLL, BOREN=OFF, MCLR=ON
      #include <glcd.h>
    
    ; ----- Define Hardware settings
      ' Define I2C settings
    
       #define I2C_MODE Master
       #define I2C_DATA PORTC.4
       #define I2C_CLOCK PORTC.3
       #define I2C_DISABLE_INTERRUPTS ON
       #define I2C_BIT_DELAY 0 us
       #define I2C_CLOCK_DELAY 0 us
       #define I2C_END_DELAY 0 us
       Dir I2C_DATA in
       Dir I2C_CLOCK in
    
    ; ----- Define GLCD Hardware settings
      #define GLCD_TYPE GLCD_TYPE_SSD1306
      #define GLCD_I2C_Address 0x78
    
    ; ----- Define variables
    
      Dim BYTENUMBER, CCOUNT as Byte
    
      CCount = 0
      dim longNumber as long
      longNumber = 123456 ' max value = 4294967290
      dim wordNumber as Word
      dim outstring as string
      wordNumber = 0
      byteNumber = 0
    
    ; ----- Main program
    
      GLCDCLS
      GLCDPrint 0, 0, "Great Cow Basic"
      GLCDPrint (0, 16, "Anobium 2015")
    
      wait 3 s
      GLCDCLS
    
      ' Prepare the static components of the screen
      GLCDPrint ( 0,   0, "PrintStr")                                ; Print some text
      GLCDPrint ( 64,  0, "@")                                    ; Print some more text
      GLCDPrint ( 72,  0, ChipMhz)                                   ; Print chip speed
      GLCDPrint ( 86, 0, "Mhz")                                     ; Print some text
      GLCDDrawString( 0,8,"DrawStr")                                 ; Draw some text
      box 0,0,GLCD_WIDTH-1, GLCD_HEIGHT-1                            ; Draw a box
      box GLCD_WIDTH-5, GLCD_HEIGHT-5,GLCD_WIDTH-1, GLCD_HEIGHT-1    ; Draw a box
      Circle( 44,41,15)                                              ; Draw a circle
      line 64,31,0,31                                                ; Draw a line
    
      DO forever
         for CCount = 31 to 127
              GLCDPrint ( 64 ,  36,  hex(longNumber_E ) )                 ; Print a HEX string
              GLCDPrint ( 76 ,  36,  hex(longNumber_U ) )                 ; Print a HEX string
              GLCDPrint ( 88 ,  36,  hex(longNumber_H ) )                 ; Print a HEX string
              GLCDPrint ( 100 ,  36, hex(longNumber   ) )                 ; Print a HEX string
              GLCDPrint ( 112 ,  36, "h" )                                ; Print a HEX string
    
              GLCDPrint ( 64 ,  44, pad(str(wordNumber), 5 ) )           ; Print a padded string
              GLCDPrint ( 64 ,  52, pad(str(byteNumber), 3 ) )           ; Print a padded string
    
              box (46,9,56,19)                                           ; Draw a Box
              GLCDDrawChar(48, 9, CCount )                               ; Draw a character
              outString = str( CCount )                                  ; Prepare a string
              GLCDDrawString(64, 9, pad(outString,3) )                   ; Draw a string
    
              filledbox 3,43,11,51, wordNumber                           ; Draw a filled box
    
              FilledCircle( 44,41,9, longNumber xor 1)                   ; Draw a filled box
              line 0,63,64,31                                            ; Draw a line
    
                                                                         ; Do some simple maths
              longNumber = longNumber + 7 : wordNumber = wordNumber + 3 : byteNumber++
          NEXT
      LOOP
      end
    
     

    Last edit: Joseph Realmuto 2017-07-23
  • Anobium

    Anobium - 2017-07-23

    Trying to make the OLED work by hacking the buffer array, or limitiing the pixels will not work. The buffer will simply overrun trashing other variables. Just need some RAM. :-)

     
  • Joseph Realmuto

    Joseph Realmuto - 2017-07-23

    Yes, I know that. Any chance of writing a GC Basic driver for low RAM chips? Someone did that here in C: https://www.ccsinfo.com/forum/viewtopic.php?t=54453

     
  • Anobium

    Anobium - 2017-07-23

    Well Yes. I am aware of this approach. We have all the fonts, we could do this.

    It is simply time. The adapation would include revising GLCD.h, the OLED specific driver and potentially the drawing primitives.

    I think it is doable. I think for the Great Cow BASIC driver this is relatively easy. I do not have a OLED with me... so, I cannot test until Mid August.

     
  • Joseph Realmuto

    Joseph Realmuto - 2017-07-23

    If you have time for this then I'll be happy to do some testing for the SSD1306 driver.

     
    • Anobium

      Anobium - 2017-07-23

      I have sent you a Personal Message. :-)

       
  • Anobium

    Anobium - 2017-07-23

    Idea. try #define GLCD_TYPE_SSD1306_32

    This will limit memory usage to 512 bytes and the display to 128 * 32. There may be other side effects - I cannot test.

     
  • stan cartwright

    stan cartwright - 2017-07-25

    I changed these lines in glcd_ssd1306.h
    Dim SSD1306_BufferAlias(512)
    in glcdcls change to
    For SSD1306_BufferLocationCalc = 1 to 512
    for SSD1306_BufferLocationCalc = 0 to 31 step 8
    and this worked if any use to Joseph.

    GLCDCLS
    GLCDDrawString (0,0,"Test")
    line (0,8,32,16,1)
    
     
    • Anobium

      Anobium - 2017-07-25

      Use of the approach / code requires the use of Great Cow BASIC compiler of v0.98.00 or greater.

       
  • Joseph Realmuto

    Joseph Realmuto - 2017-07-25

    That works but it limits you to half the display. I've been playing around and I found a few things which sort of work. I can have a 128 byte buffer and divide the display into 8 pages. When you write to a new page you clear the buffer. This only seems to work with text, and only if the text y positions are 255, 7, 15, 23, 31, 39, 47, and 55. This works fine for a mostly static display (i.e. only one line of text is changing). Here's the code:

    'Hardware settings using I2C
    '  #define GLCD_TYPE GLCD_TYPE_SSD1306
    '  #define GLCD_I2C_Address 0x78
    'Hardware settings using SPI (4Wire,MOSI(D1),SCK(D0),DC,CS)
    '  #define GLCD_TYPE GLCD_TYPE_SSD1306
    '  #define S4Wire_Data
    
    ' 1.01 Added scrollspeed
    ' 1.02 Add soft SPI (Kent Schafer)
    ' 1.03 Revised S4Wire_Data to cater for i2c or hwi2c being used at same time as SPI
    ' 1.04 Revised for performance only. No functional changes
    
    #define SSD1306_SETCONTRAST 0x81
    #define SSD1306_DISPLAYALLON_RESUME 0xA4
    #define SSD1306_DISPLAYALLON 0xA5
    #define SSD1306_NORMALDISPLAY 0xA6
    #define SSD1306_INVERTDISPLAY 0xA7
    #define SSD1306_DISPLAYOFF 0xAE
    #define SSD1306_DISPLAYON 0xAF
    
    #define SSD1306_SETDISPLAYOFFSET 0xD3
    #define SSD1306_SETCOMPINS 0xDA
    
    #define SSD1306_SETVCOMDETECT 0xDB
    
    #define SSD1306_SETDISPLAYCLOCKDIV 0xD5
    #define SSD1306_SETPRECHARGE 0xD9
    
    #define SSD1306_SETMULTIPLEX 0xA8
    
    #define SSD1306_SETLOWCOLUMN 0x00
    #define SSD1306_SETHIGHCOLUMN 0x10
    
    #define SSD1306_SETSTARTLINE 0x40
    
    #define SSD1306_MEMORYMODE 0x20
    #define SSD1306_COLUMNADDR 0x21
    #define SSD1306_PAGEADDR   0x22
    
    #define SSD1306_COMSCANINC 0xC0
    #define SSD1306_COMSCANDEC 0xC8
    
    #define SSD1306_SEGREMAP 0xA0
    
    #define SSD1306_CHARGEPUMP 0x8D
    
    #define SSD1306_EXTERNALVCC 0x01
    #define SSD1306_SWITCHCAPVCC 0x02
    
    ' Scrolling #defines
    #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
    
    #startup InitGLCD_SSD1306
    
    'Setup code for SSD1306 controllers
    #if GLCD_TYPE = GLCD_TYPE_SSD1306
        dim SSD1306_BufferLocationCalc as byte               ' mandated in main program for SSD1306
        dim SSD1306_BufferLocation as byte
    
           If ChipRAM > 256 Then
             Dim SSD1306_BufferAlias(128)
           End if
    
    #endif
    
    '''@hide
    Sub Write_Command_SSD1306 ( in SSD1306SendByte as byte )
    
        #ifdef S4Wire_DATA
    
          CS_SSD1306 = 0
          DC_SSD1306 = 0
          S4Wire_SSD1306 SSD1306SendByte
          DC_SSD1306 = 1
          CS_SSD1306 = 1
          Exit Sub
    
        #endif
    
        #ifdef I2C_DATA
    
          I2CStart
          I2CSend GLCD_I2C_Address
          I2CSend 0x00
          I2CSend SSD1306SendByte
          I2CStop
    
        #endif
    
        #ifdef HI2C_DATA
    
          HI2CStart
          HI2CSend GLCD_I2C_Address
          HI2CSend 0x00
          HI2CSend SSD1306SendByte
          HI2CStop
    
        #endif
    
    End Sub
    
    '''@hide
    Sub Write_Data_SSD1306 ( in SSD1306SendByte as byte )
    
        #ifdef S4Wire_DATA
    
          CS_SSD1306 = 0
          DC_SSD1306 = 1
          S4Wire_SSD1306 SSD1306SendByte
          DC_SSD1306 = 0
          CS_SSD1306 = 1
          Exit Sub
    
        #endif
    
        #ifdef I2C_DATA
    
          I2CStart
          I2CSend GLCD_I2C_Address
          I2CSend 0x40
          I2CSend SSD1306SendByte
          I2CStop
    
        #endif
    
        #ifdef HI2C_DATA
    
          HI2CStart
          HI2CSend GLCD_I2C_Address
          HI2CSend 0x40
          HI2CSend SSD1306SendByte
          HI2CStop
    
        #endif
    
    End Sub
    
    '''@hide
    Sub InitGLCD_SSD1306
        #IFDEF HI2C_DATA
               HIC2INIT
        #ENDIF
        #ifdef S4Wire_DATA
          dir MOSI_SSD1306 Out
          dir SCK_SSD1306 Out
          dir DC_SSD1306 Out
          dir CS_SSD1306 Out
          dir RES_SSD1306 Out
          RES_SSD1306 = 0
          wait 10 us
          RES_SSD1306 = 1
        #endif
        'Setup code for SSD1306 controllers
        'Init sequence for 128x64 OLED module
        Write_Command_SSD1306(SSD1306_DISPLAYOFF)                    ' 0xAE
        Write_Command_SSD1306(SSD1306_DEACTIVATE_SCROLL)
        Write_Command_SSD1306(SSD1306_SETDISPLAYCLOCKDIV)            ' 0xD5
        Write_Command_SSD1306(0x80)                                  ' the suggested ratio 0x80
        Write_Command_SSD1306(SSD1306_SETMULTIPLEX)                  ' 0xA8
        Write_Command_SSD1306(0x3F)
        Write_Command_SSD1306(SSD1306_SETDISPLAYOFFSET)              ' 0xD3
        Write_Command_SSD1306(0x00)                                   ' no offset
        Write_Command_SSD1306(SSD1306_SETSTARTLINE | 0x00)            ' line #0
        Write_Command_SSD1306(SSD1306_CHARGEPUMP)                    ' 0x8D
        if (vccstate = SSD1306_EXTERNALVCC) then
          Write_Command_SSD1306(0x10)
        else
          Write_Command_SSD1306(0x14)
        end if
        Write_Command_SSD1306(SSD1306_MEMORYMODE)                    ' 0x20
        'Write_Command_SSD1306(0x00)                                  ' 0x00 act like ks0108 - DO NOT SELECT!!
        Write_Command_SSD1306(0x10)                                  ' 0x01 act like PCD8544
    
        Write_Command_SSD1306(SSD1306_SEGREMAP | 0x1)
        Write_Command_SSD1306(SSD1306_COMSCANDEC)
        Write_Command_SSD1306(SSD1306_SETCOMPINS)                    ' 0xDA
        Write_Command_SSD1306(0x12)
        Write_Command_SSD1306(SSD1306_SETCONTRAST)                   ' 0x81
        if vccstate = SSD1306_EXTERNALVCC then
          Write_Command_SSD1306(0x9F)
        else
          Write_Command_SSD1306(0xCF)
        end if
        Write_Command_SSD1306(SSD1306_SETPRECHARGE)                  ' 0xd9
        if vccstate = SSD1306_EXTERNALVCC then
          Write_Command_SSD1306(0x22)
        else
          Write_Command_SSD1306(0xF1)
        end if
        Write_Command_SSD1306(SSD1306_SETVCOMDETECT)                 ' 0xDB
        Write_Command_SSD1306(0x40)
        Write_Command_SSD1306(SSD1306_DISPLAYALLON_RESUME)           ' 0xA4
        Write_Command_SSD1306(SSD1306_NORMALDISPLAY)                 ' 0xA6
        Write_Command_SSD1306(SSD1306_DISPLAYON)                     '--turn on oled panel
    
        'Colours
        GLCDBackground = 0
        GLCDForeground = 1
        GLCDFontWidth = 6
        GLCDfntDefault = 0
        GLCDfntDefaultsize = 1
    
        'Clear screen
        GLCDCLS_SSD1306
    
    End Sub
    
    '''Clears the GLCD screen
    Sub GLCDCLS_SSD1306
     ' initialise global variable. Required variable for Circle in all DEVICE DRIVERS- DO NOT DELETE
      GLCD_yordinate = 0
    
      #ifndef GLCD_TYPE_SSD1306_CHARACTER_MODE_ONLY
        For SSD1306_BufferLocationCalc = 1 to 128
            SSD1306_BufferAlias(SSD1306_BufferLocationCalc) = 0
        Next
      #endif
    
      for SSD1306_BufferLocationCalc = 0 to 63 step 8
          for GLCDTemp = 0 to 127
              Cursor_Position_SSD1306 ( GLCDTemp , SSD1306_BufferLocationCalc )
              Write_Data_SSD1306(GLCDBackground)
        Next
      next
    
      Cursor_Position_SSD1306 ( 0 , 0 )
      CurrentPage = 0
      LastPage = 0
    
    End Sub
    
    '''Draws a filled box on the GLCD screen
    '''@param LineX1 Top left corner X location
    '''@param LineY1 Top left corner Y location
    '''@param LineX2 Bottom right corner X location
    '''@param LineY2 Bottom right corner Y location
    '''@param LineColour Colour of box (0 = erase, 1 = draw, default is 1)
    Sub FilledBox_SSD1306(In LineX1, In LineY1, In LineX2, In LineY2, Optional In LineColour As Word = GLCDForeground)
    
      'Make sure that starting point (1) is always less than end point (2)
      If LineX1 > LineX2 Then
        GLCDTemp = LineX1
        LineX1 = LineX2
        LineX2 = GLCDTemp
      End If
      If LineY1 > LineY2 Then
        GLCDTemp = LineY1
        LineY1 = LineY2
        LineY2 = GLCDTemp
      End If
    
      #if GLCD_TYPE = GLCD_TYPE_SSD1306
        'Draw lines going across
        For DrawLine = LineX1 To LineX2
          For GLCDTemp = LineY1 To LineY2
            PSet DrawLine, GLCDTemp, LineColour
          Next
        Next
      #endif
    
    End Sub
    
    '''Draws a pixel on the GLCD
    '''@param GLCDX X coordinate of pixel
    '''@param GLCDY Y coordinate of pixel
    '''@param GLCDColour State of pixel ( GLCDBackground | GLCDForeground )
    Sub PSet_SSD1306(In GLCDX, In GLCDY, In GLCDColour As Word)
    
        'Set pixel at X, Y on LCD to State
        'X is 0 to 127
        'Y is 0 to 63
        'Origin in top left
    
      #if GLCD_TYPE = GLCD_TYPE_SSD1306
    
              SSD1306_BufferLocationCalc = GLCDX + 1
              CurrentPage = GLCDY
              Repeat 3
                Set C Off
                Rotate CurrentPage Right
              End Repeat
              IF CurrentPage <> LastPage THEN
               For SSD1306_BufferLocation = 1 to 128
                SSD1306_BufferAlias(SSD1306_BufferLocation) = 0
               Next
               LastPage = CurrentPage
              END IF
              GLCDDataTemp = SSD1306_BufferAlias(SSD1306_BufferLocationCalc)
              'Change data to set/clear pixel
              GLCDBitNo = GLCDY And 7
              If GLCDColour.0 = 0 Then
                GLCDChange = 254
                Set C On
              Else
                GLCDChange = 1
                Set C Off
              End If
              Repeat GLCDBitNo
                Rotate GLCDChange Left
              End Repeat
    
              If GLCDColour.0 = 0 Then
                 GLCDDataTemp = GLCDDataTemp And GLCDChange
              Else
                 GLCDDataTemp = GLCDDataTemp Or GLCDChange
              End If
              IF SSD1306_BufferAlias(SSD1306_BufferLocationCalc) <> GLCDDataTemp THEN
               SSD1306_BufferAlias(SSD1306_BufferLocationCalc) = GLCDDataTemp
               Cursor_Position_SSD1306 ( GLCDX, GLCDY )
               Write_Data_SSD1306 ( GLCDDataTemp )
              END IF
    
      #endif
    
    End Sub
    
    '''Takes raw pixel positions and translates to XY char positions
    '''@param X coordinate of pixel
    '''@param Y coordinate of pixel
    sub Cursor_Position_SSD1306( in LocX as byte, in LocY as byte )
      dim  PosCharX, PosCharX as Word
    
      ' PosCharY = LocY / 8
      ' faster than /8
      PosCharY = LocY
      Repeat 3
        Set C Off
        Rotate PosCharY Right
      End Repeat
    
      Write_Command_SSD1306( 0xB0 + PosCharY )   ' set page address
      PosCharX = ( LocX  & 0x0f )  ' lower nibble
      Write_Command_SSD1306( PosCharX )
    
      PosCharX = LocX
      Repeat 4
             Set C off
             Rotate PosCharX Right
      End Repeat
      PosCharX = ( PosCharX & 0x0F ) + 0x10
      Write_Command_SSD1306 ( PosCharX )
    
    end sub
    
    '''Stops all scrolling
    sub stopscroll_SSD1306
        Write_Command_SSD1306(SSD1306_DEACTIVATE_SCROLL)
    end sub
    
    '''Activate a right handed scroll for rows start through stop
    ''' Hint, the display is 16 rows tall. To scroll the whole display, run:
    ''' startscrollright_SSD1306(0x00, 0x0F)
    '''@param Start row
    '''@param End row
    '''@param Set time interval between each scroll step in terms of frame frequency
    SUB startscrollright_SSD1306 ( IN start , IN stop, Optional In scrollspeed As byte = 0 )
      Write_Command_SSD1306(SSD1306_RIGHT_HORIZONTAL_SCROLL)
      Write_Command_SSD1306(0X00)
      Write_Command_SSD1306(start)
      Write_Command_SSD1306(scrollspeed)
      Write_Command_SSD1306(stop)
      Write_Command_SSD1306(0X00)
      Write_Command_SSD1306(0XFF)
      Write_Command_SSD1306(SSD1306_ACTIVATE_SCROLL)
    end sub
    
    '''Activate a left handed scroll for rows start through stop
    '''Hint, the display is 16 rows tall. To scroll the whole display, run:
    '''startscrollleft_SSD1306(0x00, 0x0F)
    '''@param Start row
    '''@param End row
    '''@param Set time interval between each scroll step in terms of frame frequency
    SUB startscrollleft_SSD1306 ( IN start , IN stop, Optional In scrollspeed As byte = 0 )
      Write_Command_SSD1306(SSD1306_LEFT_HORIZONTAL_SCROLL)
      Write_Command_SSD1306(0X00)
      Write_Command_SSD1306(start)
      Write_Command_SSD1306(scrollspeed)
      Write_Command_SSD1306(stop)
      Write_Command_SSD1306(0X00)
      Write_Command_SSD1306(0XFF)
      Write_Command_SSD1306(SSD1306_ACTIVATE_SCROLL)
    end sub
    
    '''Activate a diagright handed scroll for rows start through stop
    '''Hint, the display is 16 rows tall. To scroll the whole display, run:
    '''startscrolldiagright_SSD1306(0x00, 0x0F)
    '''@param Start row
    '''@param End row
    '''@param Set time interval between each scroll step in terms of frame frequency
    SUB startscrolldiagright_SSD1306 ( IN start , IN stop, Optional In scrollspeed As byte = 0 )
      Write_Command_SSD1306(SSD1306_SET_VERTICAL_SCROLL_AREA)
      Write_Command_SSD1306(0X00)
      Write_Command_SSD1306(GLCD_HEIGHT)
      Write_Command_SSD1306(SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL)
      Write_Command_SSD1306(scrollspeed)
      Write_Command_SSD1306(start)
      Write_Command_SSD1306(0X00)
      Write_Command_SSD1306(stop)
      Write_Command_SSD1306(0X01)
      Write_Command_SSD1306(SSD1306_ACTIVATE_SCROLL)
    end sub
    
    '''Activate a diagleft handed scroll for rows start through stop
    '''Hint, the display is 16 rows tall. To scroll the whole display, run:
    '''startscrolldiagleft_SSD1306(0x00, 0x0F)
    '''@param Start row
    '''@param End row
    '''@param Set time interval between each scroll step in terms of frame frequency
    SUB startscrolldiagleft_SSD1306 ( IN start , IN stop, Optional In scrollspeed As byte = 0 )
      Write_Command_SSD1306(SSD1306_SET_VERTICAL_SCROLL_AREA)
      Write_Command_SSD1306(0X00)
      Write_Command_SSD1306(GLCD_HEIGHT)
      Write_Command_SSD1306(SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL)
      Write_Command_SSD1306(scrollspeed)
      Write_Command_SSD1306(start)
      Write_Command_SSD1306(0X00)
      Write_Command_SSD1306(stop)
      Write_Command_SSD1306(0X01)
      Write_Command_SSD1306(SSD1306_ACTIVATE_SCROLL)
    end sub
    
    '''Sets the constrast to select 1 out of 256 contrast steps.
    '''Contrast increases as the value increases.
    '''@param Dim byte value
    sub SetContrast_SSD1306 ( in dim_state )
    
      Write_Command_SSD1306(SSD1306_SETCONTRAST)
      Write_Command_SSD1306(dim_state)
    
    end sub
    
    '*********************Software SPI**********************
    
    sub S4Wire_SSD1306(in SSD1306SendByte as byte)
    
      For clocks = 1 to 8
        If SSD1306SendByte.7 = 1 Then
          MOSI_SSD1306 = 1
        Else
          MOSI_SSD1306 = 0
        End if
        Rotate SSD1306SendByte Left Simple
        SCK_SSD1306 = 0
        SCK_SSD1306 = 1
      Next
    
    end sub
    
     

    Last edit: Joseph Realmuto 2017-07-25
  • Joseph Realmuto

    Joseph Realmuto - 2017-07-25

    A second approach if you have more than one line of text which changes regularly is to saved the 128 byte buffer. In this code I can save the last three buffers. This lets me have up to three lines of text which change frequently. This approach uses 512 bytes for buffering so it might not be suitable for a low-RAM chip. I'm still looking for a more universal approach but at least I'm making some progress. Here's the code for this version:

    'Hardware settings using I2C
    '  #define GLCD_TYPE GLCD_TYPE_SSD1306
    '  #define GLCD_I2C_Address 0x78
    'Hardware settings using SPI (4Wire,MOSI(D1),SCK(D0),DC,CS)
    '  #define GLCD_TYPE GLCD_TYPE_SSD1306
    '  #define S4Wire_Data
    
    ' 1.01 Added scrollspeed
    ' 1.02 Add soft SPI (Kent Schafer)
    ' 1.03 Revised S4Wire_Data to cater for i2c or hwi2c being used at same time as SPI
    ' 1.04 Revised for performance only. No functional changes
    
    #define SSD1306_SETCONTRAST 0x81
    #define SSD1306_DISPLAYALLON_RESUME 0xA4
    #define SSD1306_DISPLAYALLON 0xA5
    #define SSD1306_NORMALDISPLAY 0xA6
    #define SSD1306_INVERTDISPLAY 0xA7
    #define SSD1306_DISPLAYOFF 0xAE
    #define SSD1306_DISPLAYON 0xAF
    
    #define SSD1306_SETDISPLAYOFFSET 0xD3
    #define SSD1306_SETCOMPINS 0xDA
    
    #define SSD1306_SETVCOMDETECT 0xDB
    
    #define SSD1306_SETDISPLAYCLOCKDIV 0xD5
    #define SSD1306_SETPRECHARGE 0xD9
    
    #define SSD1306_SETMULTIPLEX 0xA8
    
    #define SSD1306_SETLOWCOLUMN 0x00
    #define SSD1306_SETHIGHCOLUMN 0x10
    
    #define SSD1306_SETSTARTLINE 0x40
    
    #define SSD1306_MEMORYMODE 0x20
    #define SSD1306_COLUMNADDR 0x21
    #define SSD1306_PAGEADDR   0x22
    
    #define SSD1306_COMSCANINC 0xC0
    #define SSD1306_COMSCANDEC 0xC8
    
    #define SSD1306_SEGREMAP 0xA0
    
    #define SSD1306_CHARGEPUMP 0x8D
    
    #define SSD1306_EXTERNALVCC 0x01
    #define SSD1306_SWITCHCAPVCC 0x02
    
    ' Scrolling #defines
    #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
    
    #startup InitGLCD_SSD1306
    
    'Setup code for SSD1306 controllers
    #if GLCD_TYPE = GLCD_TYPE_SSD1306
        dim SSD1306_BufferLocationCalc as byte              ' mandated in main program for SSD1306
        dim SSD1306_BufferLocation as byte
    
           If ChipRAM > 640  Then
             Dim SSD1306_BufferAlias(128)
             Dim SSD1306_BufferAlias_Temp1(128)
             Dim SSD1306_BufferAlias_Temp2(128)
             Dim SSD1306_BufferAlias_Temp3(128)
           End if
    
    #endif
    
    '''@hide
    Sub Write_Command_SSD1306 ( in SSD1306SendByte as byte )
    
        #ifdef S4Wire_DATA
    
          CS_SSD1306 = 0
          DC_SSD1306 = 0
          S4Wire_SSD1306 SSD1306SendByte
          DC_SSD1306 = 1
          CS_SSD1306 = 1
          Exit Sub
    
        #endif
    
        #ifdef I2C_DATA
    
          I2CStart
          I2CSend GLCD_I2C_Address
          I2CSend 0x00
          I2CSend SSD1306SendByte
          I2CStop
    
        #endif
    
        #ifdef HI2C_DATA
    
          HI2CStart
          HI2CSend GLCD_I2C_Address
          HI2CSend 0x00
          HI2CSend SSD1306SendByte
          HI2CStop
    
        #endif
    
    End Sub
    
    '''@hide
    Sub Write_Data_SSD1306 ( in SSD1306SendByte as byte )
    
        #ifdef S4Wire_DATA
    
          CS_SSD1306 = 0
          DC_SSD1306 = 1
          S4Wire_SSD1306 SSD1306SendByte
          DC_SSD1306 = 0
          CS_SSD1306 = 1
          Exit Sub
    
        #endif
    
        #ifdef I2C_DATA
    
          I2CStart
          I2CSend GLCD_I2C_Address
          I2CSend 0x40
          I2CSend SSD1306SendByte
          I2CStop
    
        #endif
    
        #ifdef HI2C_DATA
    
          HI2CStart
          HI2CSend GLCD_I2C_Address
          HI2CSend 0x40
          HI2CSend SSD1306SendByte
          HI2CStop
    
        #endif
    
    End Sub
    
    '''@hide
    Sub InitGLCD_SSD1306
        #IFDEF HI2C_DATA
               HIC2INIT
        #ENDIF
        #ifdef S4Wire_DATA
          dir MOSI_SSD1306 Out
          dir SCK_SSD1306 Out
          dir DC_SSD1306 Out
          dir CS_SSD1306 Out
          dir RES_SSD1306 Out
          RES_SSD1306 = 0
          wait 10 us
          RES_SSD1306 = 1
        #endif
        'Setup code for SSD1306 controllers
        'Init sequence for 128x64 OLED module
        Write_Command_SSD1306(SSD1306_DISPLAYOFF)                    ' 0xAE
        Write_Command_SSD1306(SSD1306_DEACTIVATE_SCROLL)
        Write_Command_SSD1306(SSD1306_SETDISPLAYCLOCKDIV)            ' 0xD5
        Write_Command_SSD1306(0x80)                                  ' the suggested ratio 0x80
        Write_Command_SSD1306(SSD1306_SETMULTIPLEX)                  ' 0xA8
        Write_Command_SSD1306(0x3F)
        Write_Command_SSD1306(SSD1306_SETDISPLAYOFFSET)              ' 0xD3
        Write_Command_SSD1306(0x00)                                   ' no offset
        Write_Command_SSD1306(SSD1306_SETSTARTLINE | 0x00)            ' line #0
        Write_Command_SSD1306(SSD1306_CHARGEPUMP)                    ' 0x8D
        if (vccstate = SSD1306_EXTERNALVCC) then
          Write_Command_SSD1306(0x10)
        else
          Write_Command_SSD1306(0x14)
        end if
        Write_Command_SSD1306(SSD1306_MEMORYMODE)                    ' 0x20
        'Write_Command_SSD1306(0x00)                                  ' 0x00 act like ks0108 - DO NOT SELECT!!
        Write_Command_SSD1306(0x10)                                  ' 0x01 act like PCD8544
    
        Write_Command_SSD1306(SSD1306_SEGREMAP | 0x1)
        Write_Command_SSD1306(SSD1306_COMSCANDEC)
        Write_Command_SSD1306(SSD1306_SETCOMPINS)                    ' 0xDA
        Write_Command_SSD1306(0x12)
        Write_Command_SSD1306(SSD1306_SETCONTRAST)                   ' 0x81
        if vccstate = SSD1306_EXTERNALVCC then
          Write_Command_SSD1306(0x9F)
        else
          Write_Command_SSD1306(0xCF)
        end if
        Write_Command_SSD1306(SSD1306_SETPRECHARGE)                  ' 0xd9
        if vccstate = SSD1306_EXTERNALVCC then
          Write_Command_SSD1306(0x22)
        else
          Write_Command_SSD1306(0xF1)
        end if
        Write_Command_SSD1306(SSD1306_SETVCOMDETECT)                 ' 0xDB
        Write_Command_SSD1306(0x40)
        Write_Command_SSD1306(SSD1306_DISPLAYALLON_RESUME)           ' 0xA4
        Write_Command_SSD1306(SSD1306_NORMALDISPLAY)                 ' 0xA6
        Write_Command_SSD1306(SSD1306_DISPLAYON)                     '--turn on oled panel
    
        'Colours
        GLCDBackground = 0
        GLCDForeground = 1
        GLCDFontWidth = 6
        GLCDfntDefault = 0
        GLCDfntDefaultsize = 1
    
        'Clear screen
        GLCDCLS_SSD1306
    
    End Sub
    
    '''Clears the GLCD screen
    Sub GLCDCLS_SSD1306
     ' initialise global variable. Required variable for Circle in all DEVICE DRIVERS- DO NOT DELETE
      GLCD_yordinate = 0
    
      #ifndef GLCD_TYPE_SSD1306_CHARACTER_MODE_ONLY
        For SSD1306_BufferLocationCalc = 1 to 128
            SSD1306_BufferAlias(SSD1306_BufferLocationCalc) = 0
            SSD1306_BufferAlias_Temp1(SSD1306_BufferLocationCalc) = 0
            SSD1306_BufferAlias_Temp2(SSD1306_BufferLocationCalc) = 0
            SSD1306_BufferAlias_Temp3(SSD1306_BufferLocationCalc) = 0
        Next
      #endif
    
      for SSD1306_BufferLocationCalc = 0 to 63 step 8
          for GLCDTemp = 0 to 127
              Cursor_Position_SSD1306 ( GLCDTemp , SSD1306_BufferLocationCalc )
              Write_Data_SSD1306(GLCDBackground)
        Next
      next
    
      Cursor_Position_SSD1306 ( 0 , 0 )
      CurrentPage = 0
      LastPage = 255
      SavedPage1 = 255
      SavedPage2 = 255
      SavedPage3 = 255
    
    End Sub
    
    '''Draws a filled box on the GLCD screen
    '''@param LineX1 Top left corner X location
    '''@param LineY1 Top left corner Y location
    '''@param LineX2 Bottom right corner X location
    '''@param LineY2 Bottom right corner Y location
    '''@param LineColour Colour of box (0 = erase, 1 = draw, default is 1)
    Sub FilledBox_SSD1306(In LineX1, In LineY1, In LineX2, In LineY2, Optional In LineColour As Word = GLCDForeground)
    
      'Make sure that starting point (1) is always less than end point (2)
      If LineX1 > LineX2 Then
        GLCDTemp = LineX1
        LineX1 = LineX2
        LineX2 = GLCDTemp
      End If
      If LineY1 > LineY2 Then
        GLCDTemp = LineY1
        LineY1 = LineY2
        LineY2 = GLCDTemp
      End If
    
      #if GLCD_TYPE = GLCD_TYPE_SSD1306
        'Draw lines going across
        For DrawLine = LineX1 To LineX2
          For GLCDTemp = LineY1 To LineY2
            PSet DrawLine, GLCDTemp, LineColour
          Next
        Next
      #endif
    
    End Sub
    
    '''Draws a pixel on the GLCD
    '''@param GLCDX X coordinate of pixel
    '''@param GLCDY Y coordinate of pixel
    '''@param GLCDColour State of pixel ( GLCDBackground | GLCDForeground )
    Sub PSet_SSD1306(In GLCDX, In GLCDY, In GLCDColour As Word)
    
        'Set pixel at X, Y on LCD to State
        'X is 0 to 127
        'Y is 0 to 63
        'Origin in top left
    
      #if GLCD_TYPE = GLCD_TYPE_SSD1306
    
              SSD1306_BufferLocationCalc = GLCDX + 1
              CurrentPage = GLCDY
              Repeat 3
                Set C Off
                Rotate CurrentPage Right
              End Repeat
              IF CurrentPage <> LastPage THEN
               For SSD1306_BufferLocation = 1 to 128
               'save current page before clearing buffer
                SSD1306_BufferAlias_Temp3(SSD1306_BufferLocation) = SSD1306_BufferAlias_Temp2(SSD1306_BufferLocation)
                SSD1306_BufferAlias_Temp2(SSD1306_BufferLocation) = SSD1306_BufferAlias_Temp1(SSD1306_BufferLocation)
                SSD1306_BufferAlias_Temp1(SSD1306_BufferLocation) = SSD1306_BufferAlias(SSD1306_BufferLocation)
                SSD1306_BufferAlias(SSD1306_BufferLocation) = 0
                Next
                SavedPage3 = SavedPage2
                SavedPage2 = SavedPage1
                SavedPage1 = LastPage
                LastPage = CurrentPage
               IF CurrentPage = SavedPage1 THEN
                For SSD1306_BufferLocation = 1 to 128
                 SSD1306_BufferAlias(SSD1306_BufferLocation) = SSD1306_BufferAlias_Temp1(SSD1306_BufferLocation)
                Next
               END IF
               IF CurrentPage = SavedPage2 THEN
                For SSD1306_BufferLocation = 1 to 128
                 SSD1306_BufferAlias(SSD1306_BufferLocation) = SSD1306_BufferAlias_Temp2(SSD1306_BufferLocation)
                Next
               END IF
               IF CurrentPage = SavedPage3 THEN
                For SSD1306_BufferLocation = 1 to 128
                 SSD1306_BufferAlias(SSD1306_BufferLocation) = SSD1306_BufferAlias_Temp3(SSD1306_BufferLocation)
                Next
               END IF
              END IF
              GLCDDataTemp = SSD1306_BufferAlias(SSD1306_BufferLocationCalc)
              'Change data to set/clear pixel
              GLCDBitNo = GLCDY And 7
              If GLCDColour.0 = 0 Then
                GLCDChange = 254
                Set C On
              Else
                GLCDChange = 1
                Set C Off
              End If
              Repeat GLCDBitNo
                Rotate GLCDChange Left
              End Repeat
    
              If GLCDColour.0 = 0 Then
                 GLCDDataTemp = GLCDDataTemp And GLCDChange
              Else
                 GLCDDataTemp = GLCDDataTemp Or GLCDChange
              End If
              IF SSD1306_BufferAlias(SSD1306_BufferLocationCalc) <> GLCDDataTemp THEN
               SSD1306_BufferAlias(SSD1306_BufferLocationCalc) = GLCDDataTemp
               Cursor_Position_SSD1306 ( GLCDX, GLCDY )
               Write_Data_SSD1306 ( GLCDDataTemp )
              END IF
    
      #endif
    
    End Sub
    
    '''Takes raw pixel positions and translates to XY char positions
    '''@param X coordinate of pixel
    '''@param Y coordinate of pixel
    sub Cursor_Position_SSD1306( in LocX as byte, in LocY as byte )
      dim  PosCharX, PosCharX as Word
    
      ' PosCharY = LocY / 8
      ' faster than /8
      PosCharY = LocY
      Repeat 3
        Set C Off
        Rotate PosCharY Right
      End Repeat
    
      Write_Command_SSD1306( 0xB0 + PosCharY )   ' set page address
      PosCharX = ( LocX  & 0x0f )  ' lower nibble
      Write_Command_SSD1306( PosCharX )
    
      PosCharX = LocX
      Repeat 4
             Set C off
             Rotate PosCharX Right
      End Repeat
      PosCharX = ( PosCharX & 0x0F ) + 0x10
      Write_Command_SSD1306 ( PosCharX )
    
    end sub
    
    '''Stops all scrolling
    sub stopscroll_SSD1306
        Write_Command_SSD1306(SSD1306_DEACTIVATE_SCROLL)
    end sub
    
    '''Activate a right handed scroll for rows start through stop
    ''' Hint, the display is 16 rows tall. To scroll the whole display, run:
    ''' startscrollright_SSD1306(0x00, 0x0F)
    '''@param Start row
    '''@param End row
    '''@param Set time interval between each scroll step in terms of frame frequency
    SUB startscrollright_SSD1306 ( IN start , IN stop, Optional In scrollspeed As byte = 0 )
      Write_Command_SSD1306(SSD1306_RIGHT_HORIZONTAL_SCROLL)
      Write_Command_SSD1306(0X00)
      Write_Command_SSD1306(start)
      Write_Command_SSD1306(scrollspeed)
      Write_Command_SSD1306(stop)
      Write_Command_SSD1306(0X00)
      Write_Command_SSD1306(0XFF)
      Write_Command_SSD1306(SSD1306_ACTIVATE_SCROLL)
    end sub
    
    '''Activate a left handed scroll for rows start through stop
    '''Hint, the display is 16 rows tall. To scroll the whole display, run:
    '''startscrollleft_SSD1306(0x00, 0x0F)
    '''@param Start row
    '''@param End row
    '''@param Set time interval between each scroll step in terms of frame frequency
    SUB startscrollleft_SSD1306 ( IN start , IN stop, Optional In scrollspeed As byte = 0 )
      Write_Command_SSD1306(SSD1306_LEFT_HORIZONTAL_SCROLL)
      Write_Command_SSD1306(0X00)
      Write_Command_SSD1306(start)
      Write_Command_SSD1306(scrollspeed)
      Write_Command_SSD1306(stop)
      Write_Command_SSD1306(0X00)
      Write_Command_SSD1306(0XFF)
      Write_Command_SSD1306(SSD1306_ACTIVATE_SCROLL)
    end sub
    
    '''Activate a diagright handed scroll for rows start through stop
    '''Hint, the display is 16 rows tall. To scroll the whole display, run:
    '''startscrolldiagright_SSD1306(0x00, 0x0F)
    '''@param Start row
    '''@param End row
    '''@param Set time interval between each scroll step in terms of frame frequency
    SUB startscrolldiagright_SSD1306 ( IN start , IN stop, Optional In scrollspeed As byte = 0 )
      Write_Command_SSD1306(SSD1306_SET_VERTICAL_SCROLL_AREA)
      Write_Command_SSD1306(0X00)
      Write_Command_SSD1306(GLCD_HEIGHT)
      Write_Command_SSD1306(SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL)
      Write_Command_SSD1306(scrollspeed)
      Write_Command_SSD1306(start)
      Write_Command_SSD1306(0X00)
      Write_Command_SSD1306(stop)
      Write_Command_SSD1306(0X01)
      Write_Command_SSD1306(SSD1306_ACTIVATE_SCROLL)
    end sub
    
    '''Activate a diagleft handed scroll for rows start through stop
    '''Hint, the display is 16 rows tall. To scroll the whole display, run:
    '''startscrolldiagleft_SSD1306(0x00, 0x0F)
    '''@param Start row
    '''@param End row
    '''@param Set time interval between each scroll step in terms of frame frequency
    SUB startscrolldiagleft_SSD1306 ( IN start , IN stop, Optional In scrollspeed As byte = 0 )
      Write_Command_SSD1306(SSD1306_SET_VERTICAL_SCROLL_AREA)
      Write_Command_SSD1306(0X00)
      Write_Command_SSD1306(GLCD_HEIGHT)
      Write_Command_SSD1306(SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL)
      Write_Command_SSD1306(scrollspeed)
      Write_Command_SSD1306(start)
      Write_Command_SSD1306(0X00)
      Write_Command_SSD1306(stop)
      Write_Command_SSD1306(0X01)
      Write_Command_SSD1306(SSD1306_ACTIVATE_SCROLL)
    end sub
    
    '''Sets the constrast to select 1 out of 256 contrast steps.
    '''Contrast increases as the value increases.
    '''@param Dim byte value
    sub SetContrast_SSD1306 ( in dim_state )
    
      Write_Command_SSD1306(SSD1306_SETCONTRAST)
      Write_Command_SSD1306(dim_state)
    
    end sub
    
    '*********************Software SPI**********************
    
    sub S4Wire_SSD1306(in SSD1306SendByte as byte)
    
      For clocks = 1 to 8
        If SSD1306SendByte.7 = 1 Then
          MOSI_SSD1306 = 1
        Else
          MOSI_SSD1306 = 0
        End if
        Rotate SSD1306SendByte Left Simple
        SCK_SSD1306 = 0
        SCK_SSD1306 = 1
      Next
    
    end sub
    
     
    • Anobium

      Anobium - 2017-07-25

      Use of the approach / code requires the use of Great Cow BASIC compiler of v0.98.00 or greater.

       
  • Anobium

    Anobium - 2017-07-25

    I will create a very low memory driver for the SSD1306 in August 2017. Use of the approach / code will require the use of Great Cow BASIC compiler of v0.98.00 or greater, so, I will update this posting when I have completed testing.

    The driver should include a set of full capabilities that we have today - including full screen circles and full font support. It will be 8 pages using a 128byte buffer. I think this is easy doable.

    Anobium

     
  • stan cartwright

    stan cartwright - 2017-07-25

    How to do circles and lines. I suppose I'd keep track of the plot x,y. Draw in 1 buffer then at a point on the screen use buffer2 for write/map next row of 128 bytes because the bytes on display remain.
    Would 256 bytes ram minimum for 2 buffers work?
    My first thoughts was get a chip with more memory but I can see it would be useful if lower memory chips could be used.

     
    • Anobium

      Anobium - 2017-07-25

      @Stan. We are working on a solution. We can make this work as this is a good additional to the capabiliites.

       
  • Joseph Realmuto

    Joseph Realmuto - 2017-07-25

    I managed to get a low RAM text only driver working with Anobium's help. It works well, updates changing fields much faster than my prior attempts, and doesn't force me to start the text only on certain lines. The complied demo only uses 136 bytes! Here's a picture of it in action:

     
  • stan cartwright

    stan cartwright - 2017-07-25

    Excellent Joseph. I've scratched my head as for graphics and first thought it would need two 128 byte buffers.Then when I thought more my head hurt. Since you can't read the screen, I can't see how to do it. Mid point circle algo plot point jumps around the screen when drawing a circle and I just can't "see/imagine" a method to do it.

     
  • Joseph Realmuto

    Joseph Realmuto - 2017-07-25

    I went through the same thought exercise myself. Can't really see a way to do it. About the only possibility I see for low RAM chips is to define a graphics window whose size is based upon how much RAM you have available. For example, you might define a window maybe 64 pixels wide and 32 pixels high. This would need a buffer of 64 * 32 / 8, or 256 bytes. You could put this window anywhere you want on the display. Anything you draw outside the window would be rejected. You would still be able to use the remainder of the display for text. Of course, this would require a major rewrite of the graphics routines. The bottom line though is it looks like you can use low RAM chips if all you want is text. If you want graphics, at best you can only use a portion of the display, and that's assuming the graphics routines were heavily modified.

     

Log in to post a comment.