This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

SSD1308 I2C OLED - Stellaris driver API

Hi,

I have written a driver API for SSD1308 based I2C OLEDs (can be used with SSD1306 too with no/only minor changes in the initialization routine) which I will use for my C3ii INS Stellaris Booster Pack (http://e2e.ti.com/group/microcontrollerprojects/m/msp430microcontrollerprojects/664688.aspx).

The driver is comparable to the 'Simple Display' example from the EVALBOT.

The API relies on my Stellaris I2C driver which you can find here: http://e2e.ti.com/support/microcontrollers/stellaris_arm_cortex-m3_microcontroller/f/473/t/235926.aspx.

The API allows displaying:

1.) Images (black&white)

The image needs to be a black&white .BMP-Image file which must be converted into a data array for use with the API. A little programm called 'LCDAssistent' is included in the attached .zip file which can be used for this task.

2.) Centered Text

3.) Strings

4.) It makes use of an undocumented SSD1306/1308 command called 'Double-Size-Font' (0xD6). 

After receiving this command, the SSD1308 OLED controller displays  each scan line of the first 4 text lines twice. This is resulting in a font which is 2 pages tall.

Using the 0xD6 command will not affect/alter the content of the SSD1308 GDDRAM! When in 'Double-Size-Font'-Mode, the 'Set Display Start Line' command is used to display the pages PAGE4 to PAGE7.

  
Initial display content

  
Double-Size-font Mode swirtched ON

  
display Start Line set to 0x32 (start of PAGE4)

  
Double-Size-Font Mode switched OFF and Display Start Line set back to 0x40 (beginning of the PAGE1)

EDIT (01/18/2012):

Added a new version of my I2C OLED API! The r03-release includes some new functions:

 // Clears a partial row on the OLED display.
void Display128x64x1ClearArea(unsigned long ulI2CBase, unsigned long ulXStart, unsigned long ulXEnd, unsigned long ulY)

 // Displays a length-restricted string on the OLED display at the current cursor position.
void Display128x64x1StringCurrentPos(unsigned long ulI2CBase, const char *pcStr, unsigned long ulLen)

 // Set the Cursor to the specified position on the OLED display (GDDRAM address).
void Display128x64x1SetCursor(unsigned long ulI2CBase, unsigned long ulX, unsigned long ulY)

// A simple I2C based printf function supporting \%c, \%d, \%p, \%s, \%u, \%x, and \%X for use with OLED displays.
void I2COLEDprintf(const char *pcString, ...)

Here is the latest revison of the driver API: 

http://e2e.ti.com/cfs-file.ashx/__key/communityserver-discussions-components-files/473/0724.I2C-OLED-128x64-_2D00_-API_5F00_r03.zip

Please report any issues or improvements! Have fun with your OLED.

Kind regards
aBUGSworstnightmare 

  • @ Bug-Free Zone:

    Good job - very nice photos - especially like your "crack" of the hidden, "double size" font. 

    Believe your inclusion of bmp processing and text centering add much value.

    As a, "Display Guy" may I add few items to your, "Bug-Free, To Do List?"

    a) 2nd size font (not necessarily double height/width) which may "share" the current screen along w/ font_size_1.  Great for "Titles" and other emphasis.  (not achievable via 0XD6 - unfortunately)

    b) function to enable, "Selective Erasure" of individual text rows and/or screen rectangular areas. 

    c) Non-gray scale displays - such as the one shown - are extremely limited in the bmp content they can display.  (i.e. most all bmp/jpg images - even Black/White - contain gray-scale)  Suggest that you better emphasize this limitation - to prevent user frustration.  ("solution" (non-gray to gray-scale: far beyond abilities of this reporter)

    d) Model Number and Supplier/Source of this OLED would further encourage use...

  • cb1- said:
    a) 2nd size font (not necessarily double height/width) which may "share" the current screen along w/ font_size_1.

    I will think about adding a second font. If it can be done quickly I will implement one. Otherwise, you'll have to wait until I've added the function to allow use of Stellaris Graphics Library.

    cb1- said:
    b) function to enable, "Selective Erasure" of individual text rows and/or screen rectangular areas. 

    void Display128x64x1ClearLine(unsigned long ulI2CBase, unsigned long ulY) is used for clearing a whole line (page). I will expand it's functionality so it allows clearing a partial page.

    Since this simple driver uses Page Addressing Mode only you will have to combine multiple call of this function for clearing an area.

    cb1- said:
    c) Non-gray scale displays - such as the one shown - are extremely limited in the bmp content they can display.  (i.e. most all bmp/jpg images - even Black/White - contain gray-scale)  Suggest that you better emphasize this limitation - to prevent user frustration.  ("solution" (non-gray to gray-scale: far beyond abilities of this reporter)

    Well, you're right! But, since this is a single colour OLED (means pixel ON or OFF) you can't display 'real' .BMP images, only Black&white ones. .BMP is only mentioned here since it's the image file format which is needed for working with LCDAssistant. I will change this in the initial post to make it clear!

    cb1- said:
    d) Model Number and Supplier/Source of this OLED would further encourage use...

    This disappeared somehow! The display shown/used is a 0.96in 128x64pixels white OLED from WIDE.Hk. Here's the link to the product page: http://www.wide.hk/products.php?product=I2C-0.96%22-OLED-display-module-%28-compatible-Arduino-%29

    Rgds
    aBUGSworstnightmare 

  • @ Bug:

    Merci mon ami - you are both a habitual "contributor" - and an extremely responsive (& detailed) one.  Again - Bravo! for this - your most recent contribution.

    I would think that you'd add great "flexibility" to this concept if, sometime, (down the road) you'd consider adding the far better known/established 128x64 (small, 2.5" diagonal) backlit Lcd.  Suggestion based upon the vastly increased viewing area of the Lcd - which makes the screen visible from a greater distance - and easier to read for those of us who've "clocked" 50 or so...  Also - multiple, long established sources - just in case.

    Realize that each/every SW function - appropriate to the OLED - must be re-written for this Lcd.  (i.e. display driver changes)  However - rotating this proposed Lcd into "Portrait Mode" - yields 16 rows of 5x7 matrix characters.  (10 such char/row)  Yields a great deal of useful, Engineering/Programming data - all in a comfortable format.  "Kicker" here is most all such Lcds have 8 bit, parallel bus (+ strobes, /CS) - you'd have to add small MCU as, "front end" for the Lcd - or "harness" these 11 or so signals from the ARM. 

    Can reinforce the "case" for such I2C MCU as "front end" for such a display(s) - it can expand to include, "Switch Read" - thus an entire, Operator Front Panel can be created - all managed via a single I2C port.  Switch detection may trigger an interrupt of the main MCU - causing it to service this I2C Slave for, "Switch Data."

    Offer this not to, "make you crazy" - but hopefully to identify means to make your project even more compelling...

    Again - thanks for all of your efforts - will be interesting to see just "how many" here "latch on" to your scheme...

     

  • Hi cb1,

    well, I think the next display do deal with will be a small TFT ;-)!

    But - maybe you recall one of our prior conversions - what do you think about these lines:

        uccount = 170;

        Display128x64x1SetCursor(I2CTELEMETRIEBUS, 20, 0);

        I2COLEDprintf("uccount = %4d", uccount);

        Display128x64x1SetCursor(I2CTELEMETRIEBUS, 0, 1);

        I2COLEDprintf("uccount = 0x%x", uccount);

    Yes, your right! The 'I2COLEDprintf()' is ready and functional! Will take some pictures, clean the sources (comments) and update the post!

    aBUGSworstnightmare 

  • @ Bug:

    Small TFT may indeed be superior to earlier suggested (again Mono) 128x64.  As the 128x64 is 2.5" diag. - low-cost QVGA TFT's are available in 2.2, 2.4 and 2.8" (diag.).  Each/every one of these usually include either a D_Bus or SPI interface - but beware - some use the SPI "just" for key Register programming.  And - getting valid color data to fill such QVGA via serial - before "the sun sets" - may prove a challenge.  Separate ARM (my favor - new M0) serving as display "front-end" offers many advantages.

    Your code appears to direct the cursor to two different, screen locations - then prints uccount - first in decimal - later in hex.  (I'd expect that uccount would undergo some operation to warrant such, "multiple appearance" - but none is shown here!) 

    The use of a reasonable color capacity TFT (or OLED) "opens up" the full spectrum of "existing" color photos, logos, bit-maps, drawings - to your display.  As you know - size balloons when using bmp as opposed to jpg - you'll not be able to fit too many such images if you choose the MCU as storage medium - unless you can "crack" small MCU "jpg handling..."

  • cb1- said:
    Your code appears to direct the cursor to two different, screen locations - then prints uccount - first in decimal - later in hex.  (I'd expect that uccount would undergo some operation to warrant such, "multiple appearance" - but none is shown here!) 

    The code is a simple test to verify that the write formatters were working correctly. Here's a (bad) picture showing what happens on the OLED after doing these two calls of 'I2COLEDprintf()':

    Here's an excerpt from the comments:

    ...

    //! A simple I2C based printf function supporting \%c, \%d, \%p, \%s, \%u,
    //! \%x, and \%X for use with OLED displays.
    ...

    //! - \%c to print a character
    //! - \%d or \%i to print a decimal value
    //! - \%s to print a string
    //! - \%u to print an unsigned decimal value
    //! - \%x to print a hexadecimal value using lower case letters
    //! - \%X to print a hexadecimal value using upper case letters 
    //! - \%p to print a pointer as a hexadecimal value
    //! - \%\% to print out a \% character
    //!
    //! For \%s, \%d, \%i, \%u, \%p, \%x, and \%X, an optional number may reside
    //! between the \% and the format character, which specifies the minimum number
    //! of characters to use for that value; if preceded by a 0 then the extra
    //! characters will be filled with zeros instead of spaces.  For example,
    //! ``\%8d'' will use eight characters to print the decimal value with spaces
    //! added to reach eight; ``\%08d'' will use eight characters as well but will
    //! add zeroes instead of spaces.

    Rgds
    aBUGSworstnightmare 

     

  • Well ok - those "convenience, addressing functions" have long been a mainstay w/in the Graphic Controller market.  You've been around - you may get some additional ideas from SSD1963 TFT/LCD Control IC - powerful, capable and flexible.  (supports to 800x480, color pixels - this for your future "dive" into color) 

    You have mentioned your intention to move toward small TFT - likely w/on-board Controller.  These do save some cost - but condemn you/your users to small QVGA - forever!  TFT's w/out such "limited control" ICs aboard are most always less expensive - and then your, "Bug-Free" special may support TFTs ranging from 3.5 - 8.0" with practically no redesign on your end.  (slight initialization changes of SSD1963 - to accommodate pixel arrays - perhaps some color register tweaks - too)

    My belief (after having been in this field (w/some success) for substantial period) is that, "Design once - Market many times" most always trumps design again - and again - and again...  You will note that GPS and many "in vehicle, entertainment" displays started w/3.5" - and most all quickly shifted to 4.3 and now 5-7" size.  SSD1963 supports each/every one - the limited control IC on 2.2-2.8" supports none...

    As you have (so far) avoided the bmp vs jpg issue - be prepared to support the massive file sizes demanded by full-screen, color, bmp images.  And - the time to "fill the screen" via I2C - may prove unsettling.  (recall there are 76,800 pixels in QVGA display - if you seek beyond 8 bit (256 colors) you'll need to pass 2 bytes/pixel - I2C selection may be sub-optimal in such case)  (thus my suggestion earlier - 128x64 mono Lcd)

  • Hi,

    I've uploaded the new r03-revision of my I2C OLED driver API today. Please refer to post #1 for details/download link.

    aBUGSworstnightmare

  • Hi,

    I'd like to connect my oled display to my stellaris so your driver would save me alot of work but when I click on the link it says: 403 - Forbidden: Access is denied.

    Do I need some special privileges to view the driver? If so, could you give me a start in how to develop it? I've already written a small python script for the RPI and my display that works fine but it uses a python dictionary and.. well c++ doesn't have dictionaries.. ugh.

    How do you provide the character map? Yes, I'm not a C++ Pro!

    ps: I've already connected the display and configured the master. Basic commands like turning on and off, flipping the display and so on do work. Only the character map and drawing the characters is giving me a hard time.

  • Hi Bart,

    TI changed the Forum because of Stellaris-->Tiva change; looks like  some of the contents got lost!

    Find the I2C driver API and the OLED driver enclosed. 

    The character map is placed in flash; you can create your own one (if you have the patience too).

    Kind regards
    aBUGSworstnightmare

    http://e2e.ti.com/cfs-file.ashx/__key/communityserver-discussions-components-files/908/3666.I2C_5F00_Stellaris_5F00_API_5F00_r02.zip

    http://e2e.ti.com/cfs-file.ashx/__key/communityserver-discussions-components-files/908/0385.I2C-OLED-128x64-_2D00_-API_5F00_r03.zip 

  • Hi aBUGSworstnightmare,

    Looking at your driver this means you can only display graphics that have been made with the LCDprog?
    So displaying realtime info (like a clock or sensordata) would not work?

    In Python I made a character map like this:

    charmap = {
            ' ':[0x00, 0x00, 0x00, 0x00, 0x00],
            '!':[0x00, 0x00, 0x5F, 0x00, 0x00],
            '"':[0x00, 0x07, 0x00, 0x07, 0x00],
            ...
    }

    with functions to draw the character:

    def oled_drawChar(c):
            charm = dict(charmap)
            for k in range(0,5):
                    bus.write_byte_data(a, 0x40, charm[c][k])
            bus.write_byte_data(a, 0x40, 0x00)

    def oled_write(word):
            for c in word:
                    oled_drawChar(c)

    With this I could give realtime info on my oled display (clock, ip,...) but on my Stellaris I'm already stuck at translating the Python Dictionary to C++...
    How could I tackle this so that I can keep the same (more or less) approach in displaying characters?

    With kind regards,

    Bart


  • Hi Bart,

    there are functions to deal with graphics (i.e. the two examples enclosed; LCDPROG was used to generate the data array) and with text.

    It's a simple printf approach --> supporting \%c, \%d, \%p, \%s, \%u, \%x, and \%X

    void I2COLEDprintf(const char *pcString, ...) will be the 'function of your choice'.

    There is an example in how to use it shown above. Too bad that the pictures were gone.

    aBUGSworstnightmare

  • I forgot to mention: search for C3ii INS Booster Pack to See the driver in action. Those pics were still there.

    And: the character parser (your Phyton Dictionary) is included in I2COLEDprintf.

  • Thank you very much!

    Going through your code and it's really impressive!!

  • Hi aBUGSworstnightmare,

    I tried to download your library and convert some definitions to port them to new tiva launchpad, but this not work as I expected, i changed the I2C base address:

    I2C0_MASTER_BASE ----> I2C0_BASE

    And I removed the ROM_ prefix from the i2c functions, can you tell me what i need to change to use this in the SSD1306 on the new Tiva Launchpad? I have attached the project and library in the post.

    Att. Ânderson I. Silva 

    Brazil

    tiva_oled_ssd1306.rar
  • Hi, I know this was asked some time ago.

    You need to initialize the I2C ports, with this I2C library this is done by:

    I2CSetup(I2C0_BASE,true);

    Where "true" signifies 400kHz operation

    When this is done it works just fine. Prints "2131" in the lower left corner.

    Note that the y-coordinate of 10 is outside the display size. Y-coordinates are given in lines, and the display is 6 lines tall.


    Best regards, 
    Søren