Mercurial > micropython-rgb
changeset 0:4eae06eeba7c
Add initial set of display drivers
| author | Radomir Dopieralski <sheep-devel@sheep.art.pl> |
|---|---|
| date | Sun, 28 Aug 2016 10:49:29 +0200 |
| parents | |
| children | 085126ee39f9 |
| files | display.py hx8353.py ili9341.py s6d02a1.py ssd1331.py ssd1351.py st7735.py |
| diffstat | 7 files changed, 536 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/display.py Sun Aug 28 10:49:29 2016 +0200 @@ -0,0 +1,139 @@ +import time +import ustruct + + +def color565(r, g, b): + return (r & 0xf8) << 8 | (g & 0xfc) << 3 | b >> 3 + + +class DummyPin: + """A fake gpio pin for when you want to skip pins.""" + def init(self, *args, **kwargs): + pass + + def low(self): + pass + + def high(self): + pass + + +class Display: + _PAGE_SET = None + _COLUMN_SET = None + _RAM_WRITE = None + _RAM_READ = None + _INIT = () + _ENCODE_PIXEL = ">H" + _ENCODE_POS = ">HH" + _DECODE_PIXEL = ">BBB" + + def __init__(self, width, height): + self.width = width + self.height = height + self.init() + + def init(self): + """Run the initialization commands.""" + for command, data in self._INIT: + self._write(command, data) + + def _block(self, x0, y0, x1, y1, data=None): + """Read or write a block of data.""" + self._write(self._COLUMN_SET, self._encode_pos(x0, x1)) + self._write(self._PAGE_SET, self._encode_pos(y0, y1)) + if data is None: + size = ustruct.calcsize(self._DECODE_PIXEL) + return self._read(self._RAM_READ, + (x1 - x0 + 1) * (y1 - y0 + 1) * size) + self._write(self._RAM_WRITE, data) + + def _encode_pos(self, a, b): + """Encode a postion into bytes.""" + return ustruct.pack(self._ENCODE_POS, a, b) + + def _encode_pixel(self, color): + """Encode a pixel color into bytes.""" + return ustruct.pack(self._ENCODE_PIXEL, color) + + def _decode_pixel(self, data): + """Decode bytes into a pixel color.""" + return color565(*ustruct.unpack(self._DECODE_PIXEL, data)) + + def pixel(self, x, y, color=None): + """Read or write a pixel.""" + if color is None: + return self._decode_pixel(self._block(x, y, x, y)) + if not 0 <= x < self.width or not 0 <= y < self.height: + return + self._block(x, y, x, y, self._encode_pixel(color)) + + def fill_rectangle(self, x, y, w, h, color): + """Draw a filled rectangle.""" + x = min(self.width - 1, max(0, x)) + y = min(self.height - 1, max(0, y)) + w = min(self.width - x, max(1, w)) + h = min(self.height - y, max(1, h)) + self._block(x, y, x + w - 1, y + h - 1, b'') + chunks, rest = divmod(w * h, 512) + pixel = self._encode_pixel(color) + if chunks: + data = pixel * 512 + for count in range(chunks): + self._write(None, data) + self._write(None, pixel * rest) + + def fill(self, color=0): + """Fill whole screen.""" + self.fill_rectangle(0, 0, self.width, self.height, color) + + def hline(self, x, y, width, color): + """Draw a horizontal line.""" + self.fill_rectangle(x, y, width, 1, color) + + def vline(self, x, y, height, color): + """Draw a vertical line.""" + self.fill_rectangle(x, y, 1, height, color) + + +class DisplaySPI(Display): + def __init__(self, spi, dc, cs, rst=None, width=1, height=1): + self.spi = spi + self.cs = cs + self.dc = dc + self.rst = rst + self.cs.init(self.cs.OUT, value=1) + self.dc.init(self.dc.OUT, value=0) + if self.rst: + self.rst.init(self.rst.OUT, value=0) + self.reset() + super().__init__(width, height) + + def reset(self): + self.rst.low() + time.sleep_ms(50) + self.rst.high() + time.sleep_ms(50) + + def _write(self, command=None, data=None): + if command is not None: + self.dc.low() + self.cs.low() + self.spi.write(bytearray([command])) + self.cs.high() + if data is not None: + self.dc.high() + self.cs.low() + self.spi.write(data) + self.cs.high() + + def _read(self, command=None, count=0): + self.dc.low() + self.cs.low() + if command is not None: + self.spi.write(bytearray([command])) + if count: + data = self.spi.read(count) + self.cs.high() + return data +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hx8353.py Sun Aug 28 10:49:29 2016 +0200 @@ -0,0 +1,40 @@ +from display import DisplaySPI, color565 + +_SWRESET = const(0x01) +_NORON = const(0x13) +_INVOFF = const(0x20) +_INVON = const(0x21) +_DISPOFF = const(0x28) +_DISPON = const(0x29) +_CASET = const(0x2a) +_PASET = const(0x2b) +_RAMWR = const(0x2c) +_RAMRD = const(0x2e) +_MADCTL = const(0x36) +_COLMOD = const(0x3a) + +class HX8353(DisplaySPI): + """ + A simple driver for the ST7735-based displays. + + >>> from machine import Pin, SPI + >>> import hx8353 + >>> spi = SPI(0) + >>> display = hx8353.HX8383(spi, dc=Pin(0), cs=Pin(15), rst=Pin(16)) + >>> display.fill(0x7521) + >>> display.pixel(64, 64, 0) + + """ + _COLUMN_SET = _CASET + _PAGE_SET = _PASET + _RAM_WRITE = _RAMWR + _RAM_READ = _RAMRD + _INIT = ( + (_SWRESET, None), + (_DISPON, None), + ) + _ENCODE_PIXEL = ">H" + _ENCODE_POS = ">HH" + + def __init__(self, spi, dc, cs, rst=None, width=128, height=128): + super().__init__(spi, dc, cs, rst, width, height)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ili9341.py Sun Aug 28 10:49:29 2016 +0200 @@ -0,0 +1,59 @@ +import ustruct +from display import DisplaySPI, color565 + + +class ILI9341(DisplaySPI): + """ + A simple driver for the ILI9341/ILI9340-based displays. + + + >>> import ili9341 + >>> from machine import Pin, SPI + >>> spi = SPI(mosi=Pin(13), sck=Pin(14)) + >>> display = ili9341.ILI9341(spi, cs=Pin(15), dc=Pin(12), rst=Pin(16)) + >>> display.fill(ili9341.color565(0xff, 0x11, 0x22)) + >>> display.pixel(120, 160, 0) + """ + + _COLUMN_SET = 0x2a + _PAGE_SET = 0x2b + _RAM_WRITE = 0x2c + _RAM_READ = 0x2e + _INIT = ( + (0xef, b'\x03\x80\x02'), + (0xcf, b'\x00\xc1\x30'), + (0xed, b'\x64\x03\x12\x81'), + (0xe8, b'\x85\x00\x78'), + (0xcb, b'\x39\x2c\x00\x34\x02'), + (0xf7, b'\x20'), + (0xea, b'\x00\x00'), + (0xc0, b'\x23'), # Power Control 1, VRH[5:0] + (0xc1, b'\x10'), # Power Control 2, SAP[2:0], BT[3:0] + (0xc5, b'\x3e\x28'), # VCM Control 1 + (0xc7, b'\x86'), # VCM Control 2 + (0x36, b'\x48'), # Memory Access Control + (0x3a, b'\x55'), # Pixel Format + (0xb1, b'\x00\x18'), # FRMCTR1 + (0xb6, b'\x08\x82\x27'), # Display Function Control + (0xf2, b'\x00'), # 3Gamma Function Disable + (0x26, b'\x01'), # Gamma Curve Selected + (0xe0, # Set Gamma + b'\x0f\x31\x2b\x0c\x0e\x08\x4e\xf1\x37\x07\x10\x03\x0e\x09\x00'), + (0xe1, # Set Gamma + b'\x00\x0e\x14\x03\x11\x07\x31\xc1\x48\x08\x0f\x0c\x31\x36\x0f'), + (0x11, None), + (0x29, None), + ) + _ENCODE_PIXEL = ">H" + _ENCODE_POS = ">HH" + _DECODE_PIXEL = ">BBB" + + def __init__(self, spi, dc, cs, rst=None, width=240, height=320): + super().__init__(spi, dc, cs, rst, width, height) + self._scroll = 0 + + def scroll(self, dy=None): + if dy is None: + return self._scroll + self._scroll = (self._scroll + dy) % self.height + self._write(0x37, ustruct.pack('>H', self._scroll))
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/s6d02a1.py Sun Aug 28 10:49:29 2016 +0200 @@ -0,0 +1,40 @@ +from display import DisplaySPI, color565 + +_SWRESET = const(0x01) +_DISPON = const(0x29) +_SLEEPOUT = const(0x11) +_CASET = const(0x2a) +_PASET = const(0x2b) +_RAMWR = const(0x2c) +_RAMRD = const(0x2e) +_COLMOD = const(0x3a) +_MADCTL = const(0x36) + +class S6D02A1(DisplaySPI): + """ + A simple driver for the ST7735-based displays. + + >>> from machine import Pin, SPI + >>> import s6d02a1 + >>> spi = SPI(0, baudrate=40000000) + >>> display = s6d02a1.S6D02A1(spi, dc=Pin(0), cs=Pin(15), rst=Pin(16)) + >>> display.fill(0x7521) + >>> display.pixel(64, 64, 0) + + """ + _COLUMN_SET = _CASET + _PAGE_SET = _PASET + _RAM_WRITE = _RAMWR + _RAM_READ = _RAMRD + _INIT = ( + (_SWRESET, None), + (_SLEEPOUT, None), + (_MADCTL, b'\x10'), # bottom-top + (_COLMOD, b'\x05'), # RGB565 pixel format + (_DISPON, None), + ) + _ENCODE_PIXEL = ">H" + _ENCODE_POS = ">HH" + + def __init__(self, spi, dc, cs, rst=None, width=128, height=160): + super().__init__(spi, dc, cs, rst, width, height)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ssd1331.py Sun Aug 28 10:49:29 2016 +0200 @@ -0,0 +1,81 @@ +from display import DisplaySPI, color565 + + +_DRAWLINE = const(0x21) +_DRAWRECT = const(0x22) +_FILL = const(0x26) +_PHASEPERIOD = const(0x12) +_SETCOLUMN = const(0x15) +_SETROW = const(0x75) +_CONTRASTA = const(0x81) +_CONTRASTB = const(0x82) +_CONTRASTC = const(0x83) +_MASTERCURRENT = const(0x87) +_SETREMAP = const(0xA0) +_STARTLINE = const(0xA1) +_DISPLAYOFFSET = const(0xA2) +_NORMALDISPLAY = const(0xA4) +_DISPLAYALLON = const(0xA5) +_DISPLAYALLOFF = const(0xA6) +_INVERTDISPLAY = const(0xA7) +_SETMULTIPLEX = const(0xA8) +_SETMASTER = const(0xAD) +_DISPLAYOFF = const(0xAE) +_DISPLAYON = const(0xAF) +_POWERMODE = const(0xB0) +_PRECHARGE = const(0xB1) +_CLOCKDIV = const(0xB3) +_PRECHARGEA = const(0x8A) +_PRECHARGEB = const(0x8B) +_PRECHARGEC = const(0x8C) +_PRECHARGELEVEL = const(0xBB) +_VCOMH = const(0xBE) +_LOCK = const(0xfd) + + +class SSD1331(DisplaySPI): + """ +>>> +from machine import Pin, HSPI +import ssd1331 +#spi = SPI(mosi=Pin(13), sck=Pin(14), polarity=1, phase=1) +spi = HSPI(polarity=1, phase=1) +display = ssd1331.SSD1331(spi, dc=Pin(2), cs=Pin(15), rst=Pin(16)) +display.fill(0x7521) +display.pixel(32, 32, 0) + """ + _COLUMN_SET = _SETCOLUMN + _PAGE_SET = _SETROW + _RAM_WRITE = None + _RAM_READ = None + _INIT = ( + (_DISPLAYOFF, b''), + (_LOCK, b'\x0b'), + (_SETREMAP, b'\x72'), # RGB Color + (_STARTLINE, b'\x00'), + (_DISPLAYOFFSET, b'\x00'), + (_NORMALDISPLAY, b''), +# (_FILL, b'\x01'), + +# (_PHASEPERIOD, b'\x31'), +# (_SETMULTIPLEX, b'\x3f'), +# (_SETMASTER, b'\x8e'), +# (_POWERMODE,b'\x0b'), +# (_PRECHARGE, b'\x31'), #;//0x1F - 0x31 +# (_CLOCKDIV, b'\xf0'), +# (_VCOMH, b'\x3e'), #;//0x3E - 0x3F +# (_MASTERCURRENT, b'\x06'), # ;//0x06 - 0x0F +# (_PRECHARGEA, b'\x64'), +# (_PRECHARGEB, b'\x78'), +# (_PRECHARGEC, b'\x64'), +# (_PRECHARGELEVEL, b'\x3a'), # 0x3A - 0x00 +# (_CONTRASTA, b'\x91'), #//0xEF - 0x91 +# (_CONTRASTB, b'\x50'), #;//0x11 - 0x50 +# (_CONTRASTC, b'\x7d'), #;//0x48 - 0x7D + (_DISPLAYON, b''), + ) + _ENCODE_PIXEL = ">H" + _ENCODE_POS = ">BB" + + def __init__(self, spi, dc, cs, rst=None, width=96, height=64): + super().__init__(spi, dc, cs, rst, width, height)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ssd1351.py Sun Aug 28 10:49:29 2016 +0200 @@ -0,0 +1,81 @@ +from display import DisplaySPI, color565 + + +_SETCOLUMN = const(0x15) +_SETROW = const(0x75) +_WRITERAM = const(0x5C) +_READRAM = const(0x5D) +_SETREMAP = const(0xA0) +_STARTLINE = const(0xA1) +_DISPLAYOFFSET = const(0xA2) +_DISPLAYALLOFF = const(0xA4) +_DISPLAYALLON = const(0xA5) +_NORMALDISPLAY = const(0xA6) +_INVERTDISPLAY = const(0xA7) +_FUNCTIONSELECT = const(0xAB) +_DISPLAYOFF = const(0xAE) +_DISPLAYON = const(0xAF) +_PRECHARGE = const(0xB1) +_DISPLAYENHANCE = const(0xB2) +_CLOCKDIV = const(0xB3) +_SETVSL = const(0xB4) +_SETGPIO = const(0xB5) +_PRECHARGE2 = const(0xB6) +_SETGRAY = const(0xB8) +_USELUT = const(0xB9) +_PRECHARGELEVEL = const(0xBB) +_VCOMH = const(0xBE) +_CONTRASTABC = const(0xC1) +_CONTRASTMASTER = const(0xC7) +_MUXRATIO = const(0xCA) +_COMMANDLOCK = const(0xFD) +_HORIZSCROLL = const(0x96) +_STOPSCROLL = const(0x9E) +_STARTSCROLL = const(0x9F) + + +class SSD1351(DisplaySPI): + """ +>>> +from machine import Pin, SPI +import ssd1351 +spi = SPI(mosi=Pin(13), sck=Pin(14)) +display = ssd1351.SSD1351(spi, dc=Pin(12), cs=Pin(15), rst=Pin(16)) +display.fill(0x7521) +display.pixel(32, 32, 0) + """ + + _COLUMN_SET = _SETCOLUMN + _PAGE_SET = _SETROW + _RAM_WRITE = _WRITERAM + _RAM_READ = _READRAM + _INIT = ( + (_COMMANDLOCK, b'\x12'), + (_COMMANDLOCK, b'\xb1'), + (_DISPLAYOFF, b''), + (_DISPLAYENHANCE, b'\xa4\x00\x00'), + # 7:4 = Oscillator Frequency, + # 3:0 = CLK Div Ratio (A[3:0]+1 = 1..16) + (_CLOCKDIV, b'\xf0'), + (_MUXRATIO, b'\x7f'), # 127 + (_SETREMAP, b'\x74'), + (_STARTLINE, b'\x00'), + (_DISPLAYOFFSET, b'\x00'), + (_SETGPIO, b'\x00'), + (_FUNCTIONSELECT, b'\x01'), + (_PRECHARGE, b'\x32'), + (_PRECHARGELEVEL, b'\x1f'), + (_VCOMH, b'\x05'), + (_NORMALDISPLAY, b''), + (_CONTRASTABC, b'\xc8\x80\xc8'), + (_CONTRASTMASTER, b'\x0a'), + (_SETVSL, b'\xa0\xb5\x55'), + (_PRECHARGE2, b'\x01'), + (_DISPLAYON, b''), + ) + _ENCODE_PIXEL = ">H" + _ENCODE_POS = ">BB" + + def __init__(self, spi, dc, cs, rst=None, width=128, height=128): + super().__init__(spi, dc, cs, rst, width, height) +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/st7735.py Sun Aug 28 10:49:29 2016 +0200 @@ -0,0 +1,96 @@ +from display import DisplaySPI, color565 + + +_NOP=const(0x00) +_SWRESET=const(0x01) +_RDDID=const(0x04) +_RDDST=const(0x09) + +_SLPIN=const(0x10) +_SLPOUT=const(0x11) +_PTLON=const(0x12) +_NORON=const(0x13) + +_INVOFF=const(0x20) +_INVON=const(0x21) +_DISPOFF=const(0x28) +_DISPON=const(0x29) +_CASET=const(0x2A) +_RASET=const(0x2B) +_RAMWR=const(0x2C) +_RAMRD=const(0x2E) + +_PTLAR=const(0x30) +_COLMOD=const(0x3A) +_MADCTL=const(0x36) + +_FRMCTR1=const(0xB1) +_FRMCTR2=const(0xB2) +_FRMCTR3=const(0xB3) +_INVCTR=const(0xB4) +_DISSET5=const(0xB6) + +_PWCTR1=const(0xC0) +_PWCTR2=const(0xC1) +_PWCTR3=const(0xC2) +_PWCTR4=const(0xC3) +_PWCTR5=const(0xC4) +_VMCTR1=const(0xC5) + +_RDID1=const(0xDA) +_RDID2=const(0xDB) +_RDID3=const(0xDC) +_RDID4=const(0xDD) + +_PWCTR6=const(0xFC) + +_GMCTRP1=const(0xE0) +_GMCTRN1=const(0xE1) + + +class ST7735(DisplaySPI): + """ + A simple driver for the ST7735-based displays. + + >>> from machine import Pin, SPI + >>> import st7735 + >>> spi = SPI(mosi=Pin(13), sck=Pin(14)) + >>> display = st7735.ST7735(spi, dc=Pin(12), cs=Pin(15), rst=Pin(16)) + >>> display.fill(0x7521) + >>> display.pixel(64, 64, 0) + + """ + _COLUMN_SET = _CASET + _PAGE_SET = _RASET + _RAM_WRITE = _RAMWR + _RAM_READ = _RAMRD + _INIT = ( + (_SWRESET, None), + (_SLPOUT, None), + (_COLMOD, b'\x05'), # 16bit color + # fastest refresh, 6 lines front porch, 3 line back porch + (_FRMCTR1, b'\x00\x06\x03'), + (_MADCTL, b'\x08'), # bottom to top refresh + # 1 clk cycle nonoverlap, 2 cycle gate rise, 3 sycle osc equalie, + # fix on VTL + (_DISSET5, b'\x15\x02'), + (_INVCTR, b'0x00'), # line inversion + (_PWCTR1, b'\x02\x70'), # GVDD = 4.7V, 1.0uA + (_PWCTR2, b'\x05'), # VGH=14.7V, VGL=-7.35V + (_PWCTR3, b'\x01\x02'), # Opamp current small, Boost frequency + (_VMCTR1, b'\x3c\x38'), # VCOMH = 4V, VOML = -1.1V + (_PWCTR6, b'\x11\x15'), + (_GMCTRP1, b'\x09\x16\x09\x20\x21\x1b\x13\x19' + b'\x17\x15\x1e\x2b\x04\x05\x02\x0e'), # Gamma + (_GMCTRN1, b'\x08\x14\x08\x1e\x22\x1d\x18\x1e' + b'\x18\x1a\x24\x2b\x06\x06\x02\x0f'), + (_CASET, b'\x00\x02\x00\x81'), # XSTART = 2, XEND = 129 + (_RASET, b'\x00\x02\x00\x81'), # XSTART = 2, XEND = 129 + (_NORON, None), + (_DISPON, None), + ) + _ENCODE_PIXEL = ">H" + _ENCODE_POS = ">HH" + + def __init__(self, spi, dc, cs, rst=None, width=128, height=128): + super().__init__(spi, dc, cs, rst, width, height)
