Pi pico and SSD1306 OLED display

Has anyone had any problem using an SSD1306 with a Raspberry Pi Pico via the Arduino IDE?

Here is the simple code I am using -- it works well with the Arduino Nano and Nano33iot, but not with the pico:

/**************************************************************************
 * 1306_simple_pico.ino
 * 
 * SSD1306 checkout
 * 
 */
 
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
// The pins for I2C are defined by the Wire-library. 
// On an arduino UNO:       A4(SDA), A5(SCL)
// On an arduino MEGA 2560: 20(SDA), 21(SCL)
// On an arduino LEONARDO:   2(SDA),  3(SCL), ...
#define OLED_RESET     -1 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3C 

//Perhaps the following 2 lines are required for the Pico?  Or use 4,5 instead of (6u), (7u)?
//#define PIN_WIRE_SDA   (21u)
//#define PIN_WIRE_SCL   (22u)

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

void setup() {
  Serial.begin(9600);

  // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
    Serial.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever
  }
  // Clear the buffer
  display.clearDisplay();
  display.setTextSize(1);             // Normal 1:1 pixel scale
  display.setTextColor(SSD1306_WHITE);        // Draw white text
  display.setCursor(40,30);             
  display.println("HOWDY !");
  display.display();
}

void loop() {
}

As you can see above, I also tried using various define statements for PIN_WIRE_SDA and PIN_WIRE_SCL but referencing either GP4, GP5 or 21u, 22u didn't help. I know power and ground are correct, so seems to be simply making sure pico understands where SDA and SCL are. The SDA and SCL wiring has been to GP4 and GP5 (physical pins 6 and 7). Also moved the SDA, SCL to physical pins 21 and 22 but no luck.

I found one online reference ( Raspberry Pi Pico works with Arduino IDE )but I would rather use Adafruit_SSD1306.h than U8x8lib.h if possible -- or at least to see why it doesn't work!

From my install
C:\Users\David Prentice\AppData\Local\Arduino15\packages\arduino\hardware\mbed_rp2040\2.4.1\variants\RASPBERRY_PI_PICO\pins_arduino.h

// Wire
#define PIN_WIRE_SDA        (6u)
#define PIN_WIRE_SCL        (7u)

So I would expect your SSD1306 to work with GP6, GP7 pins.

From memory, you can use different I2C peripheral if you select the full-fat constructor:

  // NEW CONSTRUCTORS -- recommended for new projects
  Adafruit_SSD1306(uint8_t w, uint8_t h, TwoWire *twi = &Wire,
                   int8_t rst_pin = -1, uint32_t clkDuring = 400000UL,
                   uint32_t clkAfter = 100000UL);

David.

Thanks David! You provided me the necessary clue. Apparently the Pico defaults to using I2C1 instead of I2C2 and only uses GP6 and GP7. When I switched my wires over to GP6 and 7, the OLED worked! It turns out that one doesn't need the 2 define statements you mentioned (try commenting them out and it still works), and from what I can tell I don't seem to be able to use any other pins even if I wanted to reassign which pins for SDA and SCL.

For my own education, I would like to know why you use (6u) instead of 6 and (7u) instead of 7 in your define statements.

That is not "my" file. It is the official file from the "Arduino Mbed OS RP2040 Boards" Core installation.

If you want to know the values of default SDA, SCL in any Arduino Core, just use

Serial.println(SDA);
Serial.println(SCL);

There is no particular reason for the Core Author to use (6u) instead of (6). It is very unlikely that SDA will be used in a complex expression.

On the other hand, something like F_CPU is often used in arithmetic expressions. So it removes any confusion if it is written as (16000000uL)

David.

1 Like

Thanks for the clarification. FYI, I did try the 2 Serial.println statements above, but SDA and SCL are not declared in the scope (statements were in setup() ), so they don't appear to be global variables? I am not sure where they are set.

In which case you should try Serial.println(PIN_WIRE_SDA);
Or perhaps #include <Wire.h> before looking for SDA

I had not tested before replying. My IDE is currently set on STM32.

1 Like

[SOLVED]

Thanks again! Yes, Serial.println(PIN_WIRE_SDA) works!

I noted the following (for others this might be helpful!):

  1. One can use Serial.println(SDA) and it will compile for the Arduino Nano, but not for the Pi Pico.
  2. Pi Pico will always default to using GP6 and GP7 (I2C1). Even if you #define(PIN_WIRE_SDA) to another I2C1 pair or 12C0 pair, it will allow those re-definitions during compilation and Serial printing, but still won't illuminate your SSD1306 unless you have physically wired to GP6 and GP7. Basically, it is just not using those global variables.

You misunderstand. The Core uses the defines from the variant selected in the IDE e.g. variants\RASPBERRY_PI_PICO\pins_arduino.h

You would need to create a new variant with your own set of pin defines.
Look at the pins_arduino.h files for Uno, Leo, Mega2560, ... to see how this is done.

Regular Wire library calls will always use the default SDA, SCL pins.
If you want to use different I2C0 pins like GP8, GP9

TwoWire CustomI2C0(8, 9);
Adafruit_SSD1306 oled(128, 64, &CustomI2C0);

Untested.

David.

I stand corrected! You are correct. I tested your 2 lines and they work. So one can create our own unique instance of a TwoWire and pass it on to the Adafruit_SSD1306 constructor. The default instance is the one that uses GP6 and GP7. Thanks again for your help.

Hi Donjpearson I am trying to do the same I get Error compiling for Board Pi Pico
Did you get it working if so could you help with some working code.

I think this is what you are asking for:

/**************************************************************************
   1306_simple_pico.ino

   SSD1306 checkout

 *  Pico  ---- SSD1306 OLED display  (I2C communication)
    3.3V  -----  VCC    physical pin 36
    GND   -----  GND    physical pin 38
    GP6   -----  SDA   physical pin 9   So default uses I2C1
    GP7   -----  SCL   physical pin 10  So default uses I2C1

*/

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
// The pins for I2C are defined by the Wire-library.
// On an arduino UNO:       A4(SDA), A5(SCL)
// On an arduino MEGA 2560: 20(SDA), 21(SCL)
// On an arduino LEONARDO:   2(SDA),  3(SCL), ...


#define OLED_RESET     -1 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3C 

/* 
 *  The following uses the default Wire instance (for Pico, this uses GP6 for SDA 
 *  and GP7 for SCL). 
 *  One can use other I2C combinations by using the following 2 lines instead:
 *  
 *  TwoWire myI2C(8,9);  //create instance for SDA=GPGP8 SCL=9 
 *  Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &myI2C, OLED_RESET);
 */
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

void setup() {
  Serial.begin(9600);

  // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
    Serial.println(F("SSD1306 allocation failed"));
    for (;;); // Don't proceed, loop forever
  }
  // Clear the buffer
  display.clearDisplay();
  display.setTextSize(1);             // Normal 1:1 pixel scale
  display.setTextColor(SSD1306_WHITE);        // Draw white text
  display.setCursor(40, 30);
  display.println("HOWDY !");
  display.display();
}

void loop() {
}


That's the main problem adafruit library is not compatible for raspberry pi pico. It work fine with arduino boards but not with raspberry pi pico

The Pico upload appears to be broken.

It is simple enough to solve the "compile" problem.
But I find that upload gets 90% through and then fails.
Web Editor says

Executing command: exit status 1
rp2040load 1.0.6 - compiled with go1.16.2

.....................

If I build via the regular IDE v1.8.19 I get

.....................
An error occurred while uploading the sketch

I tried with an old version of the MBED RP2040 Core. It failed in the same way.

David.

The libraries seem to have been updated, so there are some lines you need to add for this to work. Currently the Wire library defaults to using GP0 and GP1.

In void setup(), add:

  Wire.setSDA(0);   // Add these lines
  Wire.setSCL(1);   // 
  Wire.begin();    //

This will work with the Adafruit and the U8X8 libraries. I haven't been able to get this to work with other pins yet.

[Update] This is with the Earle Philhower core.

I strongly advise you to update your "Pico" via the Boards Manager.

The Wire and SPI default pins changed from the original e.g.

//## MBED_RP2040 2.0.0 released 8 apr 2021 SPI0 on gp2-4, I2C0 on gp6-7
//## MBED_RP2040 2.7.2 released 7 feb 2022 SPI0 on gp16-19, I2C0 on gp4-5

The MBED defaults are now similar to the Earle Philhower Core.

You can always setSDA() manually if you want to. I am not aware of any Core using GP0, GP1 for I2C as a default.

David.

OK, I see my confusion...I'm using the Earle Philhower core, and have been testing my existing code and libraries against it.

I'll check again with the MBED version.

I think you will find the Philhower core expects GP4, GP5

From arduino-pico/pins_arduino.h at master · earlephilhower/arduino-pico · GitHub

// Wire
#define PIN_WIRE0_SDA  (4u)
#define PIN_WIRE0_SCL  (5u)

MBED Pico core (sinc Feb 2022) uses GP4,GP5 too.

David.

I wish it was more obvious that you should use Arduino IDE 2.0 for the Pico! I had no luck using the MBED core with the old IDE. But the new one works fine.

David, thanks for your tips - you're right, I don't need those additional lines, SDA and SCL are on GP4 and 5 in the current version.

Jeff

I have never used IDE 2.0. Nor have I seen any advertising.

I think that I am on v1.8.19 but I tend to use the Web Editor nowadays.
My PC is appallingly slow. The IDE takes a long time to switch to a different board. e.g. Uno, ESP32, Zero, Due, M0, ...

The Pico works ok with Philhower or MBED Core via the IDE.
I am a lot happier that Philhower and MBED use the same SPI, Wire pins now.
I can't use Philhower on the Web Editor.

David.

Hello David,
I'm having an issue with compiling my previously working SSD1306 application that worked on Nano but cannot compile for the Pico. Even in the online editor, I get the same issue:

/home/builder/opt/libraries/latest/adafruit_ssd1306_2_5_7/Adafruit_SSD1306.cpp:42:10: fatal error: pgmspace.h: No such file or directory

I've been at this for a while now and I cannot seem to get past compilation; let alone getting stuff on the screen. On that note however I will be using pins 8 and 9 for SCL and SDA; and I see that's going against the grain of this forum. I'm hoping I cross that bridge when I get to it; but for now I cannot get Arduino IDE to compile anything for the Pico that includes the required Adafruit GFX and SSD1306 header files.

I'm just good enough at programming to know I'm not good! Any thoughts? Much appreciation!

Aaron