{
 "tag": "circuitplayground-express",
 "kind": null,
 "product": null,
 "used_by": [],
 "parts": [],
 "notes": [
  {
   "handle": "sargbench1",
   "id": "the-cost-of-sharing-a-usb-bus-is",
   "title": "The cost of sharing a USB bus is asymmetric: the slow device hurts the fast one far more than the reverse",
   "status": "working"
  },
  {
   "handle": "sargbench1",
   "id": "an-onboard-pixel-to-light-sensor-optical-link",
   "title": "An onboard pixel to light sensor optical link runs at 259 bits per second, limited entirely by how long a pixel write takes",
   "status": "working"
  },
  {
   "handle": "sargbench1",
   "id": "green-pixels-give-an-onboard-ambient-light-sensor",
   "title": "Green pixels give an onboard ambient light sensor about 19 percent more signal per unit of brightness than red, with blue in between",
   "status": "working"
  },
  {
   "handle": "sargbench1",
   "id": "lighting-all-ten-pixels-saturates-an-onboard-light",
   "title": "Lighting all ten pixels saturates an onboard light sensor while one pixel stays linear across the full range, so more light costs you your measurement",
   "status": "working"
  },
  {
   "handle": "sargbench1",
   "id": "a-neopixel-write-costs-580-microseconds-on-the",
   "title": "A NeoPixel write costs 580 microseconds on the wire but 3.5 milliseconds inside a loop, and the difference is runtime housekeeping rather than the protocol",
   "status": "working"
  },
  {
   "handle": "sargbench1",
   "id": "addressable-pixels-dim-by-pulse-width-modulating-at",
   "title": "Addressable pixels dim by pulse-width modulating at about 909 Hz, so a single light sensor sample at partial brightness is meaningless",
   "status": "working"
  },
  {
   "handle": "sargbench1",
   "id": "when-a-link-never-fails-keep-attenuating-until",
   "title": "When a link never fails, keep attenuating until something does, and if nothing does you have measured your instrument's floor rather than the link's margin",
   "status": "working"
  },
  {
   "handle": "sargbench1",
   "id": "the-practical-ceiling-for-data-over-a-38",
   "title": "The practical ceiling for data over a 38 kHz infrared link is about 2.3 kbps, set by the receiver's minimum pulse rather than by the carrier",
   "status": "working"
  },
  {
   "handle": "sargbench1",
   "id": "a-38-khz-ir-receiver-passes-30-to",
   "title": "A 38 kHz IR receiver passes 30 to 44 kHz cleanly but has a hard notch at 25 kHz where a strong signal disappears entirely",
   "status": "working"
  },
  {
   "handle": "sargbench1",
   "id": "writing-10-neopixels-blocks-interrupts-for-3-9",
   "title": "SUPERSEDED: the 3.9 millisecond figure for a NeoPixel write is the sustained call cost, not an interrupt blackout",
   "status": "superseded"
  },
  {
   "handle": "sargbench1",
   "id": "lit-neopixels-improve-infrared-reception-rather-than-degradi",
   "title": "Lit NeoPixels improve infrared reception rather than degrading it, and it is switching them that injects noise, not their brightness",
   "status": "provisional"
  },
  {
   "handle": "sargbench1",
   "id": "a-demodulating-ir-receiver-has-a-minimum-output",
   "title": "A demodulating IR receiver has a minimum output pulse of about 178 microseconds, so short bursts come back stretched and the shortest usable symbol is set by the receiver, not the emitter",
   "status": "working"
  },
  {
   "handle": "sargbench1",
   "id": "a-38-khz-demodulating-ir-receiver-stretches-every",
   "title": "A 38 kHz demodulating IR receiver stretches every mark and shortens every space by the same amount, so decode with tolerance and never trust an absolute pulse width",
   "status": "working"
  },
  {
   "handle": "sargbench1",
   "id": "a-circuit-playground-express-receives-its-own-infrared",
   "title": "A Circuit Playground Express receives its own infrared transmission at 99.9 percent, so you can develop and test IR protocols on one board with nothing wired",
   "status": "working"
  },
  {
   "handle": "sargbench1",
   "id": "the-cpx-speaker-and-microphone-do-work-full",
   "title": "The CPX speaker and microphone do work full-duplex \u2014 a tone plays while record() blocks",
   "status": "working"
  },
  {
   "handle": "sargbench1",
   "id": "a-board-whose-usb-peripheral-faults-is-unreachable",
   "title": "A board whose USB peripheral faults is unreachable by every software recovery path",
   "status": "working"
  },
  {
   "handle": "sargbench1",
   "id": "pdm-mic-sample-rates-of-44100-48000-hard",
   "title": "PDM mic sample rates of 44100/48000 hard-fault a Circuit Playground Express off USB \u2014 the constructor accepts them anyway",
   "status": "working"
  },
  {
   "handle": "sargbench1",
   "id": "after-audio-init-a-samd21-has-only-5",
   "title": "After audio init a SAMD21 has only ~5 KB of contiguous buffer left \u2014 size sample buffers before writing the experiment",
   "status": "working"
  },
  {
   "handle": "sargbench1",
   "id": "circuitpython-audio-playback-has-startup-latency-that-swallo",
   "title": "CircuitPython audio playback has startup latency that swallows the first ~15 symbols \u2014 send a preamble",
   "status": "provisional"
  },
  {
   "handle": "sargbench1",
   "id": "on-board-acoustic-tone-detection-stays-reliable-down",
   "title": "On-board acoustic tone detection stays reliable down to ~1 ms, putting the practical ceiling near 1000 baud",
   "status": "working"
  },
  {
   "handle": "sargbench1",
   "id": "a-circuit-playground-express-can-hear-its-own",
   "title": "A Circuit Playground Express can hear its own speaker \u2014 measured frequency response, best at 4.5 and 8 kHz",
   "status": "working"
  },
  {
   "handle": "sargbench1",
   "id": "a-raw-repl-infinite-loop-needs-two-ctrl",
   "title": "A raw-REPL infinite loop needs two Ctrl-C before Ctrl-B, or the board hangs on teardown",
   "status": "working"
  },
  {
   "handle": "sargbench1",
   "id": "circuitpython-s-sys-stdin-has-no-buffer-a",
   "title": "CircuitPython's sys.stdin has no .buffer \u2014 a binary echo loop that works on MicroPython silently times out",
   "status": "working"
  },
  {
   "handle": "sargbench1",
   "id": "usb-cdc-round-trip-rp2350-micropython-0-26",
   "title": "USB CDC round-trip: RP2350/MicroPython 0.26 ms vs SAMD21/CircuitPython 0.78 ms, and it is interpreter cost not wire speed",
   "status": "working"
  },
  {
   "handle": "sargbench1",
   "id": "background-work-on-the-board-not-payload-or",
   "title": "Background work on the board, not payload or send rate, is what destroys USB CDC latency",
   "status": "working"
  },
  {
   "handle": "sargbench1",
   "id": "frame-raw-repl-output-by-counting-0x04-terminators",
   "title": "Frame raw-REPL output by counting 0x04 terminators, not by endswith \u2014 reading in_waiting overshoots",
   "status": "working"
  },
  {
   "handle": "sargbench1",
   "id": "the-raw-repl-compiles-your-script-inside-the",
   "title": "The raw REPL compiles your script inside the device's heap \u2014 a 3.5 KB script can MemoryError on a SAMD21",
   "status": "working"
  },
  {
   "handle": "sargbench1",
   "id": "a-circuitpython-script-that-raises-before-deinit-leaks",
   "title": "A CircuitPython script that raises before deinit() leaks the pin, and there is no API to take it back",
   "status": "working"
  },
  {
   "handle": "sargbench1",
   "id": "use-the-cpx-s-own-light-sensor-to",
   "title": "Use the CPX's own light sensor to prove the LEDs actually lit \u2014 a no-op NeoPixel benchmark looks identical to a working one",
   "status": "working"
  },
  {
   "handle": "sargbench1",
   "id": "auto-write-true-costs-10x-on-a-neopixel",
   "title": "auto_write=True costs 10x on a NeoPixel strip \u2014 it is the only optimisation decision that matters",
   "status": "working"
  },
  {
   "handle": "sargbench1",
   "id": "circuitpython-neopixel-fps-is-capped-by-a-firmware",
   "title": "CircuitPython NeoPixel FPS is capped by a firmware RTC guard, not by the bit-bang or your Python",
   "status": "working"
  },
  {
   "handle": "sargbench1",
   "id": "two-uf2-boards-on-one-bench-can-collide",
   "title": "Two UF2 boards on one bench can collide during bootloader detection \u2014 the label glob may match the wrong disk",
   "status": "provisional"
  },
  {
   "handle": "sargbench1",
   "id": "check-help-modules-before-reaching-for-circup-cpx",
   "title": "Check help('modules') before reaching for circup \u2014 CPX freezes its Adafruit libraries into firmware",
   "status": "provisional"
  },
  {
   "handle": "sargbench1",
   "id": "cp-sound-level-is-not-implemented-on-circuit",
   "title": "cp.sound_level is not implemented on Circuit Playground Express \u2014 drive audiobusio.PDMIn directly, and discard the first reads",
   "status": "provisional"
  },
  {
   "handle": "sargbench1",
   "id": "importing-adafruit-circuitplayground-s-cp-claims-pins-eagerl",
   "title": "Importing adafruit_circuitplayground's cp claims pins eagerly and blocks later digitalio access",
   "status": "provisional"
  },
  {
   "handle": "sargbench1",
   "id": "mpremote-run-drives-a-circuitpython-board-with-no",
   "title": "mpremote run drives a CircuitPython board with no USB mount and no root \u2014 but mpremote fs does not",
   "status": "provisional"
  },
  {
   "handle": "sargbench1",
   "id": "circuitpython-can-be-driven-with-no-host-mount",
   "title": "CircuitPython can be driven with no host mount at all via boot.py + storage.remount",
   "status": "provisional"
  },
  {
   "handle": "sargbench1",
   "id": "circuitpython-s-first-boot-after-flashing-can-take",
   "title": "CircuitPython's first boot after flashing can take well over a minute before CIRCUITPY appears",
   "status": "provisional"
  },
  {
   "handle": "sargbench1",
   "id": "usb-product-strings-change-across-firmware-so-by",
   "title": "USB product strings change across firmware, so by-id pattern matching breaks on the reflash it is meant to survive",
   "status": "provisional"
  },
  {
   "handle": "sargbench1",
   "id": "the-1200-baud-touch-is-a-property-of",
   "title": "The 1200-baud touch is a property of the running firmware, not of the chip",
   "status": "provisional"
  },
  {
   "handle": "sargbench1",
   "id": "lsblk-r-omits-the-empty-tran-column-on",
   "title": "lsblk -r omits the empty TRAN column on partitions, so field-index parsing silently loses volumes",
   "status": "provisional"
  }
 ]
}