This little gem, which cost around six dollars, US, features a gyroscope, accelerometer, on board clock, temperature sensor (a feature of the RP2040) and the built in circular display at 1.28 inches. With a resolution of 240 x 240, there’s quite a bit you can do with the board. Due to its size and shape, and with a creative 3d print, you could make a nice little smart watch, though it does not have WiFi or Bluetooth built in. However, it’s capabilities can more than make up for this lack of connectivity. One thing to keep in mind is that most of the I/O pins are exposed, so you could add both via an 8266 module that is small enough fit on the back of the device. I have not yet pursued that, however, I have been experimenting with the board and will share some of what I have learned.
As this is a Waveshare product, they have a wiki page for it:
Wiki: www.waveshare.com/wiki/RP2040-LCD-1.28
PROGRAMMING
The device can be programmed via MicroPython or C++. I am going to focus on the MicroPython side of things.
The first you will need to do is copy the firmware to the device to prepare it for use with MicroPython.
Here’s a link to the image:
Download the image and unzip it. Look for the file RP2040-LCD-1.28-image.uf2 in the directory where you unzipped the image.
Hold down the reset button on the device and plug it into your computer. If running Windows, a directory will open that is the device page. Drag the file into the device page.
You should now be able to use MicroPython with the device.
I used Thonny, a free MicroPython IDE that works nearly seamlessly with many different devices, including RP2040 based boards. I will post links at the end of this post to take you to a few good pages on how to setup your RP2040 device with Thonny.
CODE
Have a look at the following code:
from machine import Pin,I2C,SPI,PWM,ADC
from LCD1inch28 import LCD_1inch28,QMI8658
import machine
import utime
import time
Vbat_Pin = 29
sensor_temp = machine.ADC(4)
conversion_factor = 3.3 / (65535)
if __name__==’__main__’:
LCD = LCD_1inch28()
LCD.set_bl_pwm(65535)
qmi8658 = QMI8658()
Vbat = ADC(Pin(Vbat_Pin))
rtc = machine.RTC()
ax=0
ay=0
az=0
x=0
y=0
startx=50
starty=100
dotColor = LCD.black
LCD.pixel(startx,starty, dotColor)
def drawBox(sx,sy,ex,ey, colors):
LCD.fill_rect(sx,sy, ex, ey, LCD.black)
LCD.fill_rect(sx-2,sy-2, ex-2, ey-2, colors)
LCD.rect(sx-2,sy-2, ex-2, ey-2, LCD.black)
def getAcc(): #Read accelerometer and return either a positive or negative 1 for the x,y readings. Return Z for actual z axis
abc = qmi8658.Read_XYZ()
ax=abc[1]
if ax<0:
ax=-1
if ax>0:
ax=1
ay=abc[2]
if ay<0:
ay=-1
if ay>0:
ay=1
az=abc[3]
print(ax,ay,az)
return ax,ay,az
def dPrint(text,x,y):
LCD.text(text,x+1,y+1,LCD.black)
LCD.text(text,x,y,LCD.white)
LCD.fill(LCD.steel)
dPrint(“Half-Byte Clock”,60,25)
dPrint(“RP2040 LCD”,80,57)
LCD.show()
while (True):
# Get the date and time
timestamp = rtc.datetime()
# Split out date and time so they can be displayed separately
datestring = “%04d/%02d/%02d “%(timestamp[0:3])
timestring = “%02d:%02d:%02d “%(timestamp[4:7])
# Draw the box to display the date and time (box has drop shadow)
drawBox(60,106,137,29,LCD.darkblue)
# Show the date and time in the box we just drew
dPrint(“Date:” + datestring, 64, 110)
dPrint(“Time:” + timestring, 64, 120)
# Get the battery voltage and display it
sx=78
sy=213
ex=83
ey=18
drawBox(sx,sy,ex,ey,LCD.red)
reading = Vbat.read_u16()*3.3/65535*2
LCD.text(“Vbat={:.2f}”.format(reading),80,215,LCD.black)
# Get the temperature, then display it
reading = sensor_temp.read_u16() * conversion_factor
temperature = (27 – (reading – 0.706)/0.001721)
temperature = (temperature * 1.8) + 8
theTemp = str(round(temperature,0))
drawBox(70,87,115,19,LCD.red)
dPrint(“Temp: ” + theTemp , 72,89)
LCD.show()
This code more or less matches what you see in the first picture posted above. It shows you how to:
- Draw boxes, text and achieve 3d like effects
- Read the temperature sensor
- Read the battery status
- Get and display the time
- Setup the LCD
- Setup the board
- Read the accelerometer
Lets look at this, section by section:
Top:
from machine import Pin,I2C,SPI,PWM,ADC
from LCD1inch28 import LCD_1inch28,QMI8658import machine
import utime
import timeVbat_Pin = 29
sensor_temp = machine.ADC(4)
conversion_factor = 3.3 / (65535)First, in order to use most of the board’s features, you have to setup MicroPython so it can talk to the hardware. To do that, we need to use ‘machine’, or, rather, specific parts of ‘machine’ like Pin, I2C, SPI and so forth.
To use the LCD, we need to import LCD_1inch28 and QMI8658. These are part of the demo code found here: Demo code
Download that file, unzip it and go into the Python folder. There, you should find the Demo code. Open that in Thonny and run it. Provided you have your device connected, it will run the code on the device. From that point on, you can use those libraries in other scripts.
Note that the battery pin is 29 (VBAT in the section above.)
The temperature sensor is accessed via ADC pin 4.
Next, refer to:
if __name__==’__main__’:
LCD = LCD_1inch28()
LCD.set_bl_pwm(65535)
qmi8658 = QMI8658()
Vbat = ADC(Pin(Vbat_Pin))
rtc = machine.RTC()
ax=0
ay=0
az=0
x=0
y=0
startx=50
starty=100
dotColor = LCD.black
LCD.pixel(startx,starty, dotColor)
def drawBox(sx,sy,ex,ey, colors):
LCD.fill_rect(sx,sy, ex, ey, LCD.black)
LCD.fill_rect(sx-2,sy-2, ex-2, ey-2, colors)
LCD.rect(sx-2,sy-2, ex-2, ey-2, LCD.black)
def getAcc(): #Read accelerometer and return either a positive or negative 1 for the x,y readings. Return Z for actual z axis
abc = qmi8658.Read_XYZ()
ax=abc[1]
if ax<0:
ax=-1
if ax>0:
ax=1
ay=abc[2]
if ay<0:
ay=-1
if ay>0:
ay=1
az=abc[3]
print(ax,ay,az)
return ax,ay,az
def dPrint(text,x,y):
LCD.text(text,x+1,y+1,LCD.black)
LCD.text(text,x,y,LCD.white)
LCD.fill(LCD.steel)
dPrint(“Half-Byte Clock”,60,25)
dPrint(“RP2040 LCD”,80,57)
LCD.show()The first five, bolded lines above set up the LCD, and prepare the real time clock and grab the battery voltage.
Next, a handful of variables are initialized.
The lines
startx=50
starty=100
dotColor = LCD.black
LCD.pixel(startx,starty, dotColor)
Tell the LCD interface where to start and what the color will be.
DrawBox is a function that, when given start and end coordinates and color, will draw two boxes: one black, which is the shadow and one that is filled with the supplied color. The offset for the shadow is –2 pixels, so be sure to not allow the shadow box to draw offscreen. There is not error checking as of yet (I was lazy.)
getACC gets accelerometer values.
dPrint does for text what drawbox does for boxes: It prints text with a shadow.
Finally, the last four lines of this snippet will clear the screen, print two lines of text and then refresh the screen. In order for anything to show on the screen, you must first send the info to the screen and then you have to the LCD.Show() to force the refresh.
The rest of the clock demo is as follows:
while (True):
# Get the date and time
timestamp = rtc.datetime()
# Split out date and time so they can be displayed separately
datestring = “%04d/%02d/%02d “%(timestamp[0:3])
timestring = “%02d:%02d:%02d “%(timestamp[4:7])
# Draw the box to display the date and time (box has drop shadow)
drawBox(60,106,137,29,LCD.darkblue)
# Show the date and time in the box we just drew
dPrint(“Date:” + datestring, 64, 110)
dPrint(“Time:” + timestring, 64, 120)
# Get the battery voltage and display it
sx=78
sy=213
ex=83
ey=18
drawBox(sx,sy,ex,ey,LCD.red)
reading = Vbat.read_u16()*3.3/65535*2
LCD.text(“Vbat={:.2f}”.format(reading),80,215,LCD.black)
# Get the temperature, then display it
reading = sensor_temp.read_u16() * conversion_factor
temperature = (27 – (reading – 0.706)/0.001721)
temperature = (temperature * 1.8) + 8
theTemp = str(round(temperature,0))
drawBox(70,87,115,19,LCD.red)
dPrint(“Temp: ” + theTemp , 72,89)
LCD.show()
The While sets up the loop to run indefinitely (it will always evaluate to true) and, thus, update the info on the screen.
# Get the date and time
timestamp = rtc.datetime()
# Split out date and time so they can be displayed separately
datestring = “%04d/%02d/%02d “%(timestamp[0:3])
timestring = “%02d:%02d:%02d “%(timestamp[4:7])
# Draw the box to display the date and time (box has drop shadow)
drawBox(60,106,137,29,LCD.darkblue)
# Show the date and time in the box we just drew
dPrint(“Date:” + datestring, 64, 110)
dPrint(“Time:” + timestring, 64, 120)
This code grabs the current system date and time. It splits them into date and time variables. It uses standard formatting characters to format the time and the date. We draw our three d box and make it dark blue. Next, we shadow print the date and time on different lines inside the box.
Reading the battery voltage is fairly straight forward as well:
# Get the battery voltage and display it
sx=78
sy=213
ex=83
ey=18
drawBox(sx,sy,ex,ey,LCD.red)
reading = Vbat.read_u16()*3.3/65535*2
LCD.text(“Vbat={:.2f}”.format(reading),80,215,LCD.black)
First, we set the location variables, then draw the box with a red background. We read the battery voltage using the conversion factor (reading * 3.3/65535 * 2) and, finally, display it rounded to two decimal places.
Next, we get and display the temperature:
# Get the temperature, then display it
reading = sensor_temp.read_u16() * conversion_factor
temperature = (27 – (reading – 0.706)/0.001721)
temperature = (temperature * 1.8) + 8
theTemp = str(round(temperature,0))
drawBox(70,87,115,19,LCD.red)
dPrint(“Temp: ” + theTemp , 72,89)
Reading the temperature value also involves the conversion factor we used in the battery reading. We then convert from celsius (because…) and then round the value for display.
The very last line updates the screen and we then repeat.
There’s a lot of value in this little device. I am thinking of even writing a tiny game using the accelerometer, something like moving the marble through the maze and dropping it into the hole at the end of the maze.
Below are some tricks and tables containing useful bits like color values, and how to get at the hardware.
Reading the accelerometer
and gyroscope
get the values for |
xyz=qmi8658.Read_XYZ() # ax=getAcc()[0] # Call our ay=getAcc()[1] az=getAcc()[2] x=x+ax y=y+ay if y=starty if y=starty
if x=startx if x=startx
print (startx+x,y) LCD.pixel(x+startx,y+starty,LCD.white) # Plot our point |
Initialize the qmi object |
qmi8658=QMI8658() |
Accelerometer X axis |
xyz[0] |
Accelerometer Y axis |
xyz[1] |
Accelerometer Z axis |
xyz[2] |
Gyroscope X |
xyz[3] |
Gyroscope y |
xyz[4] |
Gyroscope z |
xyz[5] |
Color
Table
WHITE |
0xFFFF |
BLACK |
0x0000 |
BLUE |
0x001F |
BRED |
0XF81F |
GRED |
0XFFE0 |
GBLUE |
0X07FF |
RED |
0xF800 |
MAGENTA |
0xF81F |
GREEN |
0x07E0 |
CYAN |
0x7FFF |
YELLOW |
0xFFE0 |
BROWN |
0XBC40 |
BRRED |
0XFC07 |
GRAY |
0X8430 |
STEEL |
0x1805 |
LCYAN |
0x180f |
Circular screen
specific
Clear screen to a color: |
LCD.fill(LCD.white) |
Draw a rectangle and fill with color: |
LCD.fill_rect(0,0,240,40,LCD.red) |
Put text on screen at x,y and color |
LCD.text(“RP2040-LCD-1.28”,60,25,LCD.white) |
Update the screen |
LCD.show() |
Initialize screen object |
LCD = LCD_1inch28() LCD.set_bl_pwm(65535) |
Set pixel |
LCD.pixel(x,y,LCD.black) |
Draw rectangle |
LCD.rect(sx,sy,ex,ey,color) |
Draw line |
LCD.line(sx,sy,ex,ey,color) |
Temperature
read:
# Source:
Electrocredible.com, Language: MicroPython
from machine import ADC
import time adc = machine.ADC(4)
while True:
ADC_voltage = adc.read_u16() *
(3.3 / (65535))
temperature_celcius = 27 –
(ADC_voltage – 0.706)/0.001721
temp_fahrenheit=32+(1.8*temperature_celcius)
print(“Temperature: {}°C
{}°F”.
format(temperature_celcius,temp_fahrenheit))
time.sleep_ms(500)
Pinout:
Links:
RP2040-LCD-1.28 – Waveshare Wiki
Demo
Drawing
Datasheet
Official Raspberry Pi Documents
- Raspberry Pi Pico MicroPython Book
- Raspberry Pi related books
- Pico datasheet
- RPI-PICO-R3-PUBLIC-SCHEMATIC
- Pico R3 A4 Pinout
- Getting started with pico
- Pico c sdk
- Pico python sdk.pdf
- Pico datasheet
- Rp2040 datasheet
- Hardware design with rp2040
Raspberry Pi Demo
Developing Software