Skip to content

Commit

Permalink
updating content
Browse files Browse the repository at this point in the history
  • Loading branch information
dmccreary committed Jan 7, 2025
1 parent 4be366f commit 221e2c2
Show file tree
Hide file tree
Showing 12 changed files with 973 additions and 1 deletion.
Binary file added docs/kits/st77XX/display-picture.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/kits/st77XX/ebay-listing.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
66 changes: 66 additions & 0 deletions docs/kits/st77XX/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Building a Clock with the Color ST7735 and ST7789 Displays

![Ebay Listing](./ebay-listing.png)

[Sample Listing on eBay for $3-4](https://www.ebay.com/itm/405396699577)

This clock is built on a low-cost 1.8 inch color TFT display.
It has a resolution of 160x128 which is enough to draw date, time
and temperature information. It has an SPI interfaces and
runs on 3.3 volts.

## Interface

1. Ground
2. VCC Power input
3. SCL SPI clock input
4. SDA SPI data input
5. RES Reset
6. DC data/command selection foot
7. CS chip selection signal,low level active
8. BLK - Backlight - Must be at 3.3v to see the device. This can also
be used to dim the display.

## Driver

**Supported Resolutions:** 320x240, 240x240, 135x240 and 128x128 pixel displays

[Russ Hughes Binary Driver](https://github.com/russhughes/st7789_mpy)

## Compare

Let's compare these two common display driver ICs used in small color LCD displays.

Key Differences:

Resolution and Display Size:

- ST7735: Typically supports up to 128x160 pixels, commonly used in 1.8" displays
- ST7789: Supports up to 240x320 pixels, commonly used in 1.3" to 2.0" displays

Memory and Color Depth:

- ST7735: Has 132x162 display RAM, supports 16-bit (65K) colors
- ST7789: Has 240x320 display RAM, supports 16-bit (65K) and 18-bit (262K) colors

Power and Performance:

- ST7735: Lower power consumption, suitable for battery-operated devices
- ST7789: Higher refresh rates possible, better performance for animations

Common Features:

- Both use 4-wire SPI interface for communication
- Both support hardware scrolling
- Similar command sets, making code migration relatively straightforward
- Built-in display RAM
- Support sleep modes for power saving

In terms of practical use:

- ST7735 is often chosen for simpler projects where power efficiency is crucial
- ST7789 is preferred when higher resolution or better color reproduction is needed
- Both are well-supported in popular microcontroller libraries
- ST7789 is generally more expensive but offers better display quality

The code initialization and communication protocols are similar, though the ST7789 has some additional commands for its extended features.
4 changes: 3 additions & 1 deletion docs/lessons/13-real-time-clocks.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
# Real Time Clocks

!!! note
Real-time clock support has only recently been added to the core MicroPython libraries.
Minimal real-time clock support has only recently been added to the core MicroPython libraries.
Make sure you are using the latest release of MicroPython to use the features
built into the MicroPython Runtime.

See [The MicroPython RTC Documentation](https://docs.micropython.org/en/latest/library/machine.RTC.html) to make sure you have the right release.

Note that the built-in MicroPython library does not setting alarms, turning on and off the oscillator stop flag or accessing the temperature of the RTC (available only on some RTCs like the DS3231). These functions must be done through a library or by providing your own functions.

## The DS1307 and the DS3231

Our lessons use two different RTC chips. Let's do a comparison of these RTC modules and explain their implementation with the MicroPython.
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
173 changes: 173 additions & 0 deletions src/rtc/display-temp-v2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
from machine import Pin, I2C
import utime
import ssd1306
from utime import sleep, localtime
led = machine.Pin(25, machine.Pin.OUT)

SCL = machine.Pin(2) # SPI CLock
SDA = machine.Pin(3) # SPI Data
spi = machine.SPI(0, sck=SCL, mosi=SDA, baudrate=100000)

RES = machine.Pin(4)
DC = machine.Pin(5)
CS = machine.Pin(6)

oled = ssd1306.SSD1306_SPI(128, 64, spi, DC, RES, CS)
DS3231_ADDR = 0x68

def bcd2dec(bcd):
"""Convert binary coded decimal to decimal."""
return (((bcd & 0xf0) >> 4) * 10 + (bcd & 0x0f))

def read_ds3231():
"""Read time from DS3231 RTC."""
data = i2c.readfrom_mem(DS3231_ADDR, 0x00, 7)
second = bcd2dec(data[0])
minute = bcd2dec(data[1])
hour = bcd2dec(data[2] & 0x3f) # 24 hour mode
day = bcd2dec(data[4])
month = bcd2dec(data[5] & 0x1f)
year = bcd2dec(data[6]) + 2000
return (year, month, day, hour, minute, second)

def force_temp_conversion():
"""Force a new temperature conversion in the DS3231."""
# Read control register (0x0E)
control = i2c.readfrom_mem(DS3231_ADDR, 0x0E, 1)[0]
# Set CONV bit (bit 5)
control |= (1 << 5)
# Write back to control register
i2c.writeto_mem(DS3231_ADDR, 0x0E, bytes([control]))
# Wait for conversion to complete (max 10ms)
sleep(0.01)

def read_temperature():
"""Read temperature from DS3231 RTC with 0.25°C (0.45°F) resolution."""
# Temperature registers are 0x11 (MSB) and 0x12 (LSB)
temp_msb = i2c.readfrom_mem(DS3231_ADDR, 0x11, 1)[0]
temp_lsb = i2c.readfrom_mem(DS3231_ADDR, 0x12, 1)[0] >> 6 # Top 2 bits only

# Handle signed temperature value (2's complement)
if temp_msb & 0x80: # If negative (bit 7 is 1)
temp_msb = -(~temp_msb & 0x7F) - 1

# Convert to temperature value
# MSB is temperature in degrees Celsius
# LSB bits 7 and 6 are decimal points (0.25°C resolution)
temp_c = temp_msb + ((temp_lsb & 0x03) * 0.25)

# Convert to Fahrenheit
temp_f = (temp_c * 9/5) + 32

return temp_c, temp_f

segmentMapping = [
#a, b, c, d, e, f, g
[1, 1, 1, 1, 1, 1, 0], # 0
[0, 1, 1, 0, 0, 0, 0], # 1
[1, 1, 0, 1, 1, 0, 1], # 2
[1, 1, 1, 1, 0, 0, 1], # 3
[0, 1, 1, 0, 0, 1, 1], # 4
[1, 0, 1, 1, 0, 1, 1], # 5
[1, 0, 1, 1, 1, 1, 1], # 6
[1, 1, 1, 0, 0, 0, 0], # 7
[1, 1, 1, 1, 1, 1, 1], # 8
[1, 1, 1, 1, 0, 1, 1] # 9
]

def drawDigit(digit, x, y, width, height, thickness, color):
if digit < 0:
return
segmentOn = segmentMapping[digit]

# Draw horizontal segments
for i in [0, 3, 6]:
if segmentOn[i]:
if i == 0: # top
yOffset = 0
elif i == 3: # bottom
yOffset = height - thickness
else: # middle
yOffset = height // 2 - thickness // 2
oled.fill_rect(x, y+yOffset, width, thickness, color)

# Draw vertical segments
for i in [1, 2, 4, 5]:
if segmentOn[i]:
if i == 1 or i == 5: # upper segments
startY = y
endY = y + height // 2
else: # lower segments
startY = y + height // 2
endY = y + height
xOffset = 0 if (i == 4 or i == 5) else width-thickness
oled.fill_rect(x+xOffset, startY, thickness, endY-startY, color)

def draw_colon(x, y):
oled.fill_rect(x, y, 3, 3, 1)
oled.fill_rect(x, y+14, 3, 3, 1)

def update_screen(year, month, day, hour, minute, am_pm, colon_on, temp_c, temp_f):
left_margin = -28
y_offset = 11
digit_width = 33
digit_height = 40
digit_spacing = 41
digit_thickness = 5

oled.fill(0)

# Draw date at top
date_str = f"{month}/{day}/{year}"
oled.text(date_str, 0, 0, 1)

# Draw temperature at top right (both C and F)
temp_str = f"{temp_c:.1f}C/{temp_f:.1f}F"
oled.text(temp_str, 55, 0, 1)

# Convert 24-hour to 12-hour format
display_hour = hour if hour <= 12 else hour - 12
if display_hour == 0:
display_hour = 12

hour_ten = display_hour // 10 if display_hour >= 10 else -1
hour_right = display_hour % 10
minute_ten = minute // 10
minute_right = minute % 10

drawDigit(hour_ten, left_margin, y_offset, digit_width, digit_height, digit_thickness, 1)
drawDigit(hour_right, left_margin + digit_spacing-2, y_offset, digit_width, digit_height, digit_thickness, 1)
drawDigit(minute_ten, left_margin + 2*digit_spacing, y_offset, digit_width, digit_height, digit_thickness, 1)
drawDigit(minute_right, left_margin + 3*digit_spacing, y_offset, digit_width, digit_height, digit_thickness, 1)

if colon_on:
draw_colon(47, 20)

oled.text(am_pm, 106, 55, 1)
oled.show()

# Initialize temperature conversion
force_temp_conversion()

counter = 0
last_temp_conversion = 0
TEMP_UPDATE_INTERVAL = 10 # Force new reading every 10 seconds

while True:
current_time = time.time()
# Check if it's time for a new temperature conversion
if current_time - last_temp_conversion >= TEMP_UPDATE_INTERVAL:
force_temp_conversion()
last_temp_conversion = current_time
now = read_ds3231()
year, month, day, hour, minute, second = now
am_pm = "PM" if hour >= 12 else "AM"

# Read temperature from RTC
temp_c, temp_f = read_temperature()

update_screen(year, month, day, hour, minute, am_pm, True, temp_c, temp_f)
sleep(1)
update_screen(year, month, day, hour, minute, am_pm, False, temp_c, temp_f)
sleep(1)
counter += 1
Loading

0 comments on commit 221e2c2

Please sign in to comment.