Adafruit SSD1306 Library [Ported]

This rocks! Just playing around tonight... Spark Core is kickin' this SSD1306 OLED Display in the Apple-Dollar-Dollar-sign.


Mother Futhin' Graphics library? Heck yeah... actually I don't know what you mean... :smile:

3 Likes

@BDub, I created the multi-font (mf) GFX library that allows you to define your own fixed-height/variable width fonts from ttf fonts and use them instead of the single GLCDFONT found in the regular GFX library. The mfGF library, like the GFX library is designed to work with any Adafruit display “driver” like the SSD1306 one you did. I have several other working drivers for the ST7735, ILI9341, SSD1351, etc. The idea is to publish the single mfGFX library with ALL supported display drivers as a single library on the IDE. That’s what I was talking about :smile:

Interesting… first off… a long time ago I created an LCD Font for product manuals that emulates the exact 5 x 7 (or 8)? characters of a typical 16 x 2 LCD. I called it DOT40. I was recently thinking of emulating a 16 x 2 character LCD with this tiny 128 x 32 OLED … there is enough pixels there to do the job, and then some. So your method of converting TTF fonts could be pretty interesting… but now that I think of it, The size 1 font is basically this 5 x 7/8 character already. And it is emulating a 21 x 4 character LCD. Double size (size 2) is a 10 x 2 character LCD.

re: mfGFX, If you could make it so that you only build and include code for the specific display/driver you need, this would be really cool. Obviously you’d have to be able to do this without requiring someone to modify the .h files. I think if you just break everything out in it’s own Class, it will naturally work itself out. Is there a better way?

@BDub, the idea of creating a single huge mfGFX/driver library is interesting but it may be more work than necessary. First, combining everything means updates to each driver would be more difficult. Second, are there any benefits? The u8glib graphics library does something like that and it is a royal pain the the but to maintain and work with. What could be simpler than picking a driver, add mfGFX and Bob’s your uncle! :smile:

True, and if you publish it to the Spark libraries then you have a great responsibility to keep it so fresh and so clean clean. So now you’ve talked me out of it… just publish separate libraries for the individual drivers, and perhaps all you need to do is publish some purely example libraries (minus the library)… hmm, there is that Example projects area that is just kind of dead at the moment. Perhaps that could look more like the Spark Libraries?

@BDub, I guess I could publish each display driver with “mfGFX” appended to the name to be clear that they are modified to work with the mfGFX library. One thing I would like to see as a way to organize libraries by category like displays, sensors, etc.

Sorry for resurrecting this thread but I wanted to share how I got my 128x32 i2c OLED running. Although it’s kind of simple, I created a new gist of what should be in your sketch on the webIDE here: https://gist.github.com/callil/72da1d334d7ab47a65b9 — thanks @peekay123 for the code

note that simply adding the library files to your sketch doesn’t fully work. In Adafruit_SSD1306.h you have to change

#define SSD1306_128_64
//#define SSD1306_128_32

to

//#define SSD1306_128_64
#define SSD1306_128_32

it’s super simple, however, if you “include” the library from the list on the webIDE it doesn’t seem to let you edit that file. My workaround is to copy and past all the content from
Adafruit_SSD1306.h
Adafruit_SSD1306.cpp
Adafruit_GFX.h
Adafruit_GFX.cpp

into new tabs of the same name and only then will you be able to edit that line.

3 Likes

I’m trying to use the ported libraries and have added them and they compile fine. But when I try to compile the INO which is based on the ssd1306_128x64_i2c.ino example I get compile errors. I’ve stripped the INO code and the problem seems to be something to do with the Adafruit_SSD1306 display(OLED_RESET); line as the errors occur whenever later lines refer to display. Can anyone help suggest where I am going wrong?

The cut down code is as follows:

// This #include statement was automatically added by the Spark IDE.
#include "Adafruit_GFX.h"
// This #include statement was automatically added by the Spark IDE.
#include "Adafruit_SSD1306.h"

#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);

void setup()   {                
  Serial.begin(9600);
  // by default, we'll generate the high voltage from the 3.3v line internally! (neat!)
  display.begin(SSD1306_SWITCHCAPVCC, 0x3D);  // initialize with the I2C addr 0x3D (for the 128x64)
  // init done

  // Show image buffer on the display hardware.
  // Since the buffer is intialized with an Adafruit splashscreen
  // internally, this will display the splashscreen.
  display.display();
  delay(2000);
}

void loop() {  
}

and the compile errors are:

In file included from …/inc/spark_wiring.h:29:0,
from …/inc/application.h:29,
from i2coled.cpp:3:
…/…/core-common-lib/SPARK_Firmware_Driver/inc/config.h:12:2: warning: #warning “Defaulting to Release Build” [-Wcpp]
#warning “Defaulting to Release Build”
^
i2coled.o: In function setup': /spark/compile_server/shared/workspace/3_compile-server2/core-firmware/build/i2coled.cpp:16: undefined reference toAdafruit_SSD1306::begin(unsigned char, unsigned char)’
/spark/compile_server/shared/workspace/3_compile-server2/core-firmware/build/i2coled.cpp:22: undefined reference to Adafruit_SSD1306::display()' i2coled.o: In function__static_initialization_and_destruction_0’:
/spark/compile_server/shared/workspace/3_compile-server2/core-firmware/build/i2coled.cpp:9: undefined reference to `Adafruit_SSD1306::Adafruit_SSD1306(signed char)'
collect2: error: ld returned 1 exit status
make: *** [3615a0f5cb7c658393809d6decb9e585e886553aa82cc990b65bb338edb3.elf] Error 1

I figured out the first mistake I have done which is not to copy the cpp files (I only copied the .h files). Apologies for the post. Still not getting everything to compile yet but might be able to work it out.

My final glitch was around the following lines with the random variable. The IDE seemed to be picking up the rand part as something built in.

int random(int maxRand) {
    return rand() % maxRand;

}

To fix I just changed it to rndom (and all re references to it) and then it all compiled ok

int rndom(int maxRand) {
    return rand() % maxRand;
}

The random () error occurred because newer versions of the firmware now define it. :slight_smile:

Hello all,
first of all fanastic post, @peekay123 great work,
I’m new to spark, and this helped me to understand way of porting arduino projects.
Now I’m trying to port oscilloscope project with Adfafruit SSD1306 library, but facing problem with following:
Wire.h; pgmspace.h; SPI.h

thats the link to project, (I’m running it currently on arduino but feels a bit sluggish)
http://www.iforce2d.net/arduinoOscilloscope.txt

any suggestions please?

@Rafal, both SPI and Wire are built in to the Core firmware so comment out those lines . I don’t see any reference to pgmspace however.

@peekay123 hm… right, i did as you advised, but still having minor problems with Adafruit SSD1306, can you please look on it?

In file included from ../inc/spark_wiring.h:29:0,
from ../inc/application.h:29,
from Adafruit_GFX.h:4,
from Adafruit_GFX.cpp:34:
../../core-common-lib/SPARK_Firmware_Driver/inc/config.h:12:2: warning: #warning "Defaulting to Release Build" [-Wcpp]
#warning "Defaulting to Release Build"
^
In file included from ../inc/spark_wiring.h:29:0,
from ../inc/application.h:29,
from Adafruit_GFX.h:4,
from Adafruit_SSD1306.cpp:19:
../../core-common-lib/SPARK_Firmware_Driver/inc/config.h:12:2: warning: #warning "Defaulting to Release Build" [-Wcpp]
#warning "Defaulting to Release Build"
^
In file included from SPI.cpp:11:0:
pins_arduino.h:28:22: fatal error: pgmspace.h: No such file or directory
#include <pgmspace.h>
^
compilation terminated.
make: *** [SPI.o] Error 1

@peekay123 please find below code:

#include "Adafruit_SSD1306.h"
#include "Adafruit_GFX.h"
#include "application.h"

/*
This is set up to use a 128x64 I2C screen, as available
here: http://www.banggood.com/buy/0-96-oled.html
For wiring details see http://youtu.be/XHDNXXhg3Hg
*/


// If using software SPI (the default case):
#define OLED_MOSI   D0
#define OLED_CLK    D1
#define OLED_DC     D2
#define OLED_CS     D3
#define OLED_RESET  D4
Adafruit_SSD1306 display(OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);

#if (SSD1306_LCDHEIGHT != 64)
#error("Height incorrect, please fix Adafruit_SSD1306.h!");
#endif

/********************************************/

#define CHARWIDTH           5
#define CHARHEIGHT          8
#define AXISWIDTH           (2 + 1)                   // axis will show two-pixel wide graph ticks, then an empty column
#define VISIBLEVALUEPIXELS  (128 - AXISWIDTH)         // the number of samples visible on screen
#define NUMVALUES           (2 * VISIBLEVALUEPIXELS)  // the total number of samples (take twice as many as visible, to help find trigger point

#define TRIGGER_ENABLE_PIN       2  // set this pin high to enable trigger
#define SCREEN_UPDATE_ENABLE_PIN 3  // set this pin high to freeze screen

byte values[NUMVALUES];           // stores read analog values mapped to 0-63
int pos = 0;                      // the next position in the value array to read
int count = 0;                    // the total number of times through the loop
unsigned long readStartTime = 0;  // time when the current sampling started
int sampleRate = 1;              // A value of 1 will sample every time through the loop, 5 will sample every fifth time etc.

/********************************************/

// Draws a printf style string at the current cursor position
void displayln(const char* format, ...)
{
  char buffer[32];
  
  va_list args;
  va_start(args, format);
  vsprintf(buffer, format, args);
  va_end(args);
  
  int len = strlen(buffer);
  for (uint8_t i = 0; i < len; i++) {
    display.write(buffer[i]);
  }
}

// Draws the graph ticks for the vertical axis
void drawAxis()
{  
  // graph ticks
  for (int x = 0; x < 2; x++) {
    display.drawPixel(x,  0, WHITE);
    display.drawPixel(x, 13, WHITE);
    display.drawPixel(x, 26, WHITE);
    display.drawPixel(x, 38, WHITE);
    display.drawPixel(x, 50, WHITE);
    display.drawPixel(x, 63, WHITE);  
  }
}

// Draws the sampled values
void drawValues()
{
  int start = 0;
  
  if ( digitalRead(TRIGGER_ENABLE_PIN) ) {
    // Find the first occurence of zero
    for (int i = 0; i < NUMVALUES; i++) {
      if ( values[i] == 0 ) {
        // Now find the next value that is not zero
        for (; i < NUMVALUES; i++) {
          if ( values[i] != 0 ) {
            start = i;
            break;
          }
        }
        break;
      }
    }    
    // If the trigger point is not within half of our values, we will 
    // not have enough sample points to show the wave correctly
    if ( start >= VISIBLEVALUEPIXELS )
      return;
  }
  
  for (int i = 0; i < VISIBLEVALUEPIXELS; i++) {
    display.drawPixel(i + AXISWIDTH, 63 - (values[i + start]), WHITE);
  }
}

// Shows the time taken to sample the values shown on screen
void drawFrameTime(unsigned long us)
{
  display.setCursor(9 * CHARWIDTH, 7 * CHARHEIGHT - 2); // almost at bottom, approximately centered
  displayln("%ld us", us);
}

/********************************************/

void setup() {

  // Set up the display
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // Initialize with the I2C addr 0x3D (for the 128x64)
  display.setTextColor(WHITE);

  pinMode(TRIGGER_ENABLE_PIN, INPUT);
  pinMode(SCREEN_UPDATE_ENABLE_PIN, INPUT);
}

/********************************************/

void loop() {
  
  // If a sampling run is about to start, record the start time
  if ( pos == 0 )
    readStartTime = micros();
  
  // If this iteration is one we want a sample for, take the sample
  if ( (++count) % sampleRate == 0 )
    values[pos++] = analogRead(0) >> 4; // shifting right by 4 efficiently maps 0-1023 range to 0-63

  // If we have filled the sample buffer, display the results on screen
  if ( pos >= NUMVALUES ) {
    // Measure how long the run took
    unsigned long totalSampleTime = (micros() - readStartTime) / 2;     // Divide by 2 because we are taking twice as many samples as are shown on the screen
 
    if ( !digitalRead(SCREEN_UPDATE_ENABLE_PIN) ) {
      // Display the data on screen   
      display.clearDisplay();
      drawAxis();
      drawValues();
      drawFrameTime(totalSampleTime);
      display.display();
    }
       
    // Reset values for the next sampling run
    pos = 0;
    count = 0;
  }
}

@Rafal, you have to give me a little more detail here:

  • Are you using the web IDE to compile the code?
  • If so, did you add the Adafruit_GFX and Adafruit_SSD1306 libraries to your app?
  • Are you using I2C, hardware or software SPI for the display?

@peekay123, first of all thank you for you help,

  • yes I’m using web IDE to compile the code,
  • and as in this topic, I did have added Adafeuit_GFX and Adafruit_SSD1306. (before i have done exactly as here, I did ported Adafruit SSD1306 Lib for test, and positive, Adafruit animation works)
  • I’m using SPI OLED, and did this one with arduino pro mini - no problem, for Spark I have implemented pinouts as in this post.

if this will work, I’m planing bring more sophisticated two channel oscilloscope with integrated wave generator, (useful for basic hoppy need).

@Rafal, first I suggest you use Spark DEV. It will make it easier to work with multiple files and avoid some of the quirks of the (existing) web IDE. I think the best thing to do at this stage is to understand the source of all your files. Can you list the files you have included in your IDE application and the libraries you attached to your app or added as tabs?

If you install Spark DEV, I can create a full set of working files for you that you can copy to a single directory on you PC to compile. Keep me posted. :smile:

@peekay123, :slight_smile: thats very kind of you.
Now I’m running Spark DEV on mac and looks promising (: , libraries which i did included was only Adafruit_GFX; Adafruit_SSD1306, will give it try again.
Originally it contain for arduino - ISP.h and wire.h, when i tried to add them, this created chain of other files… as you mentioned Spark already contain "wire.h and ISP.h"
therefore I removed quotation from code, but i believe this carry necessity of deeper modification of code to accommodate it to Spark.

looking forward to make it working :smile:
Thank you @peekay123!

@Rafal, remove the SPI.h and Wire.h includes all together. They are not needed and will only create problems! The Spark SPI and Wire code is 100% compatible with the arduino code so it will work fine. However, I don’t know why you are using arduino libraries when we have already ported these for the Spark!