I2C LCD: code inside
-
Very interested by your code version, thanks in advance.
-
This post is deleted!
-
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 :)
Will update code soon.
-
@brotherdust Thank you very much for quick reply. :o)
-
@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.
-
@brotherdust Any chance for a code and answers for @DVE questions?
-
@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?
-
It works! Yay! Code later. Sleep now.
-
@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-framebufI've made progress; but still learning how to use this stuff!
-
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#L348STATIC 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. =/
-
@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?
-
@brotherdust, thanks for the link. I can test this driver also.
-
@brotherdust Waiting for the news. :o)
-
@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.
-
@brotherdust said in I2C LCD: code inside:
@DVE said in I2C LCD: code inside:
Strings support added:
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.
-
@DVE said in I2C LCD: code inside:
Strings support added:
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. =)
-
@DVE OK, thanks. I've just ordered one so I'll have the chance to check and let you know.
-
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 :)
-
@DVE Great! What about 128x64 version, because I saw some references in the code? Is it working?
-
@DVE Awesome!, thanks for sharing :-)