Commit Graph

1 Commits

Author SHA1 Message Date
David Montero b587faf1b0 feat(avr/uart): synthesize bit-level TX waveform on PD1/PE1
avr8js intercepts the transmitted byte at the UDR0 register and never
toggles the corresponding GPIO.  Real ATmega328P / ATmega2560 hardware
drives PD1 / PE1 with a start bit, 8 data bits LSB-first, and a stop bit
at the configured baud rate the moment TXEN is set.  An oscilloscope
probe on D1 therefore showed nothing in Velxio while the same probe in
the real world would resolve the UART frame.

Synthesize the frame from the inside of `onByteTransmit`:

  * Read `usart.baudRate`, `usart.bitsPerChar`, `usart.parityEnabled`,
    `usart.parityOdd`, `usart.stopBits` so unusual configurations stay
    accurate (avr8js already exposes these as public getters).
  * Build the bit list start + data(LSB first) + parity? + stopBit(s).
  * For each transition vs. previous state (initial = idle HIGH), call
    `onPinChangeWithTime(1, state, timeMs)` where
    `timeMs = (cpu.cycles + i * cyclesPerBit) / 16_000`. Same
    simulator-time clock the existing port-listener path uses, so the
    scope draws the UART waveform cycle-accurately alongside other GPIO
    activity.

Also hook `onConfigurationChange` to detect TXEN flipping 0→1 and seed
the scope baseline at idle HIGH; without that, the very first byte's
start bit transition would be invisible because the scope's pre-first-
sample default is LOW.

Both USART construction sites (initial setupSimulation around line 423,
re-init after stop around line 749) get the same hook.

Covered by `__tests__/avr-uart-tx-waveform.test.ts` (5 cases): idle seed,
byte with internal transitions, 0xFF edge case, TXEN-disabled no-op,
bit-period timing.
2026-05-22 19:49:43 +02:00