Damien George
8 years ago
2 changed files with 625 additions and 0 deletions
@ -0,0 +1,464 @@ |
|||
# Driver for official MicroPython LCD160CR display |
|||
# MIT license; Copyright (c) 2017 Damien P. George |
|||
|
|||
from micropython import const |
|||
from utime import sleep_ms |
|||
from ustruct import calcsize, pack_into |
|||
import uerrno, machine |
|||
|
|||
# for set_orient |
|||
PORTRAIT = const(0) |
|||
LANDSCAPE = const(1) |
|||
PORTRAIT_UPSIDEDOWN = const(2) |
|||
LANDSCAPE_UPSIDEDOWN = const(3) |
|||
|
|||
# for set_startup_deco; can be or'd |
|||
STARTUP_DECO_NONE = const(0) |
|||
STARTUP_DECO_MLOGO = const(1) |
|||
STARTUP_DECO_INFO = const(2) |
|||
|
|||
_uart_baud_table = { |
|||
2400: 0, |
|||
4800: 1, |
|||
9600: 2, |
|||
19200: 3, |
|||
38400: 4, |
|||
57600: 5, |
|||
115200: 6, |
|||
230400: 7, |
|||
460800: 8, |
|||
} |
|||
|
|||
class LCD160CR: |
|||
def __init__(self, connect=None, *, pwr=None, i2c=None, spi=None, i2c_addr=98): |
|||
if connect in ('X', 'Y', 'XY', 'YX'): |
|||
i = connect[-1] |
|||
j = connect[0] |
|||
y = j + '4' |
|||
elif connect == 'C': |
|||
i = 2 |
|||
j = 2 |
|||
y = 'A7' |
|||
else: |
|||
if pwr is None or i2c is None or spi is None: |
|||
raise ValueError('must specify valid "connect" or all of "pwr", "i2c" and "spi"') |
|||
|
|||
if pwr is None: |
|||
pwr = machine.Pin(y, machine.Pin.OUT) |
|||
if i2c is None: |
|||
i2c = machine.I2C(i, freq=1000000) |
|||
if spi is None: |
|||
spi = machine.SPI(j, baudrate=13500000, polarity=0, phase=0) |
|||
|
|||
if not pwr.value(): |
|||
pwr(1) |
|||
sleep_ms(10) |
|||
# else: |
|||
# alread have power |
|||
# lets be optimistic... |
|||
|
|||
# set connections |
|||
self.pwr = pwr |
|||
self.i2c = i2c |
|||
self.spi = spi |
|||
self.i2c_addr = i2c_addr |
|||
|
|||
# create temp buffers and memoryviews |
|||
self.buf16 = bytearray(16) |
|||
self.buf19 = bytearray(19) |
|||
self.buf = [None] * 10 |
|||
for i in range(1, 10): |
|||
self.buf[i] = memoryview(self.buf16)[0:i] |
|||
self.buf1 = self.buf[1] |
|||
self.array4 = [0, 0, 0, 0] |
|||
|
|||
# set default orientation and window |
|||
self.set_orient(PORTRAIT) |
|||
self._fcmd2b('<BBBBBB', 0x76, 0, 0, self.w, self.h) # viewport 'v' |
|||
self._fcmd2b('<BBBBBB', 0x79, 0, 0, self.w, self.h) # window 'y' |
|||
|
|||
def _send(self, cmd): |
|||
i = self.i2c.writeto(self.i2c_addr, cmd) |
|||
if i == len(cmd): |
|||
return |
|||
cmd = memoryview(cmd) |
|||
n = len(cmd) |
|||
while True: |
|||
i += self.i2c.writeto(self.i2c_addr, cmd[i:]) |
|||
if i == n: |
|||
return |
|||
sleep_ms(10) |
|||
|
|||
def _fcmd2(self, fmt, a0, a1=0, a2=0): |
|||
buf = self.buf[calcsize(fmt)] |
|||
pack_into(fmt, buf, 0, 2, a0, a1, a2) |
|||
self._send(buf) |
|||
|
|||
def _fcmd2b(self, fmt, a0, a1, a2, a3, a4=0): |
|||
buf = self.buf[calcsize(fmt)] |
|||
pack_into(fmt, buf, 0, 2, a0, a1, a2, a3, a4) |
|||
self._send(buf) |
|||
|
|||
def _waitfor(self, n, buf): |
|||
t = 5000 |
|||
while t: |
|||
self.i2c.readfrom_into(self.i2c_addr, self.buf1) |
|||
if self.buf1[0] >= n: |
|||
self.i2c.readfrom_into(self.i2c_addr, buf) |
|||
return |
|||
t -= 1 |
|||
sleep_ms(1) |
|||
raise OSError(uerrno.ETIMEDOUT) |
|||
|
|||
def oflush(self, n=255): |
|||
t = 5000 |
|||
while t: |
|||
self.i2c.readfrom_into(self.i2c_addr + 1, self.buf1) |
|||
r = self.buf1[0] |
|||
if r >= n: |
|||
return |
|||
t -= 1 |
|||
machine.idle() |
|||
raise OSError(uerrno.ETIMEDOUT) |
|||
|
|||
def iflush(self): |
|||
t = 5000 |
|||
while t: |
|||
self.i2c.readfrom_into(self.i2c_addr, self.buf16) |
|||
if self.buf16[0] == 0: |
|||
return |
|||
t -= 1 |
|||
sleep_ms(1) |
|||
raise OSError(uerrno.ETIMEDOUT) |
|||
|
|||
#### MISC METHODS #### |
|||
|
|||
@staticmethod |
|||
def rgb(r, g, b): |
|||
return ((b & 0xf8) << 8) | ((g & 0xfc) << 3) | (r >> 3) |
|||
|
|||
@staticmethod |
|||
def clip_line(c, w, h): |
|||
while True: |
|||
ca = ce = 0 |
|||
if c[1] < 0: |
|||
ca |= 8 |
|||
elif c[1] > h: |
|||
ca |= 4 |
|||
if c[0] < 0: |
|||
ca |= 1 |
|||
elif c[0] > w: |
|||
ca |= 2 |
|||
if c[3] < 0: |
|||
ce |= 8 |
|||
elif c[3] > h: |
|||
ce |= 4 |
|||
if c[2] < 0: |
|||
ce |= 1 |
|||
elif c[2] > w: |
|||
ce |= 2 |
|||
if ca & ce: |
|||
return False |
|||
elif ca | ce: |
|||
ca |= ce |
|||
if ca & 1: |
|||
if c[2] < c[0]: |
|||
c[0], c[2] = c[2], c[0] |
|||
c[1], c[3] = c[3], c[1] |
|||
c[1] += ((-c[0]) * (c[3] - c[1])) // (c[2] - c[0]) |
|||
c[0] = 0 |
|||
elif ca & 2: |
|||
if c[2] < c[0]: |
|||
c[0], c[2] = c[2], c[0] |
|||
c[1], c[3] = c[3], c[1] |
|||
c[3] += ((w - 1 - c[2]) * (c[3] - c[1])) // (c[2] - c[0]) |
|||
c[2] = w - 1 |
|||
elif ca & 4: |
|||
if c[0] == c[2]: |
|||
if c[1] >= h: |
|||
c[1] = h - 1 |
|||
if c[3] >= h: |
|||
c[3] = h - 1 |
|||
else: |
|||
if c[3] < c[1]: |
|||
c[0], c[2] = c[2], c[0] |
|||
c[1], c[3] = c[3], c[1] |
|||
c[2] += ((h - 1 - c[3]) * (c[2] - c[0])) // (c[3] - c[1]) |
|||
c[3] = h - 1 |
|||
else: |
|||
if c[0] == c[2]: |
|||
if c[1] < 0: |
|||
c[1] = 0 |
|||
if c[3] < 0: |
|||
c[3] = 0 |
|||
else: |
|||
if c[3] < c[1]: |
|||
c[0], c[2] = c[2], c[0] |
|||
c[1], c[3] = c[3], c[1] |
|||
c[0] += ((-c[1]) * (c[2] - c[0])) // (c[3] - c[1]) |
|||
c[1] = 0 |
|||
else: |
|||
return True |
|||
|
|||
#### SETUP COMMANDS #### |
|||
|
|||
def set_power(self, on): |
|||
self.pwr(value) |
|||
sleep_ms(15) |
|||
|
|||
def set_orient(self, orient): |
|||
self._fcmd2('<BBB', 0x14, (orient & 3) + 4) |
|||
# update width and height variables |
|||
self.iflush() |
|||
self._send(b'\x02g0') |
|||
self._waitfor(4, self.buf[5]) |
|||
self.w = self.buf[5][1] |
|||
self.h = self.buf[5][2] |
|||
|
|||
def set_brightness(self, value): |
|||
self._fcmd2('<BBB', 0x16, value) |
|||
|
|||
def set_i2c_addr(self, addr): |
|||
# 0x0e set i2c addr |
|||
if addr & 3: |
|||
raise ValueError('must specify mod 4 aligned address') |
|||
self._fcmd2('<BBW', 0x0e, 0x433249 | (addr << 24)) |
|||
|
|||
def set_uart_baudrate(self, baudrate): |
|||
try: |
|||
baudrate = _uart_baud_table[baudrate] |
|||
except KeyError: |
|||
raise ValueError('invalid baudrate') |
|||
self._fcmd2('<BBB', 0x18, baudrate) |
|||
|
|||
def set_startup_deco(self, value): |
|||
self._fcmd2('<BBB', 0x19, value) |
|||
|
|||
def save_to_flash(self): |
|||
self._fcmd2('<BBB', 0x66, 'n') |
|||
|
|||
#### PIXEL ACCESS #### |
|||
|
|||
def set_pixel(self, x, y, c): |
|||
self._fcmd2b('<BBBBH', 0x41, x, y, c) |
|||
|
|||
def get_pixel(self, x, y): |
|||
self._fcmd2b('<BBBB', 0x61, x, y) |
|||
t = 1000 |
|||
while t: |
|||
self.i2c.readfrom_into(self.i2c_addr, self.buf1) |
|||
if self.buf1[0] >= 2: |
|||
self.i2c.readfrom_into(self.i2c_addr, self.buf[3]) |
|||
return self.buf[3][1] + self.buf[3][2] << 8 |
|||
t -= 1 |
|||
sleep_ms(1) |
|||
raise OSError(uerrno.ETIMEDOUT) |
|||
|
|||
def get_line(self, x, y, buf): |
|||
l = len(buf) // 2 |
|||
self._fcmd2b('<BBBBB', 0x10, l, x, y) |
|||
t = 1000 |
|||
while t: |
|||
self.i2c.readfrom_into(self.i2c_addr, self.buf1) |
|||
if self.buf1[0] >= l: |
|||
self.i2c.readfrom_into(self.i2c_addr, buf) |
|||
return |
|||
t -= 1 |
|||
sleep_ms(1) |
|||
raise OSError(uerrno.ETIMEDOUT) |
|||
|
|||
def screen_dump(self, buf): |
|||
line = bytearray(self.w + 1) |
|||
h = len(buf) // (2 * self.w) |
|||
if h > self.h: |
|||
h = self.h |
|||
for i in range(h): |
|||
ix = i * self.w * 2 |
|||
self.get_line(0, i, line) |
|||
for j in range(1, len(line)): |
|||
buf[ix] = line[j] |
|||
ix += 1 |
|||
self.get_line(self.w // 2, i, line) |
|||
for j in range(1, len(line)): |
|||
buf[ix] = line[j] |
|||
ix += 1 |
|||
|
|||
def screen_load(self, buf): |
|||
l = self.w * self.h * 2+2 |
|||
self._fcmd2b('<BBHBBB', 0x70, l, 16, self.w, self.h) |
|||
n = 0 |
|||
ar = memoryview(buf) |
|||
while n < len(buf): |
|||
if len(buf) - n >= 0x200: |
|||
self._send(ar[n:n + 0x200]) |
|||
n += 0x200 |
|||
else: |
|||
self._send(ar[n:]) |
|||
while n < self.w * self.h * 2: |
|||
self._send(b'\x00') |
|||
n += 1 |
|||
|
|||
#### TEXT COMMANDS #### |
|||
|
|||
def set_pos(self, x, y): |
|||
self._fcmd2('<BBBB', 0x58, x, y) |
|||
|
|||
def set_text_color(self, fg, bg): |
|||
self._fcmd2('<BBHH', 0x63, fg, bg) |
|||
|
|||
def set_font(self, font, scale=0, bold=0, trans=0, scroll=0): |
|||
self._fcmd2('<BBBB', 0x46, (scroll << 7) | (trans << 6) | ((font & 3) << 4) | (bold & 0xf), scale & 0xff) |
|||
|
|||
def write(self, s): |
|||
# TODO: eventually check for room in LCD input queue |
|||
self._send(s) |
|||
|
|||
#### PRIMITIVE DRAWING COMMANDS #### |
|||
|
|||
def set_pen(self, line, fill): |
|||
self._fcmd2('<BBHH', 0x50, line, fill) |
|||
|
|||
def erase(self): |
|||
self._send(b'\x02\x45') |
|||
|
|||
def dot(self, x, y): |
|||
if 0 <= x < self.w and 0 <= y < self.h: |
|||
self._fcmd2('<BBBB', 0x4b, x, y) |
|||
|
|||
def rect(self, x, y, w, h, cmd=0x72): |
|||
if x + w <= 0 or y + h <= 0 or x >= self.w or y >= self.h: |
|||
return |
|||
elif x < 0 or y < 0: |
|||
left = top = True |
|||
if x < 0: |
|||
left = False |
|||
w += x |
|||
x = 0 |
|||
if y < 0: |
|||
top = False |
|||
h += y |
|||
y = 0 |
|||
if cmd == 0x51 or cmd == 0x72: |
|||
# draw interior |
|||
self._fcmd2b('<BBBBBB', 0x51, x, y, min(w, 255), min(h, 255)) |
|||
if cmd == 0x57 or cmd == 0x72: |
|||
# draw outline |
|||
if left: |
|||
self._fcmd2b('<BBBBBB', 0x57, x, y, 1, min(h, 255)) |
|||
if top: |
|||
self._fcmd2b('<BBBBBB', 0x57, x, y, min(w, 255), 1) |
|||
if x + w < self.w: |
|||
self._fcmd2b('<BBBBBB', 0x57, x + w, y, 1, min(h, 255)) |
|||
if y + h < self.h: |
|||
self._fcmd2b('<BBBBBB', 0x57, x, y + h, min(w, 255), 1) |
|||
else: |
|||
self._fcmd2b('<BBBBBB', cmd, x, y, min(w, 255), min(h, 255)) |
|||
|
|||
def rect_outline(self, x, y, w, h): |
|||
self.rect(x, y, w, h, 0x57) |
|||
|
|||
def rect_interior(self, x, y, w, h): |
|||
self.rect(x, y, w, h, 0x51) |
|||
|
|||
def line(self, x1, y1, x2, y2): |
|||
ar4 = self.array4 |
|||
ar4[0] = x1 |
|||
ar4[1] = y1 |
|||
ar4[2] = x2 |
|||
ar4[3] = y2 |
|||
if self.clip_line(ar4, self.w, self.h): |
|||
self._fcmd2b('<BBBBBB', 0x4c, ar4[0], ar4[1], ar4[2], ar4[3]) |
|||
|
|||
def dot_no_clip(self, x, y): |
|||
self._fcmd2('<BBBB', 0x4b, x, y) |
|||
|
|||
def rect_no_clip(self, x, y, w, h): |
|||
self._fcmd2b('<BBBBBB', 0x72, x, y, w, h) |
|||
|
|||
def rect_outline_no_clip(self, x, y, w, h): |
|||
self._fcmd2b('<BBBBBB', 0x57, x, y, w, h) |
|||
|
|||
def rect_interior_no_clip(self, x, y, w, h): |
|||
self._fcmd2b('<BBBBBB', 0x51, x, y, w, h) |
|||
|
|||
def line_no_clip(self, x1, y1, x2, y2): |
|||
self._fcmd2b('<BBBBBB', 0x4c, x1, y1, x2, y2) |
|||
|
|||
def poly_dot(self, data): |
|||
if len(data) & 1: |
|||
raise ValueError('must specify even number of bytes') |
|||
self._fcmd2('<BBB', 0x71, len(data) // 2) |
|||
self._send(data) |
|||
|
|||
def poly_line(self, data): |
|||
if len(data) & 1: |
|||
raise ValueError('must specify even number of bytes') |
|||
self._fcmd2('<BBB', 0x78, len(data) // 2) |
|||
self._send(data) |
|||
|
|||
#### TOUCH COMMANDS #### |
|||
|
|||
def touch_config(self, calib=False, save=False, irq=None): |
|||
self._fcmd2('<BBBB', 0x7a, (irq is not None) << 2 | save << 1 | calib, bool(irq) << 7) |
|||
|
|||
def is_touched(self): |
|||
self._send(b'\x02T') |
|||
b = self.buf[4] |
|||
self._waitfor(3, b) |
|||
return b[1] >> 7 != 0 |
|||
|
|||
def get_touch(self): |
|||
self._send(b'\x02T') # implicit LCD output flush |
|||
b = self.buf[4] |
|||
self._waitfor(3, b) |
|||
return b[1] >> 7, b[2], b[3] |
|||
|
|||
#### ADVANCED COMMANDS #### |
|||
|
|||
def set_spi_win(self, x, y, w, h): |
|||
pack_into('<BBBHHHHHHHH', self.buf19, 0, 2, 0x55, 10, x, y, x + w - 1, y + h - 1, 0, 0, 0, 0xffff) |
|||
self._send(self.buf19) |
|||
|
|||
def fast_spi(self, flush=True): |
|||
if flush: |
|||
self.oflush() |
|||
self._send(b'\x02\x12') |
|||
return self.spi |
|||
|
|||
def show_framebuf(self, buf): |
|||
self.fast_spi().write(buf) |
|||
|
|||
def set_scroll(self, on): |
|||
self._fcmd2('<BBB', 0x15, on) |
|||
|
|||
def set_scroll_win(self, win, x=-1, y=0, w=0, h=0, vec=0, pat=0, fill=0x07e0, color=0): |
|||
pack_into('<BBBHHHHHHHH', self.buf19, 0, 2, 0x55, win, x, y, w, h, vec, pat, fill, color) |
|||
self._send(self.buf19) |
|||
|
|||
def set_scroll_win_param(self, win, param, value): |
|||
self._fcmd2b('<BBBBH', 0x75, win, param, value) |
|||
|
|||
def set_scroll_buf(self, s): |
|||
l = len(s) |
|||
if l > 32: |
|||
raise ValueError('length must be 32 or less') |
|||
self._fcmd2('<BBB', 0x11, l) |
|||
self._send(s) |
|||
|
|||
def jpeg_start(self, l): |
|||
self.oflush() |
|||
self._fcmd2('<BBH', 0x6a, l) |
|||
|
|||
def jpeg_data(self, buf): |
|||
self._send(buf) |
|||
|
|||
def jpeg(self, buf): |
|||
self.jpeg_start(len(buf)) |
|||
self.jpeg_data(buf) |
|||
|
|||
def feed_wdt(self): |
|||
self._send(b'\x02\x17') |
|||
|
|||
def reset(self): |
|||
self._send(b'\x02Y\xef\xbe\xad\xde') |
|||
sleep_ms(15) |
@ -0,0 +1,161 @@ |
|||
# Driver test for official MicroPython LCD160CR display |
|||
# MIT license; Copyright (c) 2017 Damien P. George |
|||
|
|||
import time, math, framebuf, lcd160cr |
|||
|
|||
def get_lcd(lcd): |
|||
if type(lcd) is str: |
|||
lcd = lcd160cr.LCD160CR(lcd) |
|||
return lcd |
|||
|
|||
def show_adc(lcd, adc): |
|||
data = [adc.read_core_temp(), adc.read_core_vbat(), 3.3] |
|||
try: |
|||
data[2] = adc.read_vref() |
|||
except: |
|||
pass |
|||
for i in range(3): |
|||
lcd.set_text_color((825, 1625, 1600)[i], 0) |
|||
lcd.set_font(2) |
|||
lcd.set_pos(0, 100 + i * 16) |
|||
lcd.write('%4s: ' % ('TEMP', 'VBAT', 'VREF')[i]) |
|||
if i > 0: |
|||
s = '%6.3fV' % data[i] |
|||
else: |
|||
s = '%5.1f°C' % data[i] |
|||
lcd.set_font(1, bold=0, scale=1) |
|||
lcd.write(s) |
|||
|
|||
def test_features(lcd): |
|||
# if we run on pyboard then use ADC and RTC features |
|||
try: |
|||
import pyb |
|||
adc = pyb.ADCAll(12, 0xf0000) |
|||
rtc = pyb.RTC() |
|||
except: |
|||
adc = None |
|||
rtc = None |
|||
|
|||
# set orientation and clear screen |
|||
lcd = get_lcd(lcd) |
|||
lcd.set_orient(lcd160cr.PORTRAIT) |
|||
lcd.set_pen(0, 0) |
|||
lcd.erase() |
|||
|
|||
# create M-logo |
|||
mlogo = framebuf.FrameBuffer(bytearray(17 * 17 * 2), 17, 17, framebuf.RGB565) |
|||
mlogo.fill(0) |
|||
mlogo.fill_rect(1, 1, 15, 15, 0xffffff) |
|||
mlogo.vline(4, 4, 12, 0) |
|||
mlogo.vline(8, 1, 12, 0) |
|||
mlogo.vline(12, 4, 12, 0) |
|||
mlogo.vline(14, 13, 2, 0) |
|||
|
|||
# create inline framebuf |
|||
offx = 14 |
|||
offy = 19 |
|||
w = 100 |
|||
h = 75 |
|||
fbuf = framebuf.FrameBuffer(bytearray(w * h * 2), w, h, framebuf.RGB565) |
|||
lcd.set_spi_win(offx, offy, w, h) |
|||
|
|||
# initialise loop parameters |
|||
tx = ty = 0 |
|||
t0 = time.ticks_us() |
|||
|
|||
for i in range(300): |
|||
# update position of cross-hair |
|||
t, tx2, ty2 = lcd.get_touch() |
|||
if t: |
|||
tx2 -= offx |
|||
ty2 -= offy |
|||
if tx2 >= 0 and ty2 >= 0 and tx2 < w and ty2 < h: |
|||
tx, ty = tx2, ty2 |
|||
else: |
|||
tx = (tx + 1) % w |
|||
ty = (ty + 1) % h |
|||
|
|||
# create and show the inline framebuf |
|||
fbuf.fill(lcd.rgb(128 + int(64 * math.cos(0.1 * i)), 128, 192)) |
|||
fbuf.line(w // 2, h // 2, |
|||
w // 2 + int(40 * math.cos(0.2 * i)), |
|||
h // 2 + int(40 * math.sin(0.2 * i)), |
|||
lcd.rgb(128, 255, 64)) |
|||
fbuf.hline(0, ty, w, lcd.rgb(64, 64, 64)) |
|||
fbuf.vline(tx, 0, h, lcd.rgb(64, 64, 64)) |
|||
fbuf.rect(tx - 3, ty - 3, 7, 7, lcd.rgb(64, 64, 64)) |
|||
for phase in (-0.2, 0, 0.2): |
|||
x = w // 2 - 8 + int(50 * math.cos(0.05 * i + phase)) |
|||
y = h // 2 - 8 + int(32 * math.sin(0.05 * i + phase)) |
|||
fbuf.blit(mlogo, x, y) |
|||
for j in range(-3, 3): |
|||
fbuf.text('MicroPython', |
|||
5, h // 2 + 9 * j + int(20 * math.sin(0.1 * (i + j))), |
|||
lcd.rgb(128 + 10 * j, 0, 128 - 10 * j)) |
|||
lcd.show_framebuf(fbuf) |
|||
|
|||
# show results from the ADC |
|||
if adc: |
|||
show_adc(lcd, adc) |
|||
|
|||
# show the time |
|||
if rtc: |
|||
lcd.set_pos(2, 0) |
|||
lcd.set_font(1) |
|||
t = rtc.datetime() |
|||
lcd.write('%4d-%02d-%02d %2d:%02d:%02d.%01d' % (t[0], t[1], t[2], t[4], t[5], t[6], t[7] // 100000)) |
|||
|
|||
# compute the frame rate |
|||
t1 = time.ticks_us() |
|||
dt = time.ticks_diff(t1, t0) |
|||
t0 = t1 |
|||
|
|||
# show the frame rate |
|||
lcd.set_pos(2, 9) |
|||
lcd.write('%.2f fps' % (1000000 / dt)) |
|||
|
|||
def test_mandel(lcd): |
|||
# set orientation and clear screen |
|||
lcd = get_lcd(lcd) |
|||
lcd.set_orient(lcd160cr.PORTRAIT) |
|||
lcd.set_pen(0, 0xffff) |
|||
lcd.erase() |
|||
|
|||
# function to compute Mandelbrot pixels |
|||
def in_set(c): |
|||
z = 0 |
|||
for i in range(32): |
|||
z = z * z + c |
|||
if abs(z) > 100: |
|||
return i |
|||
return 0 |
|||
|
|||
# cache width and height of LCD |
|||
w = lcd.w |
|||
h = lcd.h |
|||
|
|||
# create the buffer for each line and set SPI parameters |
|||
line = bytearray(w * 2) |
|||
lcd.set_spi_win(0, 0, w, h) |
|||
spi = lcd.fast_spi() |
|||
|
|||
# draw the Mandelbrot set line-by-line |
|||
for v in range(h): |
|||
for u in range(w): |
|||
c = in_set((v / ((h - 1) / 3.2) - 2.3) + (u / ((w - 1) / 2.4) - 1.2) * 1j) |
|||
if c < 16: |
|||
rgb = c << 12 | c << 6 |
|||
else: |
|||
rgb = 0xf800 | c << 6 |
|||
line[2 * u] = rgb |
|||
line[2 * u + 1] = rgb >> 8 |
|||
spi.write(line) |
|||
|
|||
def test_all(lcd): |
|||
lcd = get_lcd(lcd) |
|||
test_features(lcd) |
|||
test_mandel(lcd) |
|||
|
|||
print('To run all tests: test_all(<lcd>)') |
|||
print('Individual tests are: test_features, test_mandel') |
|||
print('<lcd> argument should be a connection, eg "X", or an LCD160CR object') |
Loading…
Reference in new issue