Problems using Dig-ole OLED 12864 with I2C

After getting my project working with the OLED 12864 display on the default 9,600 UART, using UART12 on the Imp, I now need to use I2C, as I need to add a I2C memory chip to the bus and the other 4 are occupied.

Getting the UART code working was a breeze, looking at several examples, including Cap’t I wrote several little functions such as clearScreen() and setFont() which send “CL” and “SF” to the display, respectively. The print() function sends “TT” + string + 0x00. This works perfectly using the UART but hardly at all with I2C. It will send some text strings to the display and clearScreen() works in some loops but not always.

Some examples show sending “0x01” after each command even though that is not mentioned in the documentation for the OLED. Removing it from the UART version made no difference. Adding it to the I2C code made no difference.

The OLED says it has an address of 0x27. A few lines that do a quick scan see it as 4E, which would seem correct. Writing to “0x27 << 1” returns 0. Disconnecting either clock or data produces an error. Adding 10K pull-ups makes nothing work at all. I have two displays giving identical results. Tried 10, 100, 400. The wires involved are 3" long. Nothing else connects to those pins.

I must be close as I never get a write error and I do get some text strings but this is not working at even 1% of how well the UART connection works. I2C.write() must be sending the “\x00” as that is what terminates the TT command.

What detail am I missing? Help!

If the UART is working so well, why not keep it?

I don’t know about the I2C problem, but one suggestion is that you might be able to squeeze I2C into your design without losing the UART interface. The LED display only requires a UART TX
eg: hardware.uart12.configure(9600, 8, PARITY_NONE, 1, NO_RX, handler);

That would leave pin 2 to use as SDA. The other challenge is to (re)use one of the other pins as SCL. As long as you keep SDA high, SCL can be used for another purpose. I2C can only be triggered by a falling edge on SDA, while SCL is high. This can allow you to use both SPI and I2C on shared pins as long as SDA and CS are kept on separate pins AND they are not simultaneous.

Could you post the code you’re using to do the i2c write?

The Digiole datasheet I saw said max 200kHz, so don’t use 400. I2C.write doesn’t add any extra bytes when you send - if you need an \x00 you need to add it yourself.

If you’re determined to use I²C, another option is Make Deck’s P3V3, which unlike the standard Dev Kit is based on the imp002 module and so has seven extra GPIO/bus ports. I’ve used these in a couple of projects that required more pins than we could cram into the imp001 Dev Kit board.

Just thought to add that Sparkfun have also made an imp002 breakout board

this is the code that i am using, cut & pasted from imp example code. i had been trying it on i2c12 with a well used OLED. no change at all moving it to i2c89 using a new unit.
Dig-ole tech responded that pull up resistors are required. anything smaller than 22K causes there to be no output. in the functions below, with debug debris, clearScreen() works in a loop but not always. print() seems to work but the OLED does scroll txt now like it did under UART. setFont(), setColor() produces no results at all. i am omitting the other non-working functions.

Does this send the 0x00 that Digole want to end the text string with?
i2c.write(iI2cAdd, “\x00”);

local givenI2cAddress = 0x27;
local iI2cAdd = givenI2cAddress << 1 ;

i2c <- hardware.i2c89;

for (local i = 2 ; i < 256 ; i+=2)
if (, “”, 1) != null) server.log(format(“Device at address: 0x%02X”, i))
server.log(“I2C Port Scan complete”)

// this returns the one device at 0x4E

function clearScreen() {

i2c.write(iI2cAdd,“CL”) ; //Clear display.
// i2c.write(iI2cAdd,"\x01") ;


function setFont(dfont) {

local fonteee = "SF" + dfont.tostring();
i2c.write(iI2cAdd, fonteee);        //Set font 6,10,18,51,120,123,0

// i2c.write(iI2cAdd, “\x01”); // no apparent change if used or not


function setColor(colour) {

i2c.write(iI2cAdd,"SC" + colour.tostring());  
// i2c.write(iI2cAdd,"\\x01");   // no apparent use for this


function print(out_string) { // text string

local outstuff = "TT" + out_string ;
local junkk = i2c.write(iI2cAdd, outstuff);  
i2c.write(iI2cAdd, "\\x00");    // Write text
// i2c.write(iI2cAdd, "\\x01");  // no apparent difference if used.

// server.log(junkk);

Also, i sincerely appreciate all input, i thank you. If this makes it into production, i know it will be an IMP002, not a 001. Considering that i am getting some characters, i must be close to having this working. i certainly may have to consider something, especially if a second push button or some such thing has to be added. For now, the Imp001 and the Dig-Ole 12864 either support i2c or they do not.

It’s strange that stronger pullups (<22k) stop this working. I’d expect that to be the other way round. Does your display need any strapping options to move to I2C from UART? I noticed that some of the digiole displays do need this.

If they need a terminator of \x00, just put that at the end of every string (in the same I2C transaction) eg:

i2c.write(il2cAdd, outstuff + “\x00”);

Think I see your problem; the display is expecting bytes for the commands, not strings.

eg setFont(10) is sending the string “SF10”, vs “SF\x0a”.

If you change your dfont.tostring() to a dfont.tochar() you should have more luck.

Dropping to a speed of 50 gave me a much cleaner waveform on the SCL. My old 'scope can’t really capture the SDA, but what I can see is very nearly square. I’m getting output to the display, it is just working very poorly.

Hugo, you are a genius. I was so focused on the pull ups as that seems to be the top of the debug list. As it turns out, the display is tolerant of a slightly poor waveform.

Plus, my Bud Red Light is working - thanks again for that!


Follow up: my I2C bus is working with the Digole 12864 and a 24XX256 EEPROM, pull-up resistors 2K, speed set to 50. Faster speeds may work with shorter wires.

Here are a few sample functions that will work for all Digole displays.

`function clearScreen() {

  i2c.write(i2cDis,"CL") ;  //Clear display. does not get executed until the OLED receives another command.
} `
`function setFont(dfont = 0) {
    i2c.write(i2cDis,"SF" + dfont.tochar());     //Set font 6,10,18,51,120,123,0
`function setColor(colour) {
    i2c.write(i2cDis,"SC" + colour.tochar());
`function print(out_string) {     // text string

    i2c.write(i2cDis,"TT" + out_string + "\\x00");  
`function setPrintPos(xpos, ypos) {
 i2c.write(i2cDis,"TP" + xpos.tochar() + ypos.tochar()); 
`function drawBox(xp, yp, wd, ht) {     // upper left x,y of the box and then width, height
 i2c.write(i2cDis,"FR" + xp.tochar() + yp.tochar() + wd.tochar() + ht.tochar()  ); 
`function drawFrame(xp, yp, wd, ht) {    // upper left x,y of the box and then width, height
 i2c.write(i2cDis,"DR" + xp.tochar() + yp.tochar() + wd.tochar() + ht.tochar());