peter-l5 / SH1107

MicroPython driver for SH1107 OLED displays (128x128 and 128x64 pixels)
MIT License
24 stars 5 forks source link

1.12" Mono OLED + Arudino Nano ESP32 Nothing displayed #9

Closed alexraileanu closed 7 months ago

alexraileanu commented 8 months ago

Hello,

I'm trying to run the examples on an Arduino Nano ESP32 with a Pimoroni 1.12" SPI Mono Oled screen, however I can't seem to get any output. I double checked that the connections are OK by running the examples provided by Adafruit and it works with those.

I'm running the latest available Micropython version. This is the output I see in my IDE:

MPY: soft reboot
starting test
SH1107: framebuf is  standard
dir sh1107:  ['__class__', '__name__', 'const', '__dict__', '__file__', 'framebuf', 'time', '__version__', 'SH1107_SPI', 'SH1107', '_fb_variant', '__repo__', 'SH1107_I2C']
version  (name='micropython', version=(1, 22, 2, ''), _machine='Arduino Nano ESP32 with ESP32S3', _mpy=10758)
Initial free: 8296064 allocated: 25472
SPI created: 8295936 allocated: 25600
display created: 8288816 allocated: 32720
bilt test
letter dir ['__class__', 'blit', 'ellipse', 'fill', 'fill_rect', 'hline', 'line', 'pixel', 'poly', 'rect', 'scroll', 'text', 'vline']
large text test
Traceback (most recent call last):
  File "main.py", line 135, in <module>
AttributeError: 'SH1107_SPI' object has no attribute 'large_text'
MicroPython v1.22.2 on 2024-02-22; Arduino Nano ESP32 with ESP32S3
Type "help()" for more information.

I tried hard resetting by re-plugging the Arduino's USB but still the same issue. The exception shouldn't matter as before this nothing is displayed.

Even if I try a small test like:

from machine import Pin, SPI
import pkg.display.sh1107 as sh1107
import time

spi1 = SPI(1, baudrate=1_000_000, sck=Pin(13), mosi=Pin(11))
display = sh1107.SH1107_SPI(128, 128, spi1, Pin(2), None, Pin(8), rotate=0)

display.sleep(False)
display.fill(0)
display.text('SH1107', 0, 0, 1)
display.text('driver', 0, 8, 1)
display.show()
time.sleep(1)

I still see no output.

Any idea what could be the problem?

peter-l5 commented 8 months ago

Hi Alex, Thanks for raising this issue. Other than the largetext error you encountered - more on that below - it's not immediately obvious to me what is causing the display not to work. The first thing I would check is the wiring and pin assignments are correct. Looking at the device pinout info, it looks to me as if you have set up the SPI clock and MOSI pins correctly, when instantiating the SPI object. While I believe that the module doesn't need MISO and reset connected, I don't think I tested that, so for completeness it might be worth trying setting those up. The largetext error that you have got would be solved by installing and loading the framebuffer extension on my pages: it appears that the example isn't checking for its presence properly. I will have a further look at this next week when I'll have more time. In the meantime it would be great to hear if you find a solution. thanks Peter

alexraileanu commented 8 months ago

Hi Peter,

Thanks for the advice.

Since my screen doesn't have RST or MISO pins, I tried creating the SPI obj with some "random" pins but that doesn't seem to have any effect.

For debugging, I tried to use write_readinto instead of write from the SPI class to see maybe it returns some values that we could use for debugging but that was also not super helpful sadly.

Let me know if I can provide any more info and thanks again for the help!

alexraileanu commented 8 months ago

In the mean time, I've gone ahead and created https://github.com/peter-l5/SH1107/pull/10 to fix the examples throwing exceptions when framebuf2 wasn't loaded properly

alexraileanu commented 8 months ago

Also, based on the Adafruit_SH1107::begin() method, I tried changing the init_display method to send the same data (in the same way) to SPI but that also doesn't seem to change anything.

    def init_display(self):
        commands = [
            const(0xAE).to_bytes(1, "big"),                                     # DISPLAYOFF         (0xAE)
            const(0xD5).to_bytes(1, "big"), const(0x51).to_bytes(1, "big"),     # SETDISPLAYCLOCKDIV (0xD5), 0x51
            const(0x20).to_bytes(1, "big"),                                     # MEMORYMODE         (0x20)
            const(0x81).to_bytes(1, "big"), const(0x4F).to_bytes(1, "big"),     # SETCONTRAST        (0x81), 0x4F
            const(0xAD).to_bytes(1, "big"), const(0x8A).to_bytes(1, "big"),     # DCDC               (0xAD), 0x8A
            const(0xA0).to_bytes(1, "big"),                                     # SEGREMAP           (0xA0)
            const(0xC0).to_bytes(1, "big"),                                     # COMSCANINC         (0xC0)
            const(0xDC).to_bytes(1, "big"), const(0x00).to_bytes(1, "big"),     # SETDISPSTARTLINE   (0xDC), 0x00
            const(0xD3).to_bytes(1, "big"), const(0x60).to_bytes(1, "big"),     # SETDISPLAYOFFSET   (0xD3), 0x60
            const(0xD9).to_bytes(1, "big"), const(0x22).to_bytes(1, "big"),     # SETPRECHARGE       (0xD9), 0x22
            const(0xDB).to_bytes(1, "big"), const(0x35).to_bytes(1, "big"),     # SETVCOMDETECT      (0xDB), 0x35
            const(0xA8).to_bytes(1, "big"), const(0x3F).to_bytes(1, "big"),     # SETMULTIPLEX       (0xA8), 0x3F
            const(0xA4).to_bytes(1, "big"),                                     # DISPLAYALLON_RESUME(0xA4)
            const(0xA6).to_bytes(1, "big"),                                     # NORMALDISPLAY      (0xA6)
        ]

        for command in commands:
            self.write_command(command)

        _128_128_commands = [
            const(0xD3).to_bytes(1, "big"), const(0x00).to_bytes(1, "big"),     # SETDISPLAYOFFSET   (0xD3), 0x00

            const(0xA8).to_bytes(1, "big"), const(0x7F).to_bytes(1, "big"),     # SETMULTIPLEX       (0xA8), 0x7F
        ]

        for command in _128_128_commands:
            self.write_command(command)

        time.sleep(100/1000)  # sleep 100ms
        self.write_command(const(0xAF).to_bytes(1, "big"))                      # DISPLAYON          (0xAF)

The Adafruit_GrayOLED::_init() method doesn't look like it's doing anything too important (other than setting the DC pin to output (which we're doing in the SH1107_SPI class anyway)). So I'm a bit lost right now as to what could be the issue.

alexraileanu commented 8 months ago

Sorry for the spam! But I think I'm losing my mind a bit.

Unrelated to this device (the SH1107), I have a different device that I decided to tinker with (to take a break from debugging this issue). A week or so ago I had it running all happy, now it refuses to work so I'm starting to believe that there might be something wrong with my micropython installation(?). I'll continue to investigate further :D. Once again, apologies for the spam!

peter-l5 commented 8 months ago

Hi Alex, no problem and thanks for all the thoughts on this and pull request. I've been having a very busy week but hope to take a look at it tomorrow when I should have more time. If you do reload MicroPython on the board, hopefully that might help. Let me know how you get on in due course. Best, Peter

alexraileanu commented 8 months ago

Hey, nevermind the previous comment. Reflashing my arduino with the latest micropython doesn't seem to actually affect anything. With my other device (a 5x5 rgb matrix of leds) I narrowed down the problem to how the init data is being sent.

I'm still trying to debug the issue with the screen. As far as I can tell, I'm doing exactly the same as the Adafruit code does but nothing seems to be happening. I even tried to have the screen initialized by the Adafruit code in hopes to narrow the issue but alas that also didn't seem to have any effect:

peter-l5 commented 8 months ago

Hi Alex,

I've finally got around to looking into this further (apologies for the delay) and have run the test script again on my Pimoroni SPI display, trying varying a few factors.

The screen operated with a weak and sometimes flickering output when connected to the Pico's 3V3 supply output, but performed more or less perfectly when connected to the 5V pin VBUS. (Although I feel sure that it has worked somewhat better when supplied from the 3V3 pin in the past, I did wonder if the breadboard connection might be partly at fault.) Here's an image with it working when connected to VBUS: image

I notice that the Nano ESP32 has a VUSB pin although the tech specs mention that this only works when the board is powered via USB. I wondered if you considered trying to power the display from that?

I also tried varying some of the initialisation parameters but with no positive effect. Disconnecting the reset pin seemed possibly to have a slight detrimental effect at 3V3, although I don't know why that would be. Your results with the Adafruit code seem curious; if I recall correctly it sends the initialisation as one continuous block, rather than using several command calls. This may be unlikely but perhaps some of the internal power/charge related parameters interact with the approach taken in sending the initialisation commands.

Peter

peter-l5 commented 7 months ago

Hi Alex, I have a suggestion for you to consider. Currently the example code sets up the SPI bus number 1, the Pico has two: 0 and 1. I think the ESP nano that you are using only has one available by default, see: nano ESP32 cheat sheet

Edit: actually I see that the original code looks ok, referring back to the micropython quick reference for the ESP32

So unfortunately I don't think this will help.

alexraileanu commented 7 months ago

Hey Peter,

Thanks a lot for the debugging and help. I'll try to figure out how to power the screen via the VBUS pin as you mention.

I tried your suggestion about the SPI # but that didn't do anything. I also tried Software SPI as I've seen in some examples but also nothing happened.

I think at this point I'm a bit ready to give up haha. I've been struggling for a long time with this screen/matrix (other device I mentioned above).

If it's not too much to ask, could you tell me a combination of screen+microcontroller that you know for sure worked for you? I think I'm ready to have something that works without too much hassle haha.

LE: would you recommend a Raspberry Pi Pico instead of going the Arduino Nano way? LLE: I impulisvely went ahead and bought a RPI Pico, I hope it will work!

peter-l5 commented 7 months ago

Hi Alex,

Thanks for letting me know about your experience.

In terms of debugging the only further idea I have come up with is from reviewing the SH1107 datasheet (you should be able to find a copy easily with an internet search). On page 43 it gives a start up sequence which recommends clearing the internal display memory before sending the switch on command. I have amended the code to do this in a development branch: v320a-development. (There are a few other changes but nothing really material.) Might just be worth a try. For what it's worth the display seems to be working from the Pico's 3V3 supply today!

I have also made some tweaks to the demo code, this alters it to use the SPI 0 interface on the Pico instead of SPI 1. It also makes the wiring on my breadboard a bit neater. 😄

As an aside, interestingly I had a jumper wire connected to the SPI MISO pin (not needed to drive the display). The redundant end of the jumper wire was sitting on the wood of the desk and the display was not working at all well. When I plugged the loose end into an unused strip on the breadboard the problem was solved. I'm thinking that the may have been in effect a capacitance coming from the desk that caused an issue! I mention this as if you have anything similar in your wiring it could be causing a problem.

In terms of microcontrollers and displays, I have used an Arduino Uno in the past but not with a display. The Raspberry Pi Pico is the only one which I have tried with MicroPython and displays. My favourite display of those I've tried is the Adafruit 1.12 inch OLED (128x128 pixels). I have used this with the Pico using I2C. It can be changed to SPI with a jumper wire change but I've not done that. The display rendering/ output that it has produced for me is better quality that the Pimoroni display provides in my opinion. It is worth noting that I have experienced occasional EIO I2C communication errors with it, but I think those are due to having a slightly poor connection.

Good luck with the RPi Pico - I'd love to hear how it goes.

alexraileanu commented 7 months ago

Hey Peter,

Thanks for the very detailed replies. Unfortunately, the changes on your dev branch did not help.

What helped was the RPi Pico! I am able to finally make use of your (great!) library and display things on it!

I think that we can close this issue.

Thanks again for all the time you spent trying to debug this with me!