SSD1306Ascii icon indicating copy to clipboard operation
SSD1306Ascii copied to clipboard

println() stops working and freezes program

Open LouWii opened this issue 5 years ago • 2 comments

Hi,

I've been testing a few different libraries to use an oled display.

With SSD1306AsciiAvrI2c, I'm having an issue where a call to println() just stops in the middle of the string (I can see the line not entirely showing on the display) and it seems to freeze the program entirely. This happens only after running the program for 2-3 minutes.

Edit: I was testing that on a Pro Micro. On a Leonardo, it can't even run the entire 3 texts loop, it usually freezes randomly in the middle of text 1, 2 or 3.

Interestingly, this doesn't happen when I use Wire. But using Wire eats up more memory so I'd like to stick with AvrI2c.

This is my code:

#include <SSD1306Ascii.h>
#include <SSD1306AsciiAvrI2c.h>

#define I2C_ADDRESS 0x3C

SSD1306AsciiAvrI2c oled;

char textDisplayed = 3;
const int displayDelay = 3000;
long lastDisplay = 0;

void setup() {
  Serial.begin(9600);
  oled.begin(&Adafruit128x64, I2C_ADDRESS);

  oled.setFont(System5x7);
}

void loop() {
  if (millis() - lastDisplay >= displayDelay || lastDisplay == 0) {

    if (textDisplayed == 3) {
      oled.clear();
      oled.println("Hello LouWii!");
      oled.println("It's me, Pro Micro!");
      oled.println("=]");
    
      Serial.println(F("1"));

      textDisplayed = 1;
      lastDisplay = millis();
    } else if (textDisplayed == 1) {
      oled.clear();

      oled.println("Scrolling? ");
      Serial.println(F("2"));

      textDisplayed = 2;
      lastDisplay = millis();
    } else if (textDisplayed == 2) {
      oled.clear();

      oled.println("");
      oled.println("");
      oled.println("   \\\\\\||||||////");
      oled.println("    \\\\  ~ ~  //");
      oled.println("     (  @ @  )");
      oled.println("___oOOo-(_)-oOOo___");

      Serial.println(F("3"));

      textDisplayed = 3;
      lastDisplay = millis();
    }

  }
}

LouWii avatar Nov 04 '18 02:11 LouWii

I don't have a pro micro. I ran your example on a Leonardo for 20 minutes with no problem.

Your display may be very sensitive to timing of signals on the I2C bus. I suspect there are many USB interrupts with the ATmega32U4.

AvrI2c does not disable interrupts while doing I2C operations. Wire handles transfers in an ISR with interrupts disabled.

AvrI2c uses 400 kHz I2c by default. You could try 100 kHz by editing this line in SSD1306Ascii.h and set AVRI2C_FASTMODE TO zero.

/** AvrI2c uses 400 kHz fast mode if AVRI2C_FASTMODE is nonzero else 100 kHz. */
#define AVRI2C_FASTMODE 1

Another possibility is to disable interrupts during I2C writes by adding noInterrupts() and interrupts() to the write function in SSD1306AsciiAvrI2c.h like this.

  void writeDisplay(uint8_t b, uint8_t mode) {
    noInterrupts(); // Disable interrupts  <<--ADD
    if ((m_nData && mode == SSD1306_MODE_CMD)) {
      m_i2c.stop();
      m_nData = 0;
    }
    if (m_nData == 0) {
      m_i2c.start((m_i2cAddr << 1) | I2C_WRITE);
      m_i2c.write(mode == SSD1306_MODE_CMD ? 0X00 : 0X40);
    }
    m_i2c.write(b);
    if (mode == SSD1306_MODE_RAM_BUF) {
      m_nData++;
    } else {
      m_i2c.stop();
      m_nData = 0;
    }
    interrupts();  // Enable Interrupts  <<-- ADD
  }

greiman avatar Nov 04 '18 17:11 greiman

thanks so much for this turning off fast mode fixed the issue i have been chasing for a week.

harperrc avatar Oct 16 '21 18:10 harperrc