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.