Closed Winston-Lu closed 4 years ago
Hi,
I've reduced the size of the initialisation sequence to only supply non-default values, but it could be that your screen needs more values to be set.
static const uint8_t ssd1306_init_sequence [] PROGMEM = { // Initialization Sequence
// 0xAE, // Display OFF (sleep mode)
// 0x20, 0b10, // Set Memory Addressing Mode
// 00=Horizontal Addressing Mode; 01=Vertical Addressing Mode;
// 10=Page Addressing Mode (RESET); 11=Invalid
// 0xB0, // Set Page Start Address for Page Addressing Mode, 0-7
0xC8, // Set COM Output Scan Direction
// 0x00, // ---set low column address
// 0x10, // ---set high column address
// 0x40, // --set start line address
// 0x81, 0x7F, // Set contrast control register
0xA1, // Set Segment Re-map. A0=address mapped; A1=address 127 mapped.
// 0xA6, // Set display mode. A6=Normal; A7=Inverse
0xA8, 0x1F, // Set multiplex ratio(1 to 64)
// 0xA4, // Output RAM to Display
// 0xA4=Output follows RAM content; 0xA5,Output ignores RAM content
// 0xD3, 0x00, // Set display offset. 00 = no offset
// 0xD5, 0x80, // --set display clock divide ratio/oscillator frequency
// 0xD9, 0x22, // Set pre-charge period
0xDA, 0x02, // Set com pins hardware configuration
// 0xDB, 0x20, // --set vcomh 0x20 = 0.77xVcc
0x8D, 0x14 // Set DC-DC enable
};
The u8g2 library sends quite a bit more, and some slightly different settings, which you can see here: https://github.com/olikraus/u8g2/blob/master/csrc/u8x8_d_ssd1306_128x32.c
You can call oled.begin
with your own initialisation sequence. If none is supplied, the library will use the default like so:
begin(sizeof(ssd1306_init_sequence), ssd1306_init_sequence);
Hi,
I've reduced the size of the initialisation sequence to only supply non-default values, but it could be that your screen needs more values to be set.
static const uint8_t ssd1306_init_sequence [] PROGMEM = { // Initialization Sequence // 0xAE, // Display OFF (sleep mode) // 0x20, 0b10, // Set Memory Addressing Mode // 00=Horizontal Addressing Mode; 01=Vertical Addressing Mode; // 10=Page Addressing Mode (RESET); 11=Invalid // 0xB0, // Set Page Start Address for Page Addressing Mode, 0-7 0xC8, // Set COM Output Scan Direction // 0x00, // ---set low column address // 0x10, // ---set high column address // 0x40, // --set start line address // 0x81, 0x7F, // Set contrast control register 0xA1, // Set Segment Re-map. A0=address mapped; A1=address 127 mapped. // 0xA6, // Set display mode. A6=Normal; A7=Inverse 0xA8, 0x1F, // Set multiplex ratio(1 to 64) // 0xA4, // Output RAM to Display // 0xA4=Output follows RAM content; 0xA5,Output ignores RAM content // 0xD3, 0x00, // Set display offset. 00 = no offset // 0xD5, 0x80, // --set display clock divide ratio/oscillator frequency // 0xD9, 0x22, // Set pre-charge period 0xDA, 0x02, // Set com pins hardware configuration // 0xDB, 0x20, // --set vcomh 0x20 = 0.77xVcc 0x8D, 0x14 // Set DC-DC enable };
The u8g2 library sends quite a bit more, and some slightly different settings, which you can see here: https://github.com/olikraus/u8g2/blob/master/csrc/u8x8_d_ssd1306_128x32.c
You can call
oled.begin
with your own initialisation sequence. If none is supplied, the library will use the default like so:begin(sizeof(ssd1306_init_sequence), ssd1306_init_sequence);
I've tried running a different init sequence, but still no luck. Not too sure what to look for either since there is no error and the u8g2 library has a lot of code to look through. Heres what I tried:
static const uint8_t ssd1306_init_sequence [] PROGMEM = { // Initialization Sequence
0xAE, //display off
0xD5, 0x80, //clock divide ratio
0xA8, 0x1F, //Multiplex ratio
0xD3, 0x00, //Display offset
0x40, //start line at 0
0x8D, 0x14, //charge pump setting?
0x20, 0x00, //page addressing
0xA1, //segment remap
0xC8, //scan dir reverse, C0 for normal
0xDA, 0x02, // HW pin configuration
0x81, 0x8F, //contrast control
0xD9, 0xF1, //pre-charge period
0xDB, 0x40, //vcomh deselect level
0x2E, //disable scroll
0xA4, //output ram to display
0xA6 //normal display mode
}
I've tried looking through the source code for a while but didn't get anywhere that seemed to get me closer since I'm still new to the OLED IIC thing. If there was some sort of stepper debug in the Arduino debugger that went through the libraries, that would be useful. Any other ideas?
Unless you had modified the source code in the library, you also needed to provide that init sequence in the begin call:
oled.begin(sizeof(ssd1306_init_sequence), ssd1306_init_sequence);
However, your first reported code works fine for me, even after running your U8g2 code.
Running using the same init sequence as U8g2 also works for me.
I'm not sure what else to suggest.
Are you using Spence Konde's ATTinyCore?
Do you have a link to the screen you have? I assume it is one of the 4 pin ones, without a reset pin?
You could try alternative wire library implementations by including Tiny4kOLED_Wire.h or Tiny4kOLED_tiny-i2c.h instead of Tiny4kOLED.h
tiny-i2c is found here: https://github.com/technoblogy/tiny-i2c
I'm using this screen, and it does not have a reset pin: https://www.aliexpress.com/item/32982681500.html?spm=a2g0s.9042311.0.0.fc054c4dtTZCmE
I ended up using the ssd1306 library by Alexey Dynda, which works fine. I've added the #include
FYI it works when display was powered before the MCU or when MCU was reset while display stayed powered on. E.g. after flashing program while everything was connected it works like a charm, but it fails to initialize if you cut and reconnect power.
With delay of about 2 seconds before oled.begin() call for some reason it initializes properly every time. With 1 second delay it still fails.
This workaround kinda does the job for me. But it results in ~1900 ms delay anyway.
TinyI2C.init();
while (!TinyI2C.start(0x3C, 0)) {
delay(10);
}
TinyI2C.stop();
delay(50);
oled.begin();
This workaround kinda does the job for me. But it results in ~1900 ms delay anyway.
TinyI2C.init(); while (!TinyI2C.start(0x3C, 0)) { delay(10); } TinyI2C.stop(); delay(50); oled.begin();
Trying the code just gives me a compilation error with a bunch of variables in the TinyI2CMaster library having undefined variables. Can you paste the entire code and see if it works? This is what I have:
#include <Tiny4kOLED.h>
#include <TinyI2CMaster.h>
void setup(){
TinyI2C.init();
while (!TinyI2C.start(0x3C, 0)) delay(10);
TinyI2C.stop();
delay(50);
oled.begin();
}
void loop() {
oled.clear();
oled.setFont(FONT8X16);
oled.setCursor(0,1);
oled.print("ms: ");
oled.print(millis());
oled.switchFrame();
delay(100);
}
This is complete sketch I used to test. What's weird is that this code works fine when compiled and uploaded with platformIO, but from Arduino IDE it doesn't work, although it compiles and uploads without errors, OLED stays in the same state it was the moment of flashing and remains dark after power cycle. I'm out of ideas at that point.
/*
* Tiny4kOLED - Drivers for SSD1306 controlled dot matrix OLED/PLED 128x32 displays
*
* Based on ssd1306xled, re-written and extended by Stephen Denne
* from 2017-04-25 at https://github.com/datacute/Tiny4kOLED
*
*/
#include <Tiny4kOLED_tiny-i2c.h>
#include <TinyI2CMaster.h>
void initDisplay(unsigned long startDelay) {
// Clear whatever random data has been left in memory.
oled.clear();
// Position the text cursor
// In order to keep the library size small, text can only be positioned
// with the top of the font aligned with one of the four 8 bit high RAM pages.
// The Y value therefore can only have the value 0, 1, 2, or 3.
// usage: oled.setCursor(X IN PIXELS, Y IN ROWS OF 8 PIXELS STARTING WITH 0);
oled.setCursor(0, 0);
oled.print(F("start: "));
oled.print(startDelay);
oled.setCursor(0, 2);
// Write text to oled RAM (which is not currently being displayed).
oled.print(F("ms:"));
}
void updateDisplay() {
// Position the text cursor
oled.setCursor(32, 2);
// Write the number of milliseconds since power on.
// The number increases, so always overwrites any stale data.
// This means we do not need to repeatedly clear and initialize the display.
oled.print(millis());
// Swap which half of RAM is being written to, and which half is being displayed.
// This is equivalent to calling both switchRenderFrame and switchDisplayFrame.
oled.switchFrame();
}
// ============================================================================
void setup() {
TinyI2C.init();
while (!TinyI2C.start(0x3C, 0)) {
delay(10);
}
TinyI2C.stop();
delay(50);
unsigned long startDelay = millis();
// Send the initialization sequence to the oled. This leaves the display turned off.
oled.begin();
oled.on();
// This example only uses a single font, so it can be set once here.
// The characters in the 8x16 font are 8 pixels wide and 16 pixels tall.
// 2 lines of 16 characters exactly fills 128x32.
oled.setFont(FONT8X16);
// Setup the first half of memory.
initDisplay(startDelay);
// Switch the half of RAM that we are writing to, to be the half that is non currently displayed.
oled.switchRenderFrame();
// Setup the second half of memory.
initDisplay(startDelay);
// Call your own display updating code.
updateDisplay();
// Turn on the display.
oled.on();
}
void loop() {
delay(50);
updateDisplay();
}
Thanks @aosodoev for your comments and code example. That code works fine for me MOST of the time, from Arduino IDE 1.8.10 on Windows, with ATTinyCore by Spence Konde version 1.3.2 installed through boards manager.
My device (the 99% of the time that it starts properly) always reports start: 49
Very occasionally is shows a screen with random pixels turned on on three quarters of the screen with a quarter of the screen completely clear, and appears hung.
I tried this using a prototyping board with very few components:
I updated my TinyI2C (as mine was a year old, and didn't have the fix for ATtiny44/84) but that made no difference.
I took out the 50ms delay, and reported starting micros() instead of millis(), and consistently got 64.
It seems that my display is always ready to start.
The u8g2 library spends time triggering a non-existent reset pin as part of it initialisation, so maybe that explains why @Winston-Lu had success with that library?
Thank you for the nice library! I've just tested it with ssd1306 display from a different batch order and it works perfectly without any delay. "slow" module is blue oled, normal is white. Modules are not 100% identical, but schematics and driver IC supposed to be exactly the same.
I've been trying to figure out this problem for the past few days wondering why this library does not initialize the OLED properly. Using other libraries such as ux8x/u8g2 writes to the display fine, but takes up too much memory/program space for my liking. I have successfully printed on the screen once a few days ago, but I am unable to repeat this process.
I have a separate program using u8g2 to write text to the OLED display, and when I flash the Tiny4kOLED script in, the display does not clear but the rest of the script works fine (led flash). I've tried reinstalling the library, but did not work.
I am currently using an ATTINY85 with a blue SSD1306 128x32 oled screen, which should work. I have pin 0 on SDA, and pin 2 on SCK, and I'm using an Arduino Uno as an ISP to program, which has been working fine.
The U8g2 script that currently works with my setup is below: