Using u8glib for Spark? (super beginner question alert!)

Hi! I’m coming from Arduino land, and am looking to port an existing project to Spark. I’m connecting to a few OLED screens with I2C, and on Arduino I needed the Wire library to address multiple I2C devices and u8glib ( https://code.google.com/p/u8glib/ ) to send messages to the screens to display.

According to the first reply on this post ( https://community.spark.io/t/i2c-for-hmc5883l-mag-sensor/5686 ), the Wire library is included, so I don’t have to place the #include statement at the top (although, according to this - https://community.spark.io/t/i2c-information/4667 - I may actually need to replace “Wire.h” with “application.h”?). That’s great, but the same can’t be said for u8glib. I found this project ( https://github.com/pkourany/u8glibSpark ) which claims to port u8glib over to spark. However, I don’t quite understand how to use it in my own project. On the Spark Build page, I clicked “contribute library” and typed in the github address of that project, but it threw a lot of errors my way. Is there something else I should be doing?

I realize this is a very beginner-level question, but I didn’t see very clear documentation as it pertained to additional libraries for the Spark. Any help would be stellar. Thanks!

Adding a library is normally reserved to the people who made them. It has to fulfil certain requirements before being accepted by the system. You can however manually add the library to your project by using the little + sign on the top of the IDE. You’ll have to copy/paste the files to do so. Compiling locally might be easier if there are a lot of files to be included. Not only is it easy to use, it’s also a lot faster if you flash via USB, so it’s definitely worthwhile to check out, if you haven’t already.

Having said that, I think it’s best to ping @peekay123, since he seems to be the one who ported the library to begin with. He should be able to help you further.
Good luck, and don’t hesitate to ask any questions ;)!

@Pete and @Moors7, I never ported the u8glib library to the Spark. It was too much work for too little return. Instead, I ported a number of Adafruit display libraries using on the Adafruit_GFX library and then created the Adafruit_mfGFX multi-font library as a replacement. The chances that your display already has a ported library is very good and if not, I’ll port it for you. :smile:

2 Likes

Hi @Moors7 and @peekay123, thanks for responding!

@peekay123, so is the github page that I linked to the Adafruit replacement, and not actually the u8glib? For reference, I’m using these cheap (I2C only) OLED displays: www.amazon.com/Huhushop-TM-Serial-Display-Arduino/dp/B00JM7SWI4/ref=sr_1_4?ie=UTF8 They work beautifully on Arduino using U8glib and this opening line:
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE);
Initial research didn’t seem to suggest that the Adafruit libraries would be compatible to the extent that the general u8glib would be, but perhaps I overlooked something?

And @Moors7, I have indeed been connecting the Spark over USB, through the Spark Build online interface.

Thanks again for any insight!

@Pete, the github repo you linked to was a work in progress between @timb and I.

There is a Adafruit_SSD1306 library on the web IDE you can use which supports both software and hardware SPI and I2C. It will work just fine with your display though you may need pull-up resistors on the I2C lines if they are not built-in to the display. :smile:

2 Likes

Ah, okay. Thanks for the reply. I’ll give that a shot and report back!

(I never understood the purpose of the pull-up resistors, but that makes sense. I have them in place just in case :))

So, I’ve attempted to add the Adafruit library into my code and replace u8glib with it. However, I’m getting some compilation errors. Hopefully this is a simple fix for something that I’m overlooking or am ignorant of.

First, I added Adafruit_SSD1306 to my project via Spark Build. Then I tried to follow Adafruit’s I2C example (seen here: https://github.com/adafruit/Adafruit_SSD1306/blob/master/examples/ssd1306_128x64_i2c/ssd1306_128x64_i2c.ino ) as closely as possible. Unfortunately, I couldn’t get anything to show up on my screens.

The hardware setup is the same as I had running on Arduino, so that shouldn’t be the issue. Since I’m actually running four screens at once, I send the I2C lines from the Spark to a 4-channel multiplexer, which then sends individual I2C lines to each of the four screens. There’s a section that deals with the mux in the source code which I didn’t touch from the Arduino code. Could it be possible that the two platforms handle addresses slightly differently?

Here’s my code:

//#include "U8glib.h"
//U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE);	// I2C / TWI 

#include "Adafruit_SSD1306/Adafruit_SSD1306.h"

#define MUX         0x70  //Multiplexer Address
#define DISPLAY     0x3C  //OLED Display Address
#define OLED_RESET D4

Adafruit_SSD1306 display(OLED_RESET);

void draw(char str[]) {
  
  /* graphic commands to redraw the complete screen should be placed here */
  //u8g.setFont(u8g_font_fur17);
  //u8g.setFont(u8g_font_osb21);
  //u8g.drawStr( 5, 20, "Testing:");
  //u8g.drawStr( 5, 40, str);
}

void setup()
{  
  /* MUX portion */
  Wire.begin();
  Serial.begin(115200);
  mux(0);  //select Display on channel 0
  initializeDISP(DISPLAY);
  sendDISP(DISPLAY,"first");
  mux(1);  //select Display on channel 1
  initializeDISP(DISPLAY);
  sendDISP(DISPLAY,"second");
  mux(2);  //select Display on channel 2
  initializeDISP(DISPLAY);
  sendDISP(DISPLAY,"third");
  mux(3);  //select Display on channel 3
  initializeDISP(DISPLAY);
  sendDISP(DISPLAY,"fourth");
  mux(0xFF);  //disable all channels. This is not required
}

void loop()
{
}

//This here's the mux section, which I downloaded from the manufacturer's website.
/********************************************************
* When selecting a channel bit2 of the control register
* must be set to a logic 1 to enable channel selection.
* If bit2 is a logic zero then all channels will be disabled.
* If 0xFF is the selected channel it will disable all channels.
********************************************************/
void mux(byte channel)
{
  byte controlRegister = 0x04;  
  controlRegister |= channel;
  Wire.beginTransmission(MUX);
  if (channel == 0xFF){Wire.write(0x00);} //deselect all channels
  else {Wire.write(controlRegister);}     //set to selected channel
  Wire.endTransmission();
}

void initializeDISP(uint8_t address)
{
  Wire.beginTransmission(DISPLAY);
  Wire.write(0x06);
  Wire.write(0x40);
  Wire.write(0x00);
  Wire.endTransmission();  

  //u8g.begin();
  
  //Adafruit stuff
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // initialize with the I2C address 0x3C
  display.display();
  delay(2000);
  
  display.clearDisplay();
}

void sendDISP(int _disp, String rootStr)
{
  Wire.beginTransmission(_disp);
  Wire.write(0x04);
  Wire.endTransmission();
  
  /*
  // picture loop
  u8g.firstPage();  
  do {
    draw(rootStr);
  } while( u8g.nextPage() );
  */
  
  //Adafruit: text display tests
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(0,0);
  display.println(rootStr);
  display.display();
  delay(2000);
}

I simply commented out the sections where I previously had u8glib, and replaced it with my best guess for the relevant Adafruit code, based on the example linked above. One thing that confused me was OLED_RESET, defined at the top of the file. I don’t think I use it, but I need it for the code to compile, so I set it to D4, which I don’t use. If you see anything I did wrong, I’d appreciate any help. Thanks!

@Pete, here are a few questions:

The OLED reset, if you use it, is there to reset the OLED display via it RST pin.

  1. Are you powering the displays via 5V or 3.3v?

  2. Are there pull-up resistors on the displays? If so don’t add your own. If you add your own pull-ups then you need to pull-them up to the same voltage you are powering the displays with.

  3. Is it your intent to display the same thing on each OLED?

I would test the new library with a single display and the demo code to begin with. Then you can move on to the multi-display configuration. Keep me posted :smile:

Hi @peekay123.

  1. I’m powering the displays via the Spark’s 3.3V pin. They worked with either voltage on the Arduino.

  2. Yes, there are 4.7k resistors on every display, going from VCC to each of the two I2C lines.

  3. No, I’d ultimately like to send different messages to each display. That’s why I have the mux as an intermediary between the Spark and the displays (this part shouldn’t be an issue as I had this goal accomplished prior to coming over to Spark, unless the Spark does something differently when addressing the displays).

And I just realized I never gave a link to the actual displays in the OP! That was my bad. I’m using these cheap 4-pin displays, which don’t include a reset pin on them: http://www.amazon.com/Huhushop-TM-Serial-Display-Arduino/dp/B00JM7SWI4/ref=sr_1_4?ie=UTF8

I’m away at the moment, but later today I’ll do some more rudimentary attempts before trying all the screens at once. Hopefully I’m on the right path. Thanks again!

@Pete,

  1. There is not enough current on the 3.3v pin to power all four screens

I got a headache trying to unravel the layered abstraction in the u8glib code to understand what size buffer the library was setting up. This library is the best worst documented library I have seen!

The Adafruit library will setup a screen buffer of 1024 bytes when you create a (single) screen object using:

Adafruit_SSD1306 display(OLED_RESET);

For each screen you want to draw to uniquely, you need to create a screen object. They could share a common reset line or not use the reset line at all. This will allow you to control each screen individually but it will also take 4096 bytes of RAM which should be available unless you have other RAM gobbling code.

To make your code work, you now need to specify the specific display object you want to use in each operation. So you could would look like this:

#define MUX         	0x70  //Multiplexer Address
#define DISPLAY_ADDR    0x3C  //OLED Display Address
#define OLED_RESET	D4

Adafruit_SSD1306 display1(OLED_RESET);  // creat 4 display objects
Adafruit_SSD1306 display2(OLED_RESET);
Adafruit_SSD1306 display3(OLED_RESET);
Adafruit_SSD1306 display4(OLED_RESET);

void draw(char str[]) {

  /* graphic commands to redraw the complete screen should be placed here */
  //u8g.setFont(u8g_font_fur17);
  //u8g.setFont(u8g_font_osb21);
  //u8g.drawStr( 5, 20, "Testing:");
  //u8g.drawStr( 5, 40, str);
}

void setup()
{  
  /* MUX portion */
  //Wire.begin();  //Not required - done by SSD1306 init code
  Serial.begin(115200);
  mux(0);  //select Display on channel 0
  initializeDISP(&display1);
  sendDISP(&display1,"first");
  mux(1);  //select Display on channel 1
  initializeDISP(&display2);
  sendDISP(&display2,"second");
  mux(2);  //select Display on channel 2
  initializeDISP(&display3);
  sendDISP(&display3,"third");
  mux(3);  //select Display on channel 3
  initializeDISP(&display4);
  sendDISP(&display4,"fourth");
  mux(0xFF);  //disable all channels. This is not required
}

void loop()
{
}

//This here's the mux section, which I downloaded from the manufacturer's website.
/********************************************************
* When selecting a channel bit2 of the control register
* must be set to a logic 1 to enable channel selection.
* If bit2 is a logic zero then all channels will be disabled.
* If 0xFF is the selected channel it will disable all channels.
********************************************************/
void mux(byte channel)
{
  byte controlRegister = 0x04;  
  controlRegister |= channel;
  Wire.beginTransmission(MUX);
  if (channel == 0xFF){Wire.write(0x00);} //deselect all channels
  else {Wire.write(controlRegister);}     //set to selected channel
  Wire.endTransmission();
}

void initializeDISP(Adafruit_SSD1306 *display)
{
  Wire.beginTransmission(DISPLAY_ADDR);
  Wire.write(0x06);
  Wire.write(0x40);
  Wire.write(0x00);
  Wire.endTransmission();  

  //u8g.begin();

  //Adafruit stuff
  //The -> is used instead of . since we are pointing to the function of the object pointed to by "display"
  display->begin(SSD1306_SWITCHCAPVCC, 0x3C); // initialize with the I2C address 0x3C
  display->display();
  delay(2000);

  display->clearDisplay();
}

void sendDISP(Adafruit_SSD1306 *display, String rootStr)  //Need to pass pointer to specific display object
{
  Wire.beginTransmission(DISPLAY_ADDR);
  Wire.write(0x04);
  Wire.endTransmission();

  /*
  // picture loop
  u8g.firstPage();  
  do {
    draw(rootStr);
  } while( u8g.nextPage() );
  */

  //Adafruit: text display tests
  display->setTextSize(1);
  display->setTextColor(WHITE);
  display->setCursor(0,0);
  display->println(rootStr);
  display->display();
  delay(2000);
}

Hope that helps! Again, before using the code above (which I did not test :P) I would suggest you run the sample code first. :smile:

Hi @peekay123, I tried running the sample code from Adafruit’s github. After removing the PROGMEM declaration and most of the superflouous test functions, everything compiled. However, on plugging in a display I got mostly garbage output to the screen. As you can see in the picture below (both displays have identical wiring), I tried runing testdrawtriangle(), which seemed to be working as you can see the bottom of the triangle being drawn. But most of the screen is obviously filled with garbage, which was present whether I had one or two displays connected.

I looked around a bit on the forums, but couldn’t find that problem occurring anywhere else. Is that a common issue, or was I doing something completely wrong?

EDIT: Also, why won’t 3.3v work to power all four screens? They did fine from Arduino’s 3.3v, so I guess that’s confusing to me. Would simply using a logic level converter do the trick?

Thanks again for all the help. Once I get SSD1306 to work nicely with one screen, I’ll attempt to integrate the multiplexer code with it to work with all four, as in your example posted above.

Well, probably because the Spark isn't an arduino. If it were the exact same, then why would we need the :spark: in the first place? Kind of like saying that because a Lamborghini and a Fiat Panda both ride on gasoline, they should go equally fast. Would be nice, but isn't going to happen... :cry:
Technically, it's because the Uno (which I assume you're talking about) can output 50mA per pin, whereas the Spark can output 'only' 20mA per pin. Trying to connect four of these displays probably falls below the 50mA but above the 20mA, which is why it'll work on an Uno, but won't on a Core.

Fair enough, that makes sense :slight_smile: In which case, I'm guessing that a logic level converter like this one - https://www.sparkfun.com/products/12009 - wouldn't help? Darn, it would be stellar if I were able to power all four screens from the same spark. You don't think there's any way to accomplish this?

EDIT: If the Spark outputs enough current to power two displays on only one pin (as pictured above), what's stopping me from powering two displays via the 3.3V pin and the other two from the 3.3V* (analog) pin?

So, here’s a video of the two screens displaying junk as in the picture a few posts up, which can hopefully shed more light on the issue for the experienced folks :stuck_out_tongue:

I’ve placed the following code inside loop()…

void loop() {
  testfilltriangle();
  delay(2000);
  display.clearDisplay();
}

…and you can see the triangles being drawn at the tops of the screen, while the rest of the screens are filled with junk. It’s like this whether I have one or two displays connected to the Spark. Any ideas on why this is/how I could fix it?

@Pete and @Moors7, the amount of current put out by the Spark pins is not an issue here. The reason I said not to power the 4 displays via the 3.3v of the Spark is that the onboard regulator can only provide a max. of 500ma with the CC3000 taking a maxium (per datasheet) of 350ma. With each display requiring a max of roughly 20ma, that is a total of 80ma. It should be OK but keep the limit in mind.

From your picture, I see you have pull-up at each display. You only need one set of pull-ups for the I2C bus. The library on the web IDE will not compile due to some issues with referencing libraries within libraries that were clarified AFTER that library was published. So I suggest you use the same library I posted on my repo along with the matching examples I suggest you use. Give those a shot and let me know how it goes.

1 Like

@peekay123, thanks for the insight! I created a new project on the web IDE, copied over the contents of Adafruit_GFX and Adafruit_SSD1306 from your repo to two new libraries (I just used the little ‘+’ button in the top right. That’s the proper way of adding custom libraries, correct?). Then I copied over your ssd1306_128x64_i2c example into the .ino file. It complied and ran just fine, and appeared to go through all the test functions in the file. However, the very same garbage was present on the bottom ~80% of the screen.

One possible explanation I can think of is that the .ino file is actually referencing the libraries available in the web IDE instead of the libraries that I added manually, thus producing the same error. I’m attempting to rename your library files in my code to see if that’s the issue, but so far I’m only getting compiler errors. I’ll report back if I get it to work.

Is there any other explanation for this issue with the screens displaying?

EDIT: No cigar. I renamed the libraries that I copied over from @peekay123’s repo, but I’m having the same issue with the screens.

@Pete, no the IDE will not confuse the libraries you added as tabs with the libraries available. After looking at the description of your display carefully, I realized that the onboard controller is actually a Sh1106 and NOT an SSD1306!!! I have to look at what the differences are and see what changes need to be made to the code. :wink:

Ok, I think this may be the only change required. Edit line 80 of Adafruit_SSD1306.h:

#define SSD1306_SETLOWCOLUMN 0x00

change to:

#define SSD1306_SETLOWCOLUMN 0x02

Give that a shot and let me know how it goes. :smile:

Interesting! Perhaps I should have payed more attention there :stuck_out_tongue: No luck on changing that line, btw.

If the Adafruit library doesn’t happen to work, would it be beneficial to look into another library? I’ve read a little bit about Digole, but don’t know enough about it to know if it would work with my displays.

Digole displays have built-in smart controllers so they work totally differently. However, they can use I2C,ART or SPI communications. I use them all the time since they do all the work!