Wanting to hear some sound from my Presto, sadly the onboard buzzer is inaudible for my hearing, I got one of those Adafruit plug and play amp/speaker boards. Now I can give the hearing aid a nice workout :-)
Well that works very nicely, but there goes the Presto i2c port and I wanted to connect more stuff. After initially considering a GPIO extender I thought I would have a go at using the 12c_target that micropython came out with in their latest release and create an i2c slave on a pico board to link to the Presto.
Well that was quite easy, I have a test pico set up as an i2c slave to which I attach that speaker to, but also other sensors like and i2c based sht40 temperature sensor. Marvellous, and looking at my test code I’m left wondering why it took me all day to get it working, but it did. The lack of examples of setting up a pico as an i2c slave is my excuse.
Anyway flush with my now enhanced Presto, albeit now sporting a tangled array of i2c connector leads, a pico, a dangling speaker board and a temperature sensor, I shall now have to design some small pcb and 3d printed box to connect it all and discreetly hide it behind the Presto screen.
In case it helps anyone I give my small test snippets where a rpi pico is used as an i2c slave device, and a test snippet to run on a i2c master pico (or presto etc)
The Slave:
import asyncio
from machine import I2CTarget, I2C, Pin, PWM
import sht4x
alarm_event = asyncio.Event()
# mem bytearray: bytes 0-7 for being writen to, bytes 8 and 9 for reading temperature,
# bytes 10 and 11 for humidity
mem = bytearray(12)
mv = memoryview(mem)
# ----------------------------
# Create the i2c slave
i2c_slave = I2CTarget(0, scl=Pin(1), sda=Pin(0), addr=67, mem=mem)
# -----------------------------
# Create i2c sht40 temp/hum sensor
i2c_sht40 = I2C(1, scl=Pin(3), sda=Pin(2))
#sht4x_address = 0x44 #defult address in driver
sht40_sensor = sht4x.SHT4X(i2c_sht40)
async def sound_alarm():
SPEAKER_PIN = 7
# create a Pulse Width Modulation Object on this pin
speaker = PWM(Pin(SPEAKER_PIN))
while True:
speaker.duty_u16(0)
await alarm_event.wait()
speaker.duty_u16(30_000)
while alarm_event.is_set():
speaker.freq(810)
await asyncio.sleep(0.5)
speaker.freq(1000)
await asyncio.sleep(0.5)
# check mem bytearray for i2c writes
async def check_mem():
while True:
if mem[0]:
print('doing something because mem[0] was set')
mem[0] = 0
elif mem[1]:
print('doing something because mem[1] was set')
mem[1] = 0
elif mem[2]: #trigger alarm sound
asyncio.create_task(alarm_trigger())
mem[2] = 0
#etc
await asyncio.sleep(0)
async def alarm_trigger():
# sound alarm for 3 seconds
alarm_event.set()
await asyncio.sleep(3)
alarm_event.clear()
async def update_temp_sensor():
# read i2c sht40 temp/hum sensor every 30 seconds
while True:
temp, hum = sht40_sensor.measurements
temp = int(round(temp,1)*10)
hum = int(round(hum,1)*10)
mv[8:10] = temp.to_bytes(2,'little')
mv[10:12] = hum.to_bytes(2,'little')
await asyncio.sleep(30)
async def main():
asyncio.create_task(check_mem())
asyncio.create_task(update_temp_sensor())
asyncio.create_task(sound_alarm())
while True:
await asyncio.sleep(0)
try:
print('Program i2c_target_test has started')
asyncio.run(main())
except KeyboardInterrupt:
print('Ctl C')
finally:
print('Program i2c_target_test has ended')
asyncio.new_event_loop()
The Master
from machine import Pin, I2C
i2c = I2C(0, scl=Pin(1), sda=Pin(0), freq=400_000)
# write byte to i2c slave mem address 0
i2c.writeto_mem(67, 0, b'1')
# wite a non zero byte to slave address 2
# which will trigger alarm sound on speaker
i2c.writeto_mem(67, 2, b'1')
# read from i2c slave addresses containing temperature and humidity
# values from the sht40 sensor
temp_bytes = i2c.readfrom_mem(67,8,2)
hum_bytes = i2c.readfrom_mem(67,10,2)
temp = float((int.from_bytes(temp_bytes, 'little'))/10)
hum = float((int.from_bytes(hum_bytes, 'little'))/10)
print('Temperature / Humidity:', temp, hum)