## 100Msps ADC
import machine
machine.freq(200_000_000 )
print( "done" )
### 1. DMA
import time
import uctypes
class DMA:
DMA_BASE = 0x50000000
DMA_EN = 0x01 << 0
HIGH_PRIO = 0x01 << 1
INCR_READ = 0x01 << 4
INCR_WRITE= 0x01 << 5
DREQ_PIO0_RX0 = 0x04 << 15
DREQ_SPI1_TX = 0x12 << 15
DREQ_PERMANENT= 0x3F << 15
IRQ_QUIET = 0x01 << 21
BUSY = 0x01 << 24
def __init__( self, channelNumber ):
offset = channelNumber * 0x40
self.CHx_READ_ADDR = DMA.DMA_BASE + 0x00 + offset
self.CHx_WRITE_ADDR = DMA.DMA_BASE + 0x04 + offset
self.CHx_TRANS_COUNT = DMA.DMA_BASE + 0x08 + offset
self.CHx_CTRL_TRIG = DMA.DMA_BASE + 0x0C + offset
def config( self, src_addr, dst_addr, count, src_inc, dst_inc, trig_dreq ):
machine.mem32[ self.CHx_CTRL_TRIG ] = 0
machine.mem32[ self.CHx_READ_ADDR ] = src_addr
machine.mem32[ self.CHx_WRITE_ADDR ] = dst_addr
machine.mem32[ self.CHx_TRANS_COUNT ] = count
trig_val = 0
if( src_inc ):
trig_val |= DMA.INCR_READ
if( dst_inc ):
trig_val |= DMA.INCR_WRITE
trig_val |= trig_dreq
machine.mem32[ self.CHx_CTRL_TRIG ] = trig_val
def enable( self ):
machine.mem32[ self.CHx_CTRL_TRIG ] |= DMA.DMA_EN
def disable( self ):
machine.mem32[ self.CHx_CTRL_TRIG ] = 0
def is_busy( self ):
if( machine.mem32[ self.CHx_CTRL_TRIG ] & DMA.BUSY ):
return True
else:
return False
def test_dma():
dma = DMA(0)
src_buf = b"Hello World!"*1000
dst_buf = bytearray( 12*1000 )
dma.config(
src_addr = uctypes.addressof( src_buf ),
dst_addr = uctypes.addressof( dst_buf ),
count = len( src_buf ),
src_inc = True,
dst_inc = True,
trig_dreq = DMA.DREQ_PERMANENT
)
t0 = time.ticks_us()
dma.enable()
while( dma.is_busy() ):
pass
dma.disable()
t1 = time.ticks_us()
print( "dst", dst_buf[0:12], "..." )
print( "Transfer speed [B/s]:", len( src_buf )/((t1-t0)*1e-6) )
print( "@CPU freq:", machine.freq() )
test_dma()
print( "done" )
### 2. ST7789
import time
import machine
import uctypes
class St7789:
HRES = 320
VRES = 240
CASET = 0x2A
RASET = 0x2B
RAMWR = 0x2C
def __init__( self, baudrate, cs, sck, mosi, miso, dc ):
self.buf1 = bytearray( 1 )
self.buf2 = bytearray( 2 )
self.buf4 = bytearray( 4 )
self.baudrate = baudrate
self.cs = cs
self.sck = sck
self.mosi= mosi
self.miso= miso
self.dc = dc
self.cs.value( 1 )
self.dma = DMA( 0 )
self.spi_init()
self.config()
def spi_init( self ):
self.spi = machine.SPI(
1,
baudrate=self.baudrate,
polarity=0,
phase=0,
sck=self.sck,
mosi=self.mosi,
miso=self.miso
)
def write_register( self, reg, buf ): # reg for command, buf for data
self.buf1[0] = reg
self.cs.value( 0 )
self.dc.value( 0 )
self.spi.write( self.buf1 )
self.dc.value( 1 )
self.spi.write( buf )
self.cs.value( 1 )
# Note: if is_blocking is False, user should call to wait_dma explicitly
def write_register_dma( self, reg, buf, is_blocking=True ):
SPI1_BASE = 0x40040000
SSPDR = 0x008. #address of 16bit SPI1 TX FIFO
self.dma.config(
src_addr = uctypes.addressof( buf ),
dst_addr = SPI1_BASE + SSPDR,
count = len( buf ),
src_inc = True,
dst_inc = False,
trig_dreq= DMA.DREQ_SPI1_TX
)
self.buf1[0] = reg
self.cs.value( 0 )
self.dc.value( 0 )
self.spi.write( self.buf1 )
self.dc.value( 1 )
self.dma.enable()
if( is_blocking ):
self.wait_dma()
def wait_dma( self ):
while( self.dma.is_busy() ):
pass
self.dma.disable()
# Note: wait to send last byte. It should take < 1uS @ 10MHz
time.sleep_us( 1 )
self.cs.value( 1 )
def config( self ):
self.write_register( 0x11, b"" )
time.sleep_ms( 100 )
self.write_register( 0x36, b"\x60" )
self.write_register( 0x3A, b"\x55" )
self.write_register( 0xB2, b"\x0C\x0C\x00\x33\x33" )
self.write_register( 0xB7, b"\x35" )
self.write_register( 0xBB, b"\x28" )
self.write_register( 0xC0, b"\x3C" )
self.write_register( 0xC2, b"\x01" )
self.write_register( 0xC3, b"\x0B" )
self.write_register( 0xC4, b"\x20" )
self.write_register( 0xC6, b"\x0F" )
self.write_register( 0xD0, b"\xA4\xA1" )
self.write_register( 0xE0, b"\xD0\x01\x08\x0F\x11\x2A\x36\x55\x44\x3A\x0B\x06\x11\x20" )
self.write_register( 0xE1, b"\xD0\x02\x07\x0A\x0B\x18\x34\x43\x4A\x2B\x1B\x1C\x22\x1F" )
self.write_register( 0x55, b"\xB0" )
self.write_register( 0x29, b"" )
time.sleep_ms( 100 )
def set_window( self, x, y, w, h ):
x0 = x
y0 = y
x1 = x0 + w - 1
y1 = y0 + h - 1
self.buf4[0] = x0 >> 8
self.buf4[1] = x0 & 0xff
self.buf4[2] = x1 >> 8
self.buf4[3] = x1 & 0xff
self.write_register( St7789.CASET, self.buf4 )
self.buf4[0] = y0 >> 8
self.buf4[1] = y0 & 0xff
self.buf4[2] = y1 >> 8
self.buf4[3] = y1 & 0xff
self.write_register( St7789.RASET, self.buf4 )
def draw_bitmap_dma( self, x, y, w, h, buf, is_blocking=True ):
self.set_window( x, y, w, h )
self.write_register_dma( St7789.RAMWR, buf, is_blocking )
def clear( self, color ):
self.buf2[0] = color >> 8
self.buf2[1] = color & 0xff
self.set_window( 0, 0, St7789.HRES, St7789.VRES )
self.write_register( St7789.RAMWR, b"" )
self.cs.value( 0 )
self.dc.value( 1 )
for i in range( St7789.HRES ):
for j in range( St7789.VRES ):
self.spi.write( self.buf2 )
self.cs.value( 1 )
def build_square_buf( w, h ):
top = b"\xFF\xFF"*w
body=(b"\xFF\xFF" + b"\x00\x00"*(w-2) + b"\xFF\xFF")*(h-2)
bot = b"\xFF\xFF"*w
return top + body + bot
def test_lcd():
baudrate = 24_000_000
cs = machine.Pin( 13, machine.Pin.OUT )
sck = machine.Pin( 10, machine.Pin.OUT )
mosi= machine.Pin( 11, machine.Pin.OUT )
miso= machine.Pin( 12, machine.Pin.IN )
dc = machine.Pin( 14, machine.Pin.OUT )
bl = machine.Pin( 15, machine.Pin.OUT )
bl.value( 1 )
lcd = St7789( baudrate, cs, sck, mosi, miso, dc )
lcd.clear( 0x001F )
# 1/4 screen pixels square with white border red backgorund
w, h = 320//4, 240//4
bmp = build_square_buf( w, h )
t0 = time.ticks_us()
lcd.draw_bitmap_dma( 100, 100, w, h, bmp )
t1 = time.ticks_us()
print( "Maximum FPS @24MHz:", 24e6/( 320*240*16 ) ) # FPS = F/(W*H*BPP)
print( "Achieved FPS:", 1/(16*(t1-t0)*1e-6) ) # Note: Test only draws 1/16 of the sreen area
print( "Draw TSC calibration pattern")
w, h = 10, 10
bmp = build_square_buf( w, h )
lcd.draw_bitmap_dma( 50, 50, w, h, bmp )
lcd.draw_bitmap_dma( 250, 50, w, h, bmp )
lcd.draw_bitmap_dma( 250, 200, w, h, bmp )
lcd.draw_bitmap_dma( 50, 200, w, h, bmp )
test_lcd()
print( "done" )
### 3. XPT2046 - Touch Screen LCD
import time
import machine
class Xpt2046:
CHANNEL_X = 0x90
CHANNEL_Y = 0xD0
def __init__( self, baudrate, cs, sck, mosi, miso, ax=1, bx=0, ay=1, by=0 ):
self.buf_tx = bytearray( 3 )
self.buf_rx = bytearray( 3 )
self.sck = sck
self.mosi= mosi
self.miso= miso
self.cs = cs
self.cs.value( 1 )
self.ax = ax
self.bx = bx
self.ay = ay
self.by = by
self.baudrate = baudrate
self.spi_init()
def spi_init( self ):
self.spi = machine.SPI(
1,
baudrate=self.baudrate,
polarity=0,
phase=0,
sck=self.sck,
mosi=self.mosi,
miso=self.miso
)
def _read( self ):
self.cs.value( 0 )
self.buf_tx[0] = Xpt2046.CHANNEL_X
self.buf_tx[1] = 0x00
self.buf_tx[2] = 0x00
self.spi.write_readinto( self.buf_tx, self.buf_rx )
x = (self.buf_rx[1]<<4) | (self.buf_rx[2]>>4)
self.buf_tx[0] = Xpt2046.CHANNEL_Y
self.buf_tx[1] = 0x00
self.buf_tx[2] = 0x00
self.spi.write_readinto( self.buf_tx, self.buf_rx )
y = (self.buf_rx[1]<<4) | (self.buf_rx[2]>>4)
self.cs.value( 1 )
if( x == 2047 ):
x = 0
return x, y
def read( self ):
xacc = 0
yacc = 0
for i in range( 4 ):
x, y = self._read()
if( x and y ):
xacc += x
yacc += y
else:
return 0, 0
x = xacc/4
y = yacc/4
x = self.ax*x + self.bx
y = self.ay*y + self.by
return int( 320-x ), int( y )
def test_tsc():
baudrate= 1_000_000
cs = machine.Pin( 16, machine.Pin.OUT )
sck = machine.Pin( 10, machine.Pin.OUT )
mosi= machine.Pin( 11, machine.Pin.OUT )
miso= machine.Pin( 12, machine.Pin.OUT )
# Calibration values
AX = 0.176831
BX =-45.643
AY = 0.13084
BY =-16.191
tsc = Xpt2046( baudrate, cs, sck, mosi, miso, ax=AX, bx=BX, ay=AY, by=BY )
for i in range( 10 ):
x, y = tsc.read()
if( x and y ):
print( x, y )
time.sleep( 1 )
test_tsc()
print("done")
### 4. Draw
import time
import machine
import lvgl as lv
import sys
# This leds shows when lcd is busy
dma_led = machine.Pin( 25, machine.Pin.OUT )
print( "lv.init()" )
lv.init()
print( "disp_buf_t.init()" )
HRES, VRES = 320, 240
fb1 = bytearray( HRES*64 )
fb2 = bytearray( HRES*64 )
disp_draw_buf = lv.disp_draw_buf_t()
disp_draw_buf.init( fb1, fb2, len( fb1 )//lv.color_t.SIZE )
is_fb1 = True
dma_running = False
def disp_drv_flush_cb( disp_drv, area, color ):
global is_fb1, dma_running
#print( "disp_drv_flush_cb", area.x1, area.x2, area.y1, area.y2 )
if( is_fb1 ):
fb = memoryview( fb1 )
else:
fb = memoryview( fb2 )
is_fb1 = not is_fb1
if( dma_running == True ):
lcd.wait_dma()
dma_running = False
dma_led.off()
x = area.x1
y = area.y1
w = area.x2 - area.x1 + 1
h = area.y2 - area.y1 + 1
lcd.draw_bitmap_dma( x, y, w, h, fb[0:2*w*h], is_blocking=False )
dma_running = True
dma_led.on()
disp_drv.flush_ready()
print( "disp_drv_t.init()" )
disp_drv = lv.disp_drv_t()
disp_drv.init()
disp_drv.draw_buf = disp_draw_buf
disp_drv.flush_cb = disp_drv_flush_cb
disp_drv.hor_res = HRES
disp_drv.ver_res = VRES
disp_drv.register()
xx, yy, ss = 0, 0, 0
def indev_drv_read_cb( indev_drv, data ):
global xx, yy, ss, dma_running
#print( "indev_drv_read_cb" )
if( dma_running == True ):
lcd.wait_dma()
dma_running = False
dma_led.off()
tsc.spi_init()
x, y = tsc.read()
lcd.spi_init() # Reinit SPI with LCD settings
if( x or y ):
xx = x
yy = y
ss = 1
else:
ss = 0
data.state = ss
data.point.x = xx
data.point.y = yy
return False
print( "indev_drv_t.init()" )
indev_drv = lv.indev_drv_t()
indev_drv.init()
indev_drv.type = lv.INDEV_TYPE.POINTER
indev_drv.read_cb = indev_drv_read_cb
indev_drv.register()
#def cb_lv_log( msg ):
# print( msg, end="" )
#lv.log_register_print_cb( cb_lv_log )
print( "lv_run" )
def lv_run( timeout_ms=1000, period_ms=10 ):
t0 = time.ticks_ms()
while( time.ticks_diff( time.ticks_ms(), t0 ) < timeout_ms ):
tt0 = time.ticks_ms()
lv.task_handler()
tt1 = time.ticks_ms()
dt = tt1-tt0
if( period_ms > dt ):
time.sleep_ms( period_ms - dt )
lv.tick_inc( period_ms )
else:
lv.tick_inc( dt )
print("done")
* lv.init()
* disp_buf_t.init()
* disp_drv_t.init()
* indev_drv_t.init()
* lv_run
* done
### 5. Setup Demo
lcd_baudrate = 24_000_000
tsc_baudrate = 1_000_000
lcd_cs = machine.Pin( 13, machine.Pin.OUT )
tsc_cs = machine.Pin( 16, machine.Pin.OUT )
sck = machine.Pin( 10, machine.Pin.OUT )
mosi= machine.Pin( 11, machine.Pin.OUT )
miso= machine.Pin( 12, machine.Pin.IN )
dc = machine.Pin( 14, machine.Pin.OUT )
bl = machine.Pin( 15, machine.Pin.OUT )
bl.value( 1 )
# Calibration values
AX, BX = 0.176831, -45.643
AY, BY = 0.130840, -16.191
tsc = Xpt2046( tsc_baudrate, tsc_cs, sck, mosi, miso, ax=AX, bx=BX, ay=AY, by=BY )
# Init lcd last one to start lvgl with SPI LCD baudrate
lcd = St7789( lcd_baudrate, lcd_cs, sck, mosi, miso, dc )
lcd.clear( 0x0000 )
print( "done" )
### 6. build & run demo
def cb_btn( event ):
print( "Hello World!" )
scr = lv.obj()
btn = lv.btn( scr )
lbl = lv.label( btn )
lbl.set_text( "Press me!" )
btn.center()
btn.add_event_cb( cb_btn, lv.EVENT.CLICKED, None )
lv.scr_load( scr )
lv_run( 10_000 )
print( "done" )