robert-hh / SH1106

MicroPython driver for the SH1106 OLED controller
Other
157 stars 38 forks source link

hardware I2C - write_data() #3

Closed pacmac closed 7 years ago

pacmac commented 7 years ago

Hi again;

Do you know how the write_data() function can be modified to work with hardware SPI (ESP32) which does not have primitive I2C start() and i2c.stop() functions ?

I have tried just self.i2c.writeto(self.addr, buf) but the display just shows noise, I think the only function that calls this is show() ?

  def _write_data(self, buf):
    self.temp[0] = self.addr << 1
    self.temp[1] = 0x40 # Co=0, D/C#=1
    self.i2c.start()
    self.i2c.write(self.temp)
    self.i2c.write(buf)
    self.i2c.stop()

  def write_data(self, buf):
    self.i2c.writeto(self.addr, buf)
robert-hh commented 7 years ago

The command byte is missing. Try changing write_data to:

   def write_data(self, buf):
        self.i2c.writeto(self.addr, b'\x40'+buf, stop=True)

If that works, you might try also something like: Add the following two lines to init:

        self.temp1 = bytearray(1)
        self.temp1 = 0x40

And change write_data to:

   def write_data(self, buf):
        self.i2c.writeto(self.addr, self.temp1, stop=False)
        self.i2c.writeto(self.addr, buf, stop=True)

At the moment, I have no SH1106 with I2C at hand for testing, so it's just a guess.

pacmac commented 7 years ago

Thanks so much, the first option worked, but the second one fails with:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "test/oled_sh.py", line 16, in <module>
  File "lib/sh1106.py", line 152, in __init__
  File "lib/sh1106.py", line 69, in __init__
  File "lib/sh1106.py", line 75, in init_display
  File "lib/sh1106.py", line 99, in show
  File "lib/sh1106.py", line 160, in write_data
TypeError: object with buffer protocol required

Also, forgot to mention that I am using the wipy-wroom build that I created and documented this morning ( https://forum.pycom.io/topic/1347/wipy-on-esp32-wroom-procedure ) and in the pycom version I don't think the last argument is used:

TypeError: function does not take keyword arguments

robert-hh commented 7 years ago

Oh yes. The two lines in init should be:

        self.temp1 = bytearray(1)
        self.temp1[0] = 0x40
pacmac commented 7 years ago

Unfortunately, that does not work:

I forgot to mention that I am using the wipy-wroom build that I created and documented this morning ( https://forum.pycom.io/topic/1347/wipy-on-esp32-wroom-procedure ) and in the pycom version I don't think the last argument is used:

TypeError: function does not take keyword arguments

pacmac commented 7 years ago

This works:

  def write_data(self, buf):
    try:
      self.i2c.writeto(self.addr, self.temp1)
    except:
      self.temp[0] = self.addr << 1
      self.temp[1] = 0x40 # Co=0, D/C#=1
      self.i2c.start()
      self.i2c.write(self.temp)
      self.i2c.write(buf)
      self.i2c.stop()
robert-hh commented 7 years ago

In that case the first variant rules. Are you sure that the code above is right? In the try branch the buffr is not written.

pacmac commented 7 years ago

Yes, you're correct, it was not updating, this is working:

  def write_data(self, buf):
    try:
      self.i2c.writeto(self.addr, b'\x40'+buf)
    except:
      self.temp[0] = self.addr << 1
      self.temp[1] = 0x40 # Co=0, D/C#=1
      self.i2c.start()
      self.i2c.write(self.temp)
      self.i2c.write(buf)
      self.i2c.stop()
robert-hh commented 7 years ago

Since writeto is supported by the esp8266 implementation too, the except branch is hardly ever taken. If you want to keep both, you have to switch the order. Try to use start/write first, and if that fails, use writeto. You can also test for th existence of the start() method with: if hasattr(i2c, "start"): Thats a little bit easire than try/except. Then the code would look like:

  def write_data(self, buf):
    if hasattr(self.i2c, "start"):
      self.temp[0] = self.addr << 1
      self.temp[1] = 0x40 # Co=0, D/C#=1
      self.i2c.start()
      self.i2c.write(self.temp)
      self.i2c.write(buf)
      self.i2c.stop()
    else:
      self.i2c.writeto(self.addr, b'\x40'+buf)

You can also create two different write_data methods, do that test once in init and assign one of the two methods to self.write_data.

pacmac commented 7 years ago

Nice idea, switching the method would be faster, so I have done that:

https://github.com/pacmac/micropython-share/blob/master/sh1106.py

pacmac commented 7 years ago

I can send you a 1.3" oled I2C sh1106 display if you like, would probably take a week to arrive though ?!

robert-hh commented 7 years ago

Not necessary. I have a spare SPI wired model at home. I just have to resolder it, which just requires getting it from home to the lab and doing the soldering here. We have good microscopes and (de)soldering tweezers here. That make the work more reliable.

pacmac commented 7 years ago

OK, I am closing this, thanks for the help, appreciate it.

robert-hh commented 7 years ago

Just a last note: I update the driver for two reasons: a) your changes to the code b) the microypython.org port does not support the pin.high() and pin.low() methods any more.