board
RITHESH LED Display
Public Unreviewedby Rithesh03
A 300 x 70 mm PCB that spells RITHESH with 107 WS2812B RGB LEDs, controlled over Wi-Fi.
main
Rithesh03
Update 4: improved README (V1 overview, images, LED order), Version 2 proposal files
b874429
13d ago
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
"""Create the Version 2 LED footprint: v2/hardware/rithesh_v2_fp.pretty/LED_XL-2020RGBC-2812B.kicad_mod
Drawn from the XINGLIGHT XL-2020RGBC-WS2812B datasheet, page 11 (LCSC C5349955):
- Body 2.0 x 2.0 mm, 0.65 mm tall.
- "Recommended Soldering Pattern": four 0.85 (across) x 0.75 (down) mm pads, 0.5 mm apart across
and 0.5 mm apart down -> pad centres +/-0.675 x +/-0.625 mm.
- Pins (top view): DI top-left, GND top-right, VDD bottom-left, DO bottom-right.
Pin table: 1 DO, 2 GND, 3 DI, 4 VDD. The round mark on the top of the LED sits at the DO corner (pin 1);
the bottom-view triangle points to the same side.
NOTE: the pin order is different from the Version 1 LED (XL-5050: 1 VDD, 2 DO, 3 GND, 4 DI).
Usage: python3 make_v2_footprint.py
"""
import os
V2HW = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
LIB = os.path.join(V2HW, "rithesh_v2_fp.pretty")
PAD_W, PAD_H = 0.85, 0.75 # pad size, across x down (datasheet recommended pattern)
GAP_X, GAP_Y = 0.5, 0.5 # gaps between pads
PX = GAP_X / 2 + PAD_W / 2 # 0.675: pad centre, across
PY = GAP_Y / 2 + PAD_H / 2 # 0.625: pad centre, down
BODY = 1.0 # half of the 2.0 mm body
SILK_W = 0.15 # JLCPCB minimum silkscreen line width
SILK_Y = PY + PAD_H / 2 + 0.25 # 1.25: silkscreen lines above/below the pads (0.175 mm clear of pads)
SILK_X = PX + PAD_W / 2 + 0.15 # 1.25: line length
CY_X = PX + PAD_W / 2 + 0.25 # courtyard: pads + 0.25 mm -> 1.35
CY_Y = BODY + 0.25 # body + 0.25 mm -> 1.25
# (number, name, x, y) in KiCad coordinates (y down), top view
PADS = [("1", "DO", PX, PY), ("2", "GND", PX, -PY), ("3", "DI", -PX, -PY), ("4", "VDD", -PX, PY)]
def line(x1, y1, x2, y2, layer, w):
return (f' (fp_line (start {x1:.3f} {y1:.3f}) (end {x2:.3f} {y2:.3f}) '
f'(stroke (width {w}) (type solid)) (layer "{layer}"))\n')
def led_footprint():
s = ('(footprint "LED_XL-2020RGBC-2812B" (version 20221018) (generator rithesh_gen)\n'
' (layer "F.Cu")\n'
' (descr "XINGLIGHT XL-2020RGBC-WS2812B addressable RGB LED, 2.0x2.0mm (LCSC C5349955). Manufacturer '
'recommended soldering pattern (datasheet p.11): 4 pads 0.85x0.75mm, 0.5mm apart across and down '
'(centres +/-0.675 x +/-0.625mm). Pin 1 DO (bottom-right, marked corner), 2 GND, 3 DI, 4 VDD.")\n'
' (tags "LED RGB addressable WS2812 2020 XL-2020RGBC-2812B")\n'
' (attr smd)\n'
' (fp_text reference "REF**" (at 0 -2.0) (layer "F.SilkS")\n'
' (effects (font (size 0.8 0.8) (thickness 0.15))))\n'
' (fp_text value "XL-2020RGBC-2812B" (at 0 2.1) (layer "F.Fab")\n'
' (effects (font (size 0.5 0.5) (thickness 0.08))))\n'
' (fp_text user "${REFERENCE}" (at 0 0) (layer "F.Fab")\n'
' (effects (font (size 0.4 0.4) (thickness 0.06))))\n')
b = BODY
# Fab: 2.0 x 2.0 body, corner chamfer at pin 1 (DO, bottom-right) and the round top mark
for (x1, y1, x2, y2) in [(-b, -b, b, -b), (b, -b, b, b - 0.3), (b, b - 0.3, b - 0.3, b),
(b - 0.3, b, -b, b), (-b, b, -b, -b)]:
s += line(x1, y1, x2, y2, "F.Fab", 0.05)
s += (' (fp_circle (center 0.5 0.7) (end 0.64 0.7) (stroke (width 0.05) (type solid)) '
'(fill none) (layer "F.Fab"))\n')
# Silkscreen: lines above and below the pads, pin-1 dot outside the DO corner
s += line(-SILK_X, -SILK_Y, SILK_X, -SILK_Y, "F.SilkS", SILK_W)
s += line(-SILK_X, SILK_Y, SILK_X, SILK_Y, "F.SilkS", SILK_W)
s += (' (fp_circle (center 1.6 1.25) (end 1.75 1.25) (stroke (width 0.1) (type solid)) '
'(fill solid) (layer "F.SilkS"))\n')
for (x1, y1, x2, y2) in [(-CY_X, -CY_Y, CY_X, -CY_Y), (CY_X, -CY_Y, CY_X, CY_Y),
(CY_X, CY_Y, -CY_X, CY_Y), (-CY_X, CY_Y, -CY_X, -CY_Y)]:
s += line(x1, y1, x2, y2, "F.CrtYd", 0.05)
for num, name, x, y in PADS:
s += (f' (pad "{num}" smd rect (at {x:.3f} {y:.3f}) (size {PAD_W} {PAD_H}) '
f'(layers "F.Cu" "F.Paste" "F.Mask") (pinfunction "{name}"))\n')
return s + ")\n"
def main():
os.makedirs(LIB, exist_ok=True)
path = os.path.join(LIB, "LED_XL-2020RGBC-2812B.kicad_mod")
with open(path, "w") as f:
f.write(led_footprint())
# self-checks against the datasheet numbers
xs = sorted({round(x, 3) for _, _, x, _ in PADS})
ys = sorted({round(y, 3) for _, _, _, y in PADS})
assert abs((xs[1] - xs[0]) - PAD_W - GAP_X) < 1e-9 and abs((ys[1] - ys[0]) - PAD_H - GAP_Y) < 1e-9
assert SILK_Y - SILK_W / 2 - (PY + PAD_H / 2) >= 0.15 # silkscreen >= 0.15 mm from pads
print("wrote", path)
print(f"pads {PAD_W} x {PAD_H} mm, centres +/-{PX:.3f} x +/-{PY:.3f} mm, "
f"gaps {GAP_X} / {GAP_Y} mm, pattern {2 * PX + PAD_W:.2f} x {2 * PY + PAD_H:.2f} mm, "
f"courtyard {2 * CY_X:.2f} x {2 * CY_Y:.2f} mm")
for num, name, x, y in PADS:
print(f" pad {num} {name:3} at ({x:+.3f}, {y:+.3f})")
if __name__ == "__main__":
main()