metronome/hardware/eda/circuits/rtc.py
Me Here c625a8aaa2 Firmware push fix on both Kit (0.0.24) + Explorer (0.0.4)
Diagnosed from the user's console output - 25 chunks pushed cleanly at
~124ms each, then stalled. Two coupled causes:

1) Bus contention. tick() and Live sync share self.midi with the chunk
   ACKs. While the device was processing a chunk, a Note On / Clock Out /
   Live-sync FULL heartbeat could land on the same MIDI OUT stream and
   the host's parser dropped the interleaved ACK SysEx.

   Fix: self._fw_pushing flag set on 0x21 BEGIN, cleared on 0x23 COMMIT
   or any error. midi_send / Clock Out / _sync_broadcast / _sync_broadcast_full
   all early-out when _fw_pushing is True. Only ACKs go out during a push.

2) SysEx assembler garbage. self._sx = bytearray() per chunk leaks ~70
   bytes / chunk that only GC'd every 50 chunks. 25 chunks of trash plus a
   slow heap walked the wrong way explains the ramp-up to 174 -> 119 -> 124
   ms ACK times. GC every chunk now (~30ms cost on RP2040/RP2350 with
   small heap) so the assembler buffer is always fresh.

Same patch on both pico-cp/ and pico-explorer/ since the bug is identical.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-30 22:51:46 -05:00

66 lines
3.1 KiB
Python

#!/usr/bin/env python3
"""PM_K-1 RTC (SKiDL): RV-8803-C7 I2C real-time clock for the practice-log timestamps.
Run INSIDE the EDA container:
cd hardware/eda && ./run.sh python3 ../eda/circuits/rtc.py
Outputs ERC + hardware/kicad/rtc.net.
VERIFIED pinout (Micro Crystal RV-8803-C7, 8-WCDFN 3.2x1.5mm):
1=SDA 2=CLKOUT 3=VDD 4=CLKOE 5=VSS 6=/INT 7=EVI 8=SCL. Single VDD (no separate VBACKUP
pin); ~240nA typ. Shares the touch I2C bus (SDA=GPIO8, SCL=GPIO9).
BACKUP: diode-OR -- system +3V3 OR the CR2032 feed VDD_RTC through Schottkys, so the
board runs the RTC off 3V3 when on, the coin cell only when off, and (importantly for an
heirloom) the cell can be replaced WITHOUT the RTC losing time. Schottkys block charging
the (non-rechargeable) cell.
Unused pins: CLKOE->GND (CLKOUT disabled), CLKOUT->NC, EVI->GND (no event input),
/INT pulled up + routed to RTC_INT (optional alarm IRQ to a GPIO).
CONFIRM at layout: the RV-8803-C7 footprint, and cross-check the App Manual's recommended
backup circuit.
"""
import os
from skidl import *
set_default_tool(KICAD9)
P = Pin.types
R = Part("Device","R", dest=TEMPLATE, footprint="Resistor_SMD:R_0402_1005Metric")
def C(v): return Part("Device","C", value=v, footprint="Capacitor_SMD:C_0402_1005Metric")
DS = Part("Device","D_Schottky", dest=TEMPLATE, footprint="Diode_SMD:D_SOD-323")
p3v3, gnd = Net("+3V3"), Net("GND")
p3v3.drive = POWER; gnd.drive = POWER
i2c_sda, i2c_scl = Net("I2C_SDA"), Net("I2C_SCL") # shared bus (RP2350 GPIO8/9 + touch)
vdd_rtc, rtc_int = Net("VDD_RTC"), Net("RTC_INT")
RV8803 = Part(name="RV-8803-C7", tool=SKIDL, dest=TEMPLATE, ref_prefix="U",
footprint="RTC_MicroCrystal:RV-8803-C7", # footprint: confirm at layout
pins=[Pin(num=1,name="SDA",func=P.BIDIR),Pin(num=2,name="CLKOUT",func=P.OUTPUT),
Pin(num=3,name="VDD",func=P.PWRIN),Pin(num=4,name="CLKOE",func=P.INPUT),
Pin(num=5,name="VSS",func=P.PWRIN),Pin(num=6,name="INT",func=P.OPENCOLL),
Pin(num=7,name="EVI",func=P.INPUT),Pin(num=8,name="SCL",func=P.INPUT)])
u = RV8803(ref="U7")
u["VDD"] += vdd_rtc; u["VSS"] += gnd
u["SDA"] += i2c_sda; u["SCL"] += i2c_scl
u["CLKOE"] += gnd # disable CLKOUT
u["EVI"] += gnd # unused event input
u["INT"] += rtc_int # open-drain alarm (optional)
# CLKOUT left unconnected
# diode-OR backup: 3V3 -> D1 -> VDD_RTC ; CR2032 -> D2 -> VDD_RTC
d1, d2 = DS(value="BAT54"), DS(value="BAT54")
p3v3 += d1[2]; d1[1] += vdd_rtc # D_Schottky pin1=K, pin2=A : anode at 3V3, cathode at VDD_RTC
bt = Part("Device","Battery_Cell", value="CR2032",
footprint="Battery:BatteryHolder_Keystone_1066_1x2032", ref="BT1")
bt["+"] += d2[2]; d2[1] += vdd_rtc; bt["-"] += gnd
crtc = C("100nF"); vdd_rtc += crtc[1]; crtc[2] += gnd
# I2C pull-ups (bus shared with touch) + /INT pull-up, to 3V3
for net in (i2c_sda, i2c_scl):
r = R(value="4.7k"); net += r[1]; r[2] += p3v3
rint = R(value="10k"); rtc_int += rint[1]; rint[2] += p3v3
ERC()
out = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "kicad", "rtc.net"))
generate_netlist(file_=out)
print("RTC netlist ->", out)