lexus2k / ssd1306

Driver for SSD1306, SSD1331, SSD1351, IL9163, ILI9341, ST7735, PCD8544, Nokia 5110 displays running on Arduino/ESP32/Linux (Rasperry) platforms
MIT License
660 stars 127 forks source link

"draw_bitmap" problem with bottom 8 pixels #8

Closed Philip-Mohr closed 6 years ago

Philip-Mohr commented 6 years ago

library version

1.2.5

LCD display type

SSD1306

Steps to reproduce the issue

flash "draw_bitmap" (tried on Arduino Uno and Attiny45)

Expected behavior

Draw the owl

Actual behavior

Draws the owl but the top 8 pixels are cut on the top and the bottom 8 pixels are not refreshed.

I uploaded "draw_text" (with "_ssd1306_charF6x8(0, 7, "Line 7. Italic text", STYLEITALIC);") before and then uploaded "draw_bitmap" to show, that the 8 pixels on the bottom don´t refresh.

image

Philip-Mohr commented 6 years ago

"ssd1306_drawRect(1,1,126,62);" does this:

image

other librarys use the bottom 8 pixels without a problem.

lexus2k commented 6 years ago

@Philip-Mohr, thank you for posting this issue. UNO is based on Atmega328p, the same as mine Nano. And I do not observe any issues with draw_bitmap example: 20171030_075155 The picture I posted shows image, and then text, which is displayed on the top of image. The top 8 pixels and bottom 8 pixels are good. As you can see my display looks slightly different than yours. If you use Wire library in your program, could you please reduce the speed to standard 100kHz instead of 400kHz and see what happens. For now, it looks for me like i2c communication issue, I didn't find any problem in logic of ssd1306_drawBitmap(). Do you have any datasheet for you display?

Philip-Mohr commented 6 years ago

It's this board: http://s.aliexpress.com/u6zmE3m6 With u8g2 it works good, but I want an attiny compatible library. Not at home at the moment, tomorrow I will test 100khz

lexus2k commented 6 years ago

Hi @Philip-Mohr ,

I noticed one thing in your screenshots. The resulting image (owl) is shifted by 8 pixels up. That's why you don't have 8 top rows, and there is empty 8 bottom rows in your case. I checked 0.96" ssd1306 and 1.3" ssd1306 oleds, I have. And they both work ok for me.

Could you please, share your sketch source code? Which configuration of u8g2 library did you use for your lcd? I check the top most initialization sequence for ssd1306 128x64, and my library does the same initialization steps for the display. Could it be possible, that your display is not ssd1306? For example, sh1106 has almost the same commands.

lexus2k commented 6 years ago

Could you please edit file src/lcd/ssd1306_128x64.c and insert the line 0xB0, right before SSD1306_MEMORYMODE, HORIZONTAL_ADDRESSING_MODE, line, and let me know if it helps.

Philip-Mohr commented 6 years ago

Hey dude,

with u8g2 i need to use U8X8_SSD1306_128X64_NONAME_HW_I2C u8x8(/* reset=*/ U8X8_PIN_NONE);

When i use the SH1106 code from u8g2 it works, but a bit buggy, so it seems to be a SSD1306. Adafruit lib and u8g2 both work without a problem.

I tried 0xB0, but it doesn´t help. (What does 0xB0?).

Also i tried to reduce the i2c speed, but i´m not sure if i´ve done it right. After Wire.begin(); i added Wire.setClock(); and tried 400khz, 100khz, 31khz and some other random numbers.

And i don´t know if sharing the code is necessary. It´s just your draw_bitmap code.

ESP8266 has the same bug btw with my panel and your lib.

Philip-Mohr commented 6 years ago

I removed my arduino 1.8.3 ide and all libs etc, so i could do a clean install of the arduino 1.8.5 with only your lib. Same problem. I would think that the board is defective, but the other 2 libs work without a problem. I have an old project laying around with an oled display and arduino pro mini. When i find it, i will try it there.

Philip-Mohr commented 6 years ago

Tried the oled with the digispark and digisparkOLED library. also there no problems. I don´t get why your lib works on your oled without a problem and on mine not. But i wanna use your lib, because it´s the best in my opinion.

lexus2k commented 6 years ago

Thank you for the response. I'm still looking at the issue, trying to figure out what happened. I will check against digisparkOLED library.

lexus2k commented 6 years ago

Hi @Philip-Mohr

Please, try display configuration I listed below instead of the one in src/lcd/ssd1306_128x64.c file and let me know if it works.

static const uint8_t PROGMEM s_oled128x64_initData[] =
{
    SSD1306_DISPLAYOFF, // display off
    SSD1306_MEMORYMODE, HORIZONTAL_ADDRESSING_MODE, // Page Addressing mode
    0xB0,
    SSD1306_COMSCANDIR,
    SSD1306_SETLOWCOLUMN, 
    SSD1306_SETHIGHCOLUMN, 
    SSD1306_SETSTARTLINE,
    /* normal page addressing mode */
    SSD1306_SETCONTRAST, 0x3F, // contast value
    SSD1306_SEGREMAP | 0x01,
    SSD1306_NORMALDISPLAY,
    SSD1306_SETMULTIPLEX, 63,
    SSD1306_DISPLAYALLON_RESUME,
    SSD1306_SETDISPLAYOFFSET, 0x00, // --no offset
    SSD1306_SETDISPLAYCLOCKDIV, 0xF0,
    SSD1306_SETPRECHARGE, 0x22, // --switch vcc
    SSD1306_SETCOMPINS, 0x12, // --set divide ratio
    SSD1306_SETVCOMDETECT, 0x20, // --vcom detect
    SSD1306_CHARGEPUMP, 0x14,
    SSD1306_DISPLAYON 
};
Philip-Mohr commented 6 years ago

Tried it, same problem :/

lexus2k commented 6 years ago

Ok, lets try the simple things: What does ssd1306_putPixels(0,0,0x99); show on the display? No any other draw commands, just this one. You should see 4 pixels at (0,0), (0,3), (0,4) and (0,7)

Try this version of drawBitmap:

void ssd1306_drawBitmap(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *buf)
{
    uint8_t i, j;
    ssd1306_setRamBlock(x, y, w);
    ssd1306_dataStart();
    for(j=0; j<(h >> 3); j++)
    {
//        if ( g_lcd_type == LCD_TYPE_PCD8544 )
        {
           ssd1306_endTransmission();
           ssd1306_setPos(x, y+j);
           ssd1306_dataStart();
        }
        for(i=w;i>0;i--)
        {
            ssd1306_sendByte(s_invertByte^pgm_read_byte(buf++));
        }
    }
    ssd1306_endTransmission();
}
Philip-Mohr commented 6 years ago

Dude! It worked! 😄 i removed all if ( g_lcd_type == LCD_TYPE_PCD8544 ) (not the else if's) and now it seems to work. Thank you very much!!!!

btw when I compile for digispark, i´m getting this error:

`C:\Program Files (x86)\Arduino\libraries\ssd1306\src\ssd1306.cpp: In function 'SPRITE ssd1306_createSprite(uint8_t, uint8_t, uint8_t, const uint8_t*)':

C:\Program Files (x86)\Arduino\libraries\ssd1306\src\ssd1306.cpp:419:28: error: 'nullptr' was not declared in this scope

 return {x,y,w,x,y,data,nullptr};`
lexus2k commented 6 years ago

Hi @Philip-Mohr , I'm glad to hear that the changes helped you. However, I'm still trying to figure out, why ssd1306_setRamBlock() didn't work well for you. Actually it sends 4 ssd1306 commands: Column address, Set page, Set high column and Set low column. The commenting out g_lcd_type == LCD_TYPE_PCD8544 causes library to send those command in two different i2c sessions. During the first session only one command is sent: Column address. Other three commands are sent in second session.

As for the issue with digispark, which compiler and IDE do you use? nullptr appeared in C++11 first. For now you can try to simply replace nullptr with 0.

lexus2k commented 6 years ago

@Philip-Mohr, could you please download latest sources from https://github.com/lexus2k/ssd1306 and check if the changes fix both issues:

I found the root cause with compilation for digispark board. Actually, the library ssd1306 requires c++11/c99. This is defined by compiler flags. By default for all supported Arduino boards they are set to -std=gnu++11 and -std=gnu11. However, digispark settings are different. You can fix that by making changes to platform.txt file installed with digispark board: I found mine in this location: "C:\Users\User\AppData\Local\Application Data\Arduino15\packages\digistump\hardware\avr\1.6.7\"

Edit platform.txt for your Digispark board and add required standards to compilation flags. Here is example how I modified the flags for Digispark board:

compiler.c.flags=-c -g -Os -w -std=gnu11 -ffunction-sections -fdata-sections -MMD compiler.cpp.flags=-c -g -Os -w -std=gnu++11 -fno-exceptions -ffunction-sections -fdata-sections -MMD

Now I can compile the code for Digispark with the latest ssd1306 sources.

Philip-Mohr commented 6 years ago

Hey Dude! In the new version i still need to delete if ( g_lcd_type == LCD_TYPE_PCD8544 ), otherwise the same problem as before occures. Also bad news for digispark. After the change in the platform.txt it compiled. But i´m getting no i2c commands. I´m using p0 and p2. I hookep up my logic analyzer and saw nothing. For looking that i made no mistake with the wiring I uploaded the digispark I2Cscanner example and in the logic analyzer software I saw how it scanned the ports with p0/p2. Do you have a digispark or have you just compiled it without testing? Can i donate a few bucks for maybe a digispark and a beer? 😃 💻 🍺

lexus2k commented 6 years ago

Hi @Philip-Mohr , Regarding your lcd ssd1306 issue. I'm reading datasheet ssd1306 and still have no clear answer, why my implementation of sending control commands doesn't work in your case. According to the datasheet, it should work. But since you gave me a clue, I need to do more analysis.

Regarding Digispark, how many i2c devices are you going to use in your project? By default, since Digispark is based on Attiny85, the library switches internal software i2c implementation, which allows only direct connection with single i2c device: ssd1306 display, - and usage of any pins. By default i2c pins used by the library for Attiny controllers are pin 3 and pin 4. This is pointed in the examples and you can find that in the documentation (ssd1306_i2c_conf.h). That is the reason, why you do not see anything on p0/p2 pins. You wrote that you're trying to use pins p0, p2, which, I believe, are PB0 and PB2. Try to update ssd1306_i2c_conf.h with the pin numbers, you use for the project. I checked Digispark I2Cscanner, and found that they implemented specific Wire library for Attiny controllers (in original Arduino Wire is not available for those). So, there are 2 ways for you available right now:

I don't have Digispark module to check, I have only single Attiny85 chip and ISP programmer.

With new version of ssd1306 library, there will be ability to configure pins from the project source (if interesting, you can check 1.3.0_i2c_spi branch in development). Also, with new version it will be possible to choose to use either software or hardware i2c implementation in the project.

Thank you for your wishes. I'm pleased. I can order ssd1306 module, you have, and digispark board, but it will take from 2 weeks to 1.5 months to get them. Maybe, we will be able to solve the issue a little bit faster.

Philip-Mohr commented 6 years ago

I tried the preferred method and it worked 😄 thank you! But the 8 bottom pixel problems still happens. When removing the 3 if ( g_lcd_type == LCD_TYPE_PCD8544 ) lines the problem goes away. But just for the draw_bitmap sketch. With buffers_demo and draw_text i still have the same problem.

lexus2k commented 6 years ago

Actually I'm thinking now that you have not ssd1306 lcd, but sh1106 instead (or some lcd not fully compliant with ssd1306 spec). They have similar datasheets and very often manufactures describe sh1106 as ssd1306, but sh1106 doesn't support Horizontal/Vertical addressing modes, and supports only Page Addressing mode. That explains, why my library doesn't work for you correctly (as you noticed the problem with the text printing). The main mode of my library is horizontal addressing mode, while u8g2 uses page addressing mode. That's why it works. But don't worry, I will add SH1106 support (at least I have the datasheet for it). I just only need your help in testing.

lexus2k commented 6 years ago

Please, check commit https://github.com/lexus2k/ssd1306/commit/8c12ac93c65da84fd1461526d3c9a55629661019 and initialize your display with sh1106_128x64_i2c_init()

lexus2k commented 6 years ago

Hi @Philip-Mohr , Do the changes help you to solve the issue? You can try also 1.3.0_i2c_spi branch. It also has support for SH1106 oled display.

Philip-Mohr commented 6 years ago

Sry for answering so late (had much stuff to do (learn stm32... i hate these fu**ers )). I downloaded the 1.3.0_i2c_spi branch and uploaded it with sh1106_128x64_i2c_init(). Works nice now. But now it also works with ssd1306_128x64_i2c_init(). Have i done something wrong? ^^ Btw, thank you really much for your help 😃

lexus2k commented 6 years ago

I'm surprised. Looking at the manufactures, I found that there are several ssd1306 controller versions (at least, I saw ssd1306, ssd1306b). If both variants work for you, use ssd1306_128x64_i2c_init() since it is faster. The new library 1.3.0 is greatly reworked, and it is not still published. I'm going to do that soon.

Philip-Mohr commented 6 years ago

Cool Cool! Thank you 👍