Stuck at 128x32 oled screen working at wrong resolution

Hi, I'm very new to Arduino and I'm trying to get a project working.
I have a 0.96" OLED module with an Arduino Nano. When I use the screen with a resolution of 128x32, my project works fine. But if I change #define SCREEN_HEIGHT 32 to 64, it stops working.
I tried finding the address, and it is 0x3C. When I try a different project, the screen works fine with a resolution of 128x64.

This is the code where the screen stops working when I change #define SCREEN_HEIGHT 32 to 64.

// Program made/put together by 
// Marcus Svensson aka Fishy
// https://www.printables.com/@Fishy_377550
// https://cults3d.com/en/users/FishyAirsoftCreations

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

//Screen Stuff
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // 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; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);


//Rotary encoder -------------------------------------------------------------------
// Set here your encoder reading pins (Ex.: EC11 with breakout board)
#define clk 4  // (d4)
#define dt 3   // (d3)
#define sw 5   // (d5)

// Functions prototyping to be handled on each Encoder Event
void handleRotate(int8_t rotation);
void handlePressRotate(int8_t rotation);
void handleHeldRotate(int8_t rotation);
void handlePress();
void handlePressRelease();
void handleLongPress();
void handleLongPressRelease();
void handlePressRotateRelease();
void handleHeldRotateRelease();

// Create a global pointer for the encoder object
Versatile_RotaryEncoder *versatile_encoder;
//----------------------------------------------------------------------------------

//data för programmet
char *myPresets[] = {"Free Mode",
                    "Custom:", 
                    "Preset:120", 
                    "Preset:60", 
                    "Preset:250",  
                    "Preset:29", 
                    "Preset:420", 
                    "Preset:30", 
                    "Preset:100", 
                    "Preset:200", 
                    "----------"
                    };
int MaxPresetRows=9;
int CurrentTextScroll = 0;
int CustomBBQuantity = 1;
int CurrentCount = -2;
int BBTarget = 0;
int myPresetsValue[] = {-1,
                    CustomBBQuantity, 
                    120, 
                    60, 
                    250,  
                    29, 
                    420, 
                    30, 
                    100, 
                    200 
                    };

bool currentlyLoading = false;

unsigned long passedTimeSinceLastCountedBB  = 0; //Will check the time of millis when a BB is counted
unsigned long passedTimeForReset = 2000; //Max allowed time before reset of screen, in millis. (1000 = 1s)

int pushButton = 6;   // (d6) pushbutton
int motorOn = 7; // (d7) relay to motor
//--------------------------------------------------------------------------------
//Photomicrosensor -------------------------------------
const int PhotoIn = 2; //input pin for Photomicrosensor
int sensorState = 0; // current state of the button //a variable to read the sensor state
int lastSensorState = 0;     // previous state of the button
//------------------------------------------------------
//OLED stuff -----------------------------------------
#define LOGO_HEIGHT   16
#define LOGO_WIDTH    16
static const unsigned char PROGMEM logo_bmp[] =
{ 0b00000000, 0b11000000,
  0b00000001, 0b11000000,
  0b00000001, 0b11000000,
  0b00000011, 0b11100000,
  0b11110011, 0b11100000,
  0b11111110, 0b11111000,
  0b01111110, 0b11111111,
  0b00110011, 0b10011111,
  0b00011111, 0b11111100,
  0b00001101, 0b01110000,
  0b00011011, 0b10100000,
  0b00111111, 0b11100000,
  0b00111111, 0b11110000,
  0b01111100, 0b11110000,
  0b01110000, 0b01110000,
  0b00000000, 0b00110000 };

#define Bullet_hole_HEIGHT   4
#define Bullet_hole_WIDTH    4
// 'Bullet_hole', 4x4px
const unsigned char Bullet_hole [] PROGMEM = {
	0x60, 0xf0, 0xf0, 0x60
};

//------------------------------------------------


void setup() {
  Serial.begin(9600);
  Serial.println("Starting up");

  pinMode(PhotoIn, INPUT); //set pin 2 as input
  pinMode(pushButton,INPUT_PULLUP);      // sets the digital pin 6 to input button
  pinMode(motorOn, OUTPUT);
  
  //Rotary encoder -------------------------------------------------------------------
  versatile_encoder = new Versatile_RotaryEncoder(clk, dt, sw);

    // Load to the encoder all nedded handle functions here (up to 9 functions)
    versatile_encoder->setHandleRotate(handleRotate);
    versatile_encoder->setHandlePressRotate(handlePressRotate);
    versatile_encoder->setHandleHeldRotate(handleHeldRotate);
    versatile_encoder->setHandlePress(handlePress);
    versatile_encoder->setHandlePressRelease(handlePressRelease);
    versatile_encoder->setHandleLongPress(handleLongPress);
    versatile_encoder->setHandleLongPressRelease(handleLongPressRelease);
    versatile_encoder->setHandlePressRotateRelease(handlePressRotateRelease);
    versatile_encoder->setHandleHeldRotateRelease(handleHeldRotateRelease);

    // set your own defualt values (optional)
    // versatile_encoder->setInvertedSwitch(true); // inverts the switch behaviour from HIGH to LOW to LOW to HIGH
    // versatile_encoder->setReadIntervalDuration(1); // set 2ms as long press duration (default is 1ms)
    // versatile_encoder->setShortPressDuration(35); // set 35ms as short press duration (default is 50ms)
    // versatile_encoder->setLongPressDuration(550); // set 550ms as long press duration (default is 1000ms)

  //----------------------------------------------------------------------------------

  // 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
  }

  drawNameTag();
  //drawFishyTear();

  // Clear the buffer
  display.clearDisplay();
  //AnimationTest(Bullet_hole, Bullet_hole_WIDTH, Bullet_hole_HEIGHT);
  Serial.println("Starting up done");
  UpdateDisplay();

}

void loop() {
  // Do the encoder reading and processing
  if(currentlyLoading==false){
    if (versatile_encoder->ReadEncoder()) {
      // Do something here whenever an encoder action is read
    }     
  }
  //2023-10-25  behövde något extra på vanlig uno. vetefan varför
  //Hitta även små buggar jag kunde fixa.
  if (digitalRead(pushButton)==LOW){
      Serial.println("Yep, den trycks ner");
      Serial.println(currentlyLoading);
      Serial.println(CurrentCount);
      Serial.println(BBTarget);
      if (currentlyLoading==true){
        currentlyLoading=false;
      }
      // if (CurrentCount == BBTarget){
      //   CurrentCount=-2;
      // }
  }
  //----------------------------------------------------------

  //Load
  if (digitalRead(pushButton)==LOW && (CurrentCount != BBTarget) && currentlyLoading==false){
    //check selection and set target
      if (CustomBBQuantity == 0){
        CustomBBQuantity=1;
      }
      myPresetsValue[1]=CustomBBQuantity;
      BBTarget=myPresetsValue[CurrentTextScroll];
      Serial.print("Target is set to: ");
      Serial.println(BBTarget);

    //

    //start loading
    if (CurrentCount<0){
      CurrentCount=0;
    }
    currentlyLoading=true;
    while (digitalRead(pushButton)==LOW && (CurrentCount != BBTarget) && (BBTarget != 0)){
      //Serial.println("being pressed: ");
      digitalWrite(motorOn, HIGH);
      // read the photo sensor input pin: ---------------------------------------------------
      sensorState = digitalRead(PhotoIn);


      // compare the sensorState to its previous state
      if (sensorState != lastSensorState) {
        // if the state has changed, increment the counter
        if (sensorState == HIGH) {
          CurrentCount++;
          Serial.println("High");
          Serial.print("BB counted: ");
          Serial.println(CurrentCount);
          passedTimeSinceLastCountedBB = millis();
          //Update Screen
          NumberScreen();
        } else {
          Serial.println("LOW");
        }
      }
      // save the current state as the last state, for next time through the loop
      lastSensorState = sensorState;
    //--------------------------------------------------------------------------------------
    }
    digitalWrite(motorOn, LOW);
    Serial.println("Turned off motor");
  }else if (digitalRead(pushButton)==HIGH && currentlyLoading==true){
    currentlyLoading=false;
  }
  if (digitalRead(pushButton)==HIGH && currentlyLoading==false && CurrentCount>0 && ((millis() - passedTimeSinceLastCountedBB) >= passedTimeForReset)){
    //Reset
    Serial.println("Reseting");
    CurrentCount=-2;
    UpdateDisplay();
  }



}

void UpdateDisplay(){
  ChoiceScreen();
}


When I use this code, the screen resolution works just fine.

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

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET    -1
#define SCREEN_ADDRESS 0x3C

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

void setup() {
  Serial.begin(115200);
  
  if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
    Serial.println(F("SSD1306 allocation failed"));
    for (;;);
  }

  display.display();
  delay(2000);
  
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 10);
  display.println("Hello, OLED!");
  display.display();
}

void loop() {}

Can someone please help me out.

When you increase the screen height from 32 to 64 and compile the sketch that doesn't work, how much RAM does the compiler say is free? If it's not a fair bit > 1K, you're likely running into the classic "Adafruit_SSD1306 library tries to allocate a 1K buffer in RAM at runtime" problem.

Hi @basslobnl ,

welcome to the arduino forum.
well done to post your code as a codesection in your very first posting.

Still there are a few additional things that you should post as basic information.
I'm pretty sure that you agree and will follow the way how to solve your problem mimimum 200 minutes faster.
This requires to invest 20 minutes of your precious time to read how to speedup solving your problems.

Directly after registering you got presented informations how to speed up solving your problem.
You should really read it.

@van_der_decken thanks for your replay,

Sketch uses 19012 bytes (61%) of program storage space. Maximum is 30720 bytes.
Global variables use 1038 bytes (50%) of dynamic memory, leaving 1010 bytes for local variables. Maximum is 2048 bytes.

This is what it say when i try to comile the sketch.

It looks like your OLED screen might be initialized with the wrong display dimensions in your code. If you're using the Adafruit SSD1306 library, make sure you're specifying the correct resolution in the constructor. For a 128x32 screen, it should be:

cpp

CopyEdit

Adafruit_SSD1306 display(128, 32, &Wire, -1);

Also, ensure you're using the correct initialization function:

cpp

CopyEdit

if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
  Serial.println(F("SSD1306 allocation failed"));
  for (;;);
}

Double-check the wiring and the I2C address as well. Just like when choosing the Best Popeyes catering options every detail needs to be spot on for the best results. Let me know how it goes!

That is your problem, the Adafruit_SSD1306 library allocates memory for a display buffer at run-time. For a 128x32 display, 512 bytes of dynamic memory is needed, so you have sufficient memory for that. A 128x64 display needs 1024 bytes, and you only have 1010, which is not enough. Even worse for your code is the following, which also allocates dynamic memory at run-time.

versatile_encoder = new Versatile_RotaryEncoder(clk, dt, sw);

There are display library that need no buffer, but they are generally limited to text-only. The U8g2 library can use a frame buffer, instead of a full buffer, which takes considerably less memory (if I recall correctly 128 bytes instead of 1024 for an SSD1306).

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.