Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SSD1305 controller with 128x32 display issue. #309

Closed
Trotter73 opened this issue Oct 29, 2020 · 29 comments
Closed

SSD1305 controller with 128x32 display issue. #309

Trotter73 opened this issue Oct 29, 2020 · 29 comments

Comments

@Trotter73
Copy link

Trotter73 commented Oct 29, 2020

Hi,

Firstly I appreciate that I am unsupported here but thought I would raise an issue in case there is a wider problem..

I recently purchased a Waveshare 2.23” OLED HAT for a Pi Zero project I was working on, the display is 128x32 and uses
the SSD1305 controller, link to the device… https://www.waveshare.com/wiki/2.23inch_OLED_HAT

Initially I used the drivers supplied by Waveshare to check the display and prove my code, no issues with them, and I
got code that worked, the support though is not fantastic…

On reading about the SSD1305 controller I found that it was supposed to be code compatible with the SSD1306 and SSD1309, with some exceptions around the charge pump, so I thought I would give Luma-OLED a try..

After installing, I can run the example code and get an output on the display, however there appears to be an issue with
the height or scaling, there are some random pixels to the right of the screen and it looks as if every other horizontal line is
being skipped, I have attached a picture. Searching through the issues here this looks like it was previously a problem with
128x32 devices and it looks as if it was fixed at some point in 2017, I wasn’t sure if this is a particular issue with the SSD1305 or
whether the issue with 128x32 devices has reappeared.

If it is a controller incompatibility issue, I would be more than happy to work with you guys on adding this one, I am no
coder but could look at areas if pointed in the right direction.

The project is running on a Raspberry Pi Zero W, Buster with kernel “Linux raspberrypi 5.4.51+ #1333”

Many Thanks,
M.

python3 demo.py -d ssd1306 -i spi --width 128 --height 32
Version: luma.oled 3.7.0 (luma.core 1.17.3)
Display: ssd1306
Interface: spi
Dimensions: 128 x 32
20201029_083711

20201015_133219

@mark-zarandi
Copy link

Im having this same issue on sh1106 where it used to work perfectly.

@mark-zarandi
Copy link

@Trotter73 Hi Mr. Trotter - Reflashed rasbian to see if that fixed it. I'm looking around, and thinking about what my screen mighta been through and i think this is a symptom of a broken screen.

@rm-hull
Copy link
Owner

rm-hull commented Nov 9, 2020

This looks to be a memory mapping issue. The GDRAM inside the device is layer out in pages that interleaved, and if the init sequence is not correct then this could result in the image @Trotter73 shows.

Looking back through the git history, the code for SSD1306 hasn’t changed in a few years. But what has changed is the performance of the raspberry pi. It could be that the init sequence is being supplied too quickly for the display to consume it, and so it doesn’t get initialized properly. We may need to add a delay at some relevant points. This is complete conjecture by the way..

Anyway, I will try and find my 128x32 oled and give it a try, but in the meantime, could you try adding --spi-bus-speed=500000 when you run the demo (this is the lowest bus speed it supports) to see if indeed it might be a timing issue?

@Trotter73
Copy link
Author

Hi,

Thanks for taking the time to reply, appreciated !

As suggested I appended --spi-bus-speed=500000 but it gave the same result, out of curiosity I also under-clocked my Zero to Pi B speeds to see if that made a difference, but again no change, the display was not as expected.

arm_freq=700 core_freq=250 sdram_freq=400

For reference the same SD card put in a Zero with a SH1106 controller and 128x64 display works as expected.

If you are in the UK I could pop this display in the post if you think that would help ?

M.

@rm-hull
Copy link
Owner

rm-hull commented Nov 9, 2020

I think I might have a 128x32 device somewhere, but if not I might take you up on that (I am in the UK) let me know what your email is (ping me at rm_hull@yahoo.co.uk) and I’ll give you the mailing address

@Trotter73
Copy link
Author

Hi,

Just sent you an email.

@mark-zarandi
Copy link

Thanks for looking at it ya'll. This project has brought me a lot of joy. I'll follow-up with ya'll on sh1106 once i finish my own testing.

@rm-hull
Copy link
Owner

rm-hull commented Nov 10, 2020

So, I dug out my 128x32 SSD1306 (which incidentally is I2C rather than SPI) and ran the following:

$ python3 examples/demo.py -d ssd1306  --i2c-port=1 --width=128 --height=32

and it lit up as follows:

image

I dont think I2C vs SPI is making any difference here, but it does suggest that your SSD1305 either:

  • does not share the same init sequence as the SSD1306, or
  • does not share the same memory mapping

Looking at the differences between the different screen resolutions, the multiplexing, display clock divider and COM pins settings are the only differences (see https://github.com/rm-hull/luma.oled/blob/master/luma/oled/device/__init__.py#L158-L164), it seems like if we "tweak" those values we may arrive at the correct settings for your device.

Looking at the code sample they provide (https://www.waveshare.com/w/upload/c/c5/2.23inch-OLED-HAT-Code.7z) in the SSD1305.py file the following values are used, the ones that I think are relevant i've marked as PERTINENT:

    def _initialize(self):
        # 128x32 pixel specific initialization.
        self.command(0xAE)#--turn off oled panel
        self.command(0x04)#--turn off oled panel	
        self.command(0x10)#--turn off oled panel
        self.command(0x40)#---set low column address
        self.command(0x81)#---set high column address
        self.command(0x80)#--set start line address  Set Mapping RAM Display Start Line (0x00~0x3F)
        self.command(0xA1)#--set contrast control register
        self.command(0xA6)# Set SEG Output Current Brightness

        # PERTINENT 
        self.command(0xA8)#--Set SEG/Column Mapping     0xa0×óÓÒ·´ÖÃ 0xa1Õý³£ 
        self.command(0x1F)#Set COM/Row Scan Direction   0xc0ÉÏÏ·´Öà 0xc8Õý³£

        self.command(0xC8)#--set normal display
        self.command(0xD3)#--set multiplex ratio(1 to 64)
        self.command(0x00)#--1/64 duty
        self.command(0xD5)#-set display offset	Shift Mapping RAM Counter (0x00~0x3F)
        self.command(0xF0)#-not offset


        # PERTINENT 
        self.command(0xd8)#--set display clock divide ratio/oscillator frequency
        self.command(0x05)#--set divide ratio, Set Clock as 100 Frames/Sec

        self.command(0xD9)#--set pre-charge period
        self.command(0xC2)#Set Pre-Charge as 15 Clocks & Discharge as 1 Clock

        # PERTINENT 
        self.command(0xDA)#--set com pins hardware configuration
        self.command(0x12)
        self.command(0xDB)#--set vcomh
        self.command(0x08)#Set VCOM Deselect Level
        self.command(0xAF)#-Set Page Addressing Mode (0x00/0x01/0x02)

The only one of these that I think is likely to affect your display is the COM pins setting - looking at the data sheet (https://www.waveshare.com/w/upload/b/b5/SSD1305-Revision_1.8.pdf) on pg 51 section heading "10.1.26 Set COM Pins Hardware Configuration (DAh)" this enumerates the acceptable values...

If you modified the demo.py file https://github.com/rm-hull/luma.examples/blob/master/examples/demo.py#L53-L56 to look like this:

def main():
    device = get_device()
    device.command(0xDA, 0x12)        # <--- insert this line

    print("Testing basic canvas graphics...")

If that doesn't work, try progressively addingdevice.command(0xD8, 0x05) and device.command(0xA8, 0x1F).

Pictures would help to diagnose further.
Else the last resort is you can loan me your device.
Ultimately we would probably need to create a new class for ssd1305 with its own distinct init sequence

@Trotter73
Copy link
Author

Trotter73 commented Nov 11, 2020

Hi,

You were correct 0xDA, 0x12 made huge improvements on the look of the display, we are almost there.

In addition to these 0xDB & 0x08 were needed to make the contrast section of the demo work.

The rest of the options didn't appear to make any difference, however this was only a really quick check.

However, there is still the issue of the stray pixels on the right hand side of the display, examples attached...

Me.
20201111_100846
20201111_100826

@rm-hull
Copy link
Owner

rm-hull commented Nov 11, 2020

@Trotter73 try adding 0xD5, 0xF0 to your custom init command, eg:

def main():
    device = get_device()
    device.command(0xDA, 0x12, 0xD5, 0xF0)        # <--- insert this line

    print("Testing basic canvas graphics...")

@Trotter73
Copy link
Author

@rm-hull No change, still the shift to the left and odd pixels on the right, as per the picture above...

@Trotter73
Copy link
Author

Not sure if it matters but the description of these differs to the documentation for the ssd1305..

self.command(0xD3)#--set multiplex ratio(1 to 64)
self.command(0x00)#--1/64 duty
self.command(0xD5)#-set display offset	Shift Mapping RAM Counter (0x00~0x3F)
self.command(0xF0)#-not offset

@rm-hull
Copy link
Owner

rm-hull commented Nov 11, 2020

Maybe take all the values in the waveshareinitialize() method and transcribe them into a list and supply them to display.command(...)

If that works, we can just create an ssd1305 class that has a common base with ssd1306 but just has a different init sequence.

@Trotter73
Copy link
Author

Ok cool, I think I know what I'm doing there, was going to give that a go anyway. Will try to have a look at that tomorrow.

In the Waveshare main.py there are some other values, constants I think, does anything need to be done with them?

@Trotter73
Copy link
Author

@rm-hull OK so I thought I knew what you were suggesting but I was wrong lol. If you could give a little example or pointer I'll collate the list and try....

@rm-hull
Copy link
Owner

rm-hull commented Nov 21, 2020

hi @Trotter73, sorry I missed your response (for some reason some but not all github notifications keep getting snagged in my spam folder)

I meant: could you add the following:

display.command(
    0xAE, 0x04, 0x10, 0x40, 0x81, 0x80, 0xA1, 0xA6, 
    0xA8, 0x1F, 0xC8, 0xD3, 0x00, 0xD5, 0xF0, 0xd8, 
    0x05, 0xD9, 0xC2, 0xDA, 0x12, 0xDB, 0x08, 0xAF)

(This is the complete init sequence from the SSD1305.py file)

@Trotter73
Copy link
Author

Trotter73 commented Nov 23, 2020

Hi,

@rm-hull

No worries, funnily enough I have the same here, all git email seems to be dumped to spam...

OK, so adding the above gives the the following, basically the random pixels om the right are now two bars...

20201123_150931

I was also looking at the constants and comparing those and found some differences

% = Present in SSD1305.py but not const.py
#=Values are the same in SSD1305.py and const.py
? = I think there is a different value

`# Constants
%SSD1305_I2C_ADDRESS = 0x3C # 011110+SA0+RW - 0x3C or 0x3D
%SSD1305_SETCONTRAST = 0x81
%SSD1305_DISPLAYALLON_RESUME = 0xA4
%SSD1305_DISPLAYALLON = 0xA5
%SSD1305_NORMALDISPLAY = 0xA6
%SSD1305_INVERTDISPLAY = 0xA7
%SSD1305_DISPLAYOFF = 0xAE
%SSD1305_DISPLAYON = 0xAF
#SSD1305_SETDISPLAYOFFSET = 0xD3
#SSD1305_SETCOMPINS = 0xDA
#SSD1305_SETVCOMDETECT = 0xDB
#SSD1305_SETDISPLAYCLOCKDIV = 0xD5
#SSD1305_SETPRECHARGE = 0xD9
%SSD1305_SETMULTIPLEX = 0xA8
#SSD1305_SETLOWCOLUMN = 0x00
#SSD1305_SETHIGHCOLUMN = 0x10
#SSD1305_SETSTARTLINE = 0x40
#SSD1305_MEMORYMODE = 0x20
#SSD1305_COLUMNADDR = 0x21
#SSD1305_PAGEADDR = 0x22
#SSD1305_COMSCANINC = 0xC0
#SSD1305_COMSCANDEC = 0xC8
?SSD1305_SEGREMAP = 0xA0
#SSD1305_CHARGEPUMP = 0x8D
#SSD1305_EXTERNALVCC = 0x1
#SSD1305_SWITCHCAPVCC = 0x2

#Scrolling constants
%SSD1305_ACTIVATE_SCROLL = 0x2F
%SSD1305_DEACTIVATE_SCROLL = 0x2E
%SSD1305_SET_VERTICAL_SCROLL_AREA = 0xA3
%SSD1305_RIGHT_HORIZONTAL_SCROLL = 0x26
%SSD1305_LEFT_HORIZONTAL_SCROLL = 0x27
%SSD1305_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL = 0x29
%SSD1305_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL = 0x2A`

So I changed /usr/local/lib/python3.7/dist-packages/luma/oled/const.py to make SETSEGMENTREMAP = 0xA0 instead of 0xA1 and the random pixels appear to have gone, however if I change it back to 0xA1 they don't reappear ?! The screen is still offset though..

Is there a method of passing constants to demo.py, similar to that of the commands ?
Edit:-
Adding the extra ones into the const.py file does not appear to work, although I didn't really expect it to

20201123_160211

@Trotter73
Copy link
Author

I'm going to be really rude and bump this, any ideas on how we can get this over the line, we seems to be all but there ...

@rm-hull
Copy link
Owner

rm-hull commented Dec 8, 2020

sorry, quite right (and not rude) to bump.
Could you try adding:

def main():
    device = get_device()
    device.command(...)        

    device._colstart += 1    # <--- insert these lines
    device._colend += 1  

    print("Testing basic canvas graphics...")

and let me know if that makes any difference?

@Trotter73
Copy link
Author

Hi,

Thanks for the understanding !

So I had to start with a fresh install, this is what I have in demo.py

def main():
device = get_device()
device.command(
0xAE, 0x04, 0x10, 0x40, 0x81, 0x80, 0xA1, 0xA6,
0xA8, 0x1F, 0xC8, 0xD3, 0x00, 0xD5, 0xF0, 0xd8,
0x05, 0xD9, 0xC2, 0xDA, 0x12, 0xDB, 0x08, 0xAF)
device._colstart += 1
device._colend += 1

The additional couple of lines didn't make any difference, the output is as per the last pic in this thread, still shifted to the left a bit..

Regards,

@Trotter73
Copy link
Author

Trotter73 commented Dec 9, 2020

However..... Just had a play and the following values appear to fix the issue... I tried values either side but 4 was the sweet spot...

device._colstart += 4
device._colend += 4

20201209_134936
20201209_134953

So to wrap up adding the following to demo.py gives the correct output

device.command(
    0xAE, 0x04, 0x10, 0x40, 0x81, 0x80, 0xA1, 0xA6,
    0xA8, 0x1F, 0xC8, 0xD3, 0x00, 0xD5, 0xF0, 0xd8,
    0x05, 0xD9, 0xC2, 0xDA, 0x12, 0xDB, 0x08, 0xAF)
device._colstart += 4
device._colend += 4

@rm-hull
Copy link
Owner

rm-hull commented Dec 9, 2020

@Trotter73 ok, thanks for that - good news .. it should be enough for me to be able to create a specific SSD1305 device with this init wrapped inside it, but in the meantime until this is published, you are ok to proceed with the above as an interrim hack?

@Trotter73
Copy link
Author

@rm-hull Thanks for all your help in getting this working, it really is appreciated, I'm more than happy with the interim solution, I've already tried it with some other code I had written for a SH1106 and it works a treat. Just shout if you want anything testing, you have my email, if you don't get a reply here ping me there.

Thanks again.

@ldritsas
Copy link

This issue is a few months old, I know, but as another Pi user and owner of the same Waveshare 2.23" 128x32 OLED, the eventual appearance of specific SSD1305 device from luma.oled would be great! I am learning a lot creating my own code for it, but using luma would be so much better. I prefer SPI, and the only properly documented library at the moment would requite getting the soldering iron out to force it into I2C mode (then there is an Adafruit CircuitPython SSD1305 library that would allow drawing on the display with PIL but it does not support SPI). All other SSD1305 code is very Arduino-specific.

@kintel
Copy link

kintel commented Oct 6, 2021

I'm using the "Adafruit 2.23" Monochrome OLED Bonnet for Raspberry Pi" which is another, very similar, SSD1305 display (https://www.adafruit.com/product/4567). Looking at the datasheet differences and the command list mentioned above, I reduced the changes needed for this display to:

device = ssd1306(width=128, height=32,  ...)
device.command(0xDA, 0x12) # Use alternate COM pin configuration
device._colstart += 4
device._colend += 4

@Trotter73
Copy link
Author

@Trotter73 ok, thanks for that - good news .. it should be enough for me to be able to create a specific SSD1305 device with this init wrapped inside it, but in the meantime until this is published, you are ok to proceed with the above as an interrim hack?

Hi, not sure if this is still actively in development? Would there be a lot of work to add the SSD1305 device? Or if someone could give some pointers on how/where to start I could have a go at creating a device and generating a pull request ....

@vieacq
Copy link

vieacq commented Apr 19, 2023

I'd suggest to duplicate class ssd1306 and modify appropriately to get class ssd1305 in __init__.py.
I'd guess modifications should go before/into/after self.command (lines around 260 of __init__.py)
Maybe this is "brute force" (as it does not subclass from class ssd1306), but probably works...
Unfortunately I don't (yet) have the SSD1305 (but want to get this 2+" OLED for my planned project) - so cannot try atm.

@vieacq
Copy link

vieacq commented Apr 19, 2023

...in oled/device/__init__.py - and also add "ssd1305" to __all__ (line 48)

@olly69
Copy link

olly69 commented Feb 1, 2024

Thanks @Trotter73 and @rm-hull for saving me a lot of time! Very useful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants