Welcome to the Pycom forum Forum
    • \[\[global:header.categories\]\]
    • \[\[global:header.recent\]\]
    • \[\[global:header.tags\]\]
    • \[\[global:header.popular\]\]
    • Login

    Explore Pybytes | Official Documentation | Report a Firmware Bug/Issue | GitHub

    I2C LCD: code inside

    Scheduled Pinned Locked Moved LoPy
    41 Posts 8 Posters 27.7k Views 8 Watching
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • D Offline
      DVE
      last edited by DVE

      Hi all,

      I'm new on this forum, and with LoPy also.
      I want to share my experience with 0.91" 128x32 I2C OLED Display, I forced it to work with LoPy.
      Its not mentioned clearly in the manual, i2c pins are G16,G17 on the prototype board (P9-P10 on the LoPy).

      So, it works :)
      alt text
      [0_1479599353875_DSC_0609.JPG]
      (It looks like inserting screenshots is not working here btw :) )

      Code here: https://github.com/dmitryelj/LoPyI2CLCD

      Its only a prototype, will be improved later

      PS: Update from 17.12.2016: SPI version added too.

      1 Reply Last reply Reply Quote 4
      • D Offline
        DVE
        last edited by DVE

        Strings support added:
        alt text

        Usage is easy, example:

            import sys,  machine
            
            # Types: 1 - 128x32 I2C OLED Display, 2 - 128x64 I2C OLED Display
            displayType = 1 
            initialize(displayType)
            set_contrast(128) # 1-255
            displayOn()
            clearBuffer()
            addString(0, 0,  sys.platform + " " + sys.version)
            addString(0, 1,  "---")
            addString(0, 2,  "CPU: {} MHz".format(machine.freq()[0]/1000000))
            drawBuffer()
        
        B 2 Replies Last reply Reply Quote 0
        • D Offline
          daniel
          last edited by

          @DVE Awesome!, thanks for sharing :-)

          1 Reply Last reply Reply Quote 0
          • R Offline
            rskoniec
            last edited by rskoniec

            @DVE Great! What about 128x64 version, because I saw some references in the code? Is it working?

            The machine is working as good as it's code.

            1 Reply Last reply Reply Quote 0
            • D Offline
              DVE
              last edited by

              128x64 display support was added to the source code, but I don't have a real display to test. So, you can try, but no guarantee :)

              R 1 Reply Last reply Reply Quote 0
              • R Offline
                rskoniec @DVE
                last edited by

                @DVE OK, thanks. I've just ordered one so I'll have the chance to check and let you know.

                The machine is working as good as it's code.

                1 Reply Last reply Reply Quote 0
                • B Offline
                  brotherdust @DVE
                  last edited by

                  @DVE said in I2C LCD: code inside:

                  Strings support added:
                  alt text

                  Usage is easy, example:

                      import sys,  machine
                      
                      initialize()
                      set_contrast(128) # 1-255
                      displayOn()
                      clearBuffer()
                      addString(0, 0,  sys.platform + " " + sys.version)
                      addString(0, 1,  "---")
                      addString(0, 2,  "CPU: {} MHz".format(machine.freq()[0]/1000000))
                      drawBuffer()
                  

                  @DVE Thanks for the code! I ordered a 128x96 display from Adafruit last week and expect to get it on Wednesday. When I have it in-hand, I will test your code and send a pull request over if I can get working. =)

                  B 1 Reply Last reply Reply Quote 0
                  • B Offline
                    brotherdust @brotherdust
                    last edited by

                    @brotherdust said in I2C LCD: code inside:

                    @DVE said in I2C LCD: code inside:

                    Strings support added:
                    alt text

                    Usage is easy, example:

                        import sys,  machine
                        
                        initialize()
                        set_contrast(128) # 1-255
                        displayOn()
                        clearBuffer()
                        addString(0, 0,  sys.platform + " " + sys.version)
                        addString(0, 1,  "---")
                        addString(0, 2,  "CPU: {} MHz".format(machine.freq()[0]/1000000))
                        drawBuffer()
                    

                    @DVE Thanks for the code! I ordered a 128x96 display from Adafruit last week and expect to get it on Wednesday. When I have it in-hand, I will test your code and send a pull request over if I can get working. =)

                    ahem Sorry. 128x64.

                    1 Reply Last reply Reply Quote 0
                    • B Offline
                      brotherdust @DVE
                      last edited by

                      @DVE So, I tried your code on my 128x64. It just shows up as a bunch of random noise on the display. =( I dug through the MP codebase and found this: https://github.com/pycom/pycom-micropython/blob/master/drivers/display/ssd1306.py

                      Lo and behold! It's for the same display driver as what we have! Wait.. no framebuf module.

                      Twiddled with the make configurations and managed to make a build with framebuf included. Trying it now. It's late so I might not report back until tomorrow.

                      R D 2 Replies Last reply Reply Quote 0
                      • R Offline
                        rskoniec @brotherdust
                        last edited by

                        @brotherdust Waiting for the news. :o)

                        The machine is working as good as it's code.

                        B 1 Reply Last reply Reply Quote 0
                        • D Offline
                          DVE @brotherdust
                          last edited by

                          @brotherdust, thanks for the link. I can test this driver also.

                          1 Reply Last reply Reply Quote 0
                          • B Offline
                            brotherdust @rskoniec
                            last edited by

                            @rskoniec said in I2C LCD: code inside:

                            @brotherdust Waiting for the news. :o)

                            Sorry! I was hacking on NyQuil last night. I got the framebuf code to compile and loaded it up on to one of my LoPy's. Tried the driver code, but all I got was the same result: a screen full of static. Same result as when I used @DVE 's code. Maybe my module is defective? Not sure. Anyway, tried a few things, couldn't get it to do anything different, then rage-quit because I wasn't clear-headed enough to figure out what the LoPy was telling me on the console. heh. Either of you have any luck?

                            B 1 Reply Last reply Reply Quote 0
                            • B Offline
                              brotherdust @brotherdust
                              last edited by brotherdust

                              Here's what I'm putting in:

                              # MicroPython SSD1306 OLED driver, I2C and SPI interfaces
                              
                              from micropython import const
                              import time
                              import framebuf
                              
                              
                              # register definitions
                              SET_CONTRAST        = const(0x81)
                              SET_ENTIRE_ON       = const(0xa4)
                              SET_NORM_INV        = const(0xa6)
                              SET_DISP            = const(0xae)
                              SET_MEM_ADDR        = const(0x20)
                              SET_COL_ADDR        = const(0x21)
                              SET_PAGE_ADDR       = const(0x22)
                              SET_DISP_START_LINE = const(0x40)
                              SET_SEG_REMAP       = const(0xa0)
                              SET_MUX_RATIO       = const(0xa8)
                              SET_COM_OUT_DIR     = const(0xc0)
                              SET_DISP_OFFSET     = const(0xd3)
                              SET_COM_PIN_CFG     = const(0xda)
                              SET_DISP_CLK_DIV    = const(0xd5)
                              SET_PRECHARGE       = const(0xd9)
                              SET_VCOM_DESEL      = const(0xdb)
                              SET_CHARGE_PUMP     = const(0x8d)
                              
                              
                              class SSD1306:
                                  def __init__(self, width, height, external_vcc):
                                      self.width = width
                                      self.height = height
                                      self.external_vcc = external_vcc
                                      self.pages = self.height // 8
                                      self.buffer = bytearray(self.pages * self.width)
                                      self.framebuf = framebuf.FrameBuffer1(self.buffer, self.width, self.height)
                                      self.poweron()
                                      self.init_display()
                              
                                  def init_display(self):
                                      for cmd in (
                                          SET_DISP | 0x00, # off
                                          # address setting
                                          SET_MEM_ADDR, 0x00, # horizontal
                                          # resolution and layout
                                          SET_DISP_START_LINE | 0x00,
                                          SET_SEG_REMAP | 0x01, # column addr 127 mapped to SEG0
                                          SET_MUX_RATIO, self.height - 1,
                                          SET_COM_OUT_DIR | 0x08, # scan from COM[N] to COM0
                                          SET_DISP_OFFSET, 0x00,
                                          SET_COM_PIN_CFG, 0x02 if self.height == 32 else 0x12,
                                          # timing and driving scheme
                                          SET_DISP_CLK_DIV, 0x80,
                                          SET_PRECHARGE, 0x22 if self.external_vcc else 0xf1,
                                          SET_VCOM_DESEL, 0x30, # 0.83*Vcc
                                          # display
                                          SET_CONTRAST, 0xff, # maximum
                                          SET_ENTIRE_ON, # output follows RAM contents
                                          SET_NORM_INV, # not inverted
                                          # charge pump
                                          SET_CHARGE_PUMP, 0x10 if self.external_vcc else 0x14,
                                          SET_DISP | 0x01): # on
                                          self.write_cmd(cmd)
                                      self.fill(0)
                                      self.show()
                              
                                  def poweroff(self):
                                      self.write_cmd(SET_DISP | 0x00)
                              
                                  def contrast(self, contrast):
                                      self.write_cmd(SET_CONTRAST)
                                      self.write_cmd(contrast)
                              
                                  def invert(self, invert):
                                      self.write_cmd(SET_NORM_INV | (invert & 1))
                              
                                  def show(self):
                                      x0 = 0
                                      x1 = self.width - 1
                                      if self.width == 64:
                                          # displays with width of 64 pixels are shifted by 32
                                          x0 += 32
                                          x1 += 32
                                      self.write_cmd(SET_COL_ADDR)
                                      self.write_cmd(x0)
                                      self.write_cmd(x1)
                                      self.write_cmd(SET_PAGE_ADDR)
                                      self.write_cmd(0)
                                      self.write_cmd(self.pages - 1)
                                      self.write_data(self.buffer)
                              
                                  def fill(self, col):
                                      self.framebuf.fill(col)
                              
                                  def pixel(self, x, y, col):
                                      self.framebuf.pixel(x, y, col)
                              
                                  def scroll(self, dx, dy):
                                      self.framebuf.scroll(dx, dy)
                              
                                  def text(self, string, x, y, col=1):
                                      self.framebuf.text(string, x, y, col)
                              
                              
                              class SSD1306_I2C(SSD1306):
                                  def __init__(self, width, height, i2c, addr=0x3c, external_vcc=False):
                                      self.i2c = i2c
                                      self.addr = addr
                                      self.temp = bytearray(2)
                                      super().__init__(width, height, external_vcc)
                              
                                  def write_cmd(self, cmd):
                                      self.temp[0] = 0x80 # Co=1, D/C#=0
                                      self.temp[1] = cmd
                                      self.i2c.writeto(self.addr, self.temp)
                              
                                  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 poweron(self):
                                      pass
                              
                              from machine import I2C
                              i2c = I2C(0, I2C.MASTER, baudrate=1000000)
                              display = SSD1306_I2C(width=128, height=64, i2c=i2c, addr=0x3d)
                              

                              The 128x64 display has hardware address of 0x3d. Anyway, here's what comes out:

                              Traceback (most recent call last):
                                File "<stdin>", line 1, in <module>
                                File "<stdin>", line 109, in __init__
                                File "<stdin>", line 37, in __init__
                                File "<stdin>", line 64, in init_display
                                File "<stdin>", line 89, in show
                                File "<stdin>", line 119, in write_data
                              AttributeError: 'I2C' object has no attribute 'start'
                              

                              The display turns on, but it's full of what looks like random noise. I looked through the source code for the I2C module and the start method is there:
                              https://github.com/pycom/pycom-micropython/blob/master/esp32/mods/machine_i2c.c#L348

                              STATIC mp_obj_t machine_i2c_start(mp_obj_t self_in) {
                                  machine_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in);
                                  mp_hal_i2c_start(self);
                                  return mp_const_none;
                              }
                              MP_DEFINE_CONST_FUN_OBJ_1(machine_i2c_start_obj, machine_i2c_start);
                              
                              >>> help(machine.I2C)
                              <class 'I2C'>object  is of type type
                                init -- <function>
                                scan -- <function>
                                readfrom -- <function>
                                readfrom_into -- <function>
                                writeto -- <function>
                                readfrom_mem -- <function>
                                readfrom_mem_into -- <function>
                                writeto_mem -- <function>
                                MASTER -- 0
                              

                              I don't get why it's not present in the list of available methods for this class. =/

                              1 Reply Last reply Reply Quote 0
                              • B Offline
                                brotherdust
                                last edited by

                                @DVE Update on using the built-in framebuffer and SSD1306 driver:
                                The driver was using I2C "primitives" that were disabled in the esp32 version of machine_i2c. The recent commits I've made on my relevant github repo:
                                https://github.com/brotherdust/pycom-micropython/commits/i2c-framebuf

                                I've made progress; but still learning how to use this stuff!

                                1 Reply Last reply Reply Quote 0
                                • B Offline
                                  brotherdust
                                  last edited by

                                  It works! Yay! Code later. Sleep now.

                                  D R 2 Replies Last reply Reply Quote 0
                                  • D Offline
                                    DVE @brotherdust
                                    last edited by DVE

                                    @brotherdust Its great :)

                                    I ordered 128x64 display too on Ebay, will be able to test next week.

                                    @brotherdust said in I2C LCD: code inside:

                                    The driver was using I2C "primitives" that were disabled in the esp32 version of machine_i2c

                                    How it works? Do you need to reload a firmware with enabled primitives?

                                    1 Reply Last reply Reply Quote 0
                                    • R Offline
                                      rskoniec @brotherdust
                                      last edited by

                                      @brotherdust Any chance for a code and answers for @DVE questions?

                                      The machine is working as good as it's code.

                                      B 1 Reply Last reply Reply Quote 0
                                      • B Offline
                                        brotherdust @rskoniec
                                        last edited by

                                        @rskoniec said in I2C LCD: code inside:

                                        @brotherdust Any chance for a code and answers for @DVE questions?

                                        @rskoniec, my apologies. I thought that I had answered this and didn't give it any more thought.

                                        The commit I referenced enables the I2C primitives. You'll need to recompile the firmware and upload it. Then the code will work.

                                        After reviewing the code a bit more, I think it can be refactored not to use the primitives (I2C.start, stop, etc). The primitives are already a part of other, more high-level routines. But the easiest way to get the driver going was just to enable those functions. =) I'm too lazy to re-factor and go through all the pull requests and justifications to get it included upstream.

                                        R R 2 Replies Last reply Reply Quote 0
                                        • R Offline
                                          rskoniec @brotherdust
                                          last edited by

                                          @brotherdust Thank you very much for quick reply. :o)

                                          The machine is working as good as it's code.

                                          1 Reply Last reply Reply Quote 0
                                          • D Offline
                                            DVE
                                            last edited by

                                            Got the 128x64 display this week. Stupid chinese seller sent SPI version instead of I2C.
                                            But I was able to add SPI support as well :)
                                            alt text

                                            Will update code soon.

                                            R 1 Reply Last reply Reply Quote 2

                                            Hello! It looks like you're interested in this conversation, but you don't have an account yet.

                                            Getting fed up of having to scroll through the same posts each visit? When you register for an account, you'll always come back to exactly where you were before, and choose to be notified of new replies (either via email, or push notification). You'll also be able to save bookmarks and upvote posts to show your appreciation to other community members.

                                            With your input, this post could be even better 💗

                                            Register Login
                                            • 1
                                            • 2
                                            • 3
                                            • 1 / 3
                                            • First post
                                              Last post

                                            Pycom on Twitter

                                            Pycom