Files
n_signer/plans/teensy41_bringup.md

183 lines
8.9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Plan: Teensy 4.1 Bring-up (Blink → Serial → Display → Touch → SD)
> **Status: Phase 0 + SD + TFT + touch all verified on hardware (2026-07-26).**
> - **Toolchain** installed (`teensy:avr` 1.62.0 + udev rules), blink sketch
> confirmed (red LED @ 1 Hz), HelloSerial confirmed (`teensy41 alive #N` over
> `/dev/ttyACM0` once per second). CDC-ACM transport path verified.
> - **SD card** test sketch ([`firmware/teensy41/sd_test/sd_test.ino`](../firmware/teensy41/sd_test/sd_test.ino))
> mounted a 32 GB FAT32 card via `SD.begin(BUILTIN_SDCARD)` (4-bit SDMMC),
> listed the root directory, read the first 512 bytes of `bcm2710-rpi-2-b.dtb`.
> exFAT re-test pending the 1 TB SDXC card.
> - **TFT display** test sketch ([`firmware/teensy41/tft_test/tft_test.ino`](../firmware/teensy41/tft_test/tft_test.ino))
> confirmed on hardware: **landscape 480×320**, fill edge-to-edge, text
> readable, colors correct. Uses `ST7796_t3` library (hardware SPI0).
> - **Touch** calibration sketch ([`firmware/teensy41/touch_cal/touch_cal.ino`](../firmware/teensy41/touch_cal/touch_cal.ino))
> confirmed on hardware: 4-corner tap calibration → live dot-draw tracks the
> stylus across the full 480×320 screen.
> **Calibration constants:** `x_min=207, x_max=1909, y_min=168, y_max=1798,
> invert_x=1, invert_y=1` (with axis swap: raw Y → screen X, raw X → screen Y).
>
> **Hard-won lessons (read these before porting the display/touch code):**
>
> 1. **Landscape, not portrait.** The target orientation is **landscape
> 480×320** (wider than tall). Use `tft.init(320, 480)` + `setRotation(1)`
> to get landscape with zero offsets. Do NOT use `init(480, 320)` — that
> hits the library's else-branch which computes a negative `_colstart` and
> offsets the image off the panel.
> 2. **`tft.width()` / `tft.height()` are broken.** The `ST7796_t3` accessors
> always return the unrotated 480×320 regardless of `setRotation()`. Use the
> constants `SCREEN_W=480` / `SCREEN_H=320` for all drawing coordinates,
> never `tft.width()`/`tft.height()`.
> 3. **Pin 10 is SPI0 CS0 — do not `pinMode` it.** Calling `pinMode(10, INPUT)`
> (e.g. for `t_irq`) corrupts the SPI0 engine and reverts the display to
> the wrong orientation. `t_irq` is on **pin 2** (see
> [`firmware/teensy41/WIRING.md`](../firmware/teensy41/WIRING.md)).
> 4. **XPT2046 axes are swapped in landscape rotation 1.** Raw Y maps to
> screen X, raw X maps to screen Y. The calibration struct stores
> `x_min/x_max` as the range of raw Y, `y_min/y_max` as the range of raw X,
> and `raw_to_screen()` swaps accordingly.
> 5. **`drawPixel()` mispositions near edges.** Use `fillRect(x, y, 1, n, c)` /
> `fillRect(x, y, n, 1, c)` for crosshairs and thin lines instead of
> `drawPixel()` — `fillRect` is reliable across the full screen.
>
> **Next:** exFAT re-test on the 1 TB SDXC card (when it arrives), then start
> porting the CYD display/touch/UI code per
> [`plans/teensy41_signer_port.md`](teensy41_signer_port.md) Phase 2+.
Phase 0 of [`plans/teensy41_signer_port.md`](teensy41_signer_port.md). Goal: prove the
toolchain, the board, and the USB CDC transport path before porting any signer code.
Toolchain: **Arduino CLI + Teensyduino** (matches the primary path in the port plan).
## 0. On the LED you see at power-on
The Teensy 4.1 ships from PJRC with a factory **blink sketch** on the onboard red LED
(pin 13). Expected behavior at first plug-in:
- **Red LED near USB connector blinks ~1 Hz** → factory blink program is running → board is healthy.
- **Steady red LED** → a previous sketch left it on, or the board is halted.
- **Steady orange/green LED** → that is the *power* LED, always on when the board has power. Not the user LED.
- **No LED activity at all, and `lsusb` shows `16c0:0478 ... Teensy Halfkay Bootloader`** → the application flash was erased and the board is sitting in the Halfkay bootloader. This is healthy and is the easiest state to upload from: `arduino-cli upload` (via Teensy Loader) pushes a sketch to Halfkay directly, no Program-button press needed. There is no `/dev/ttyACMx` in this state because Halfkay enumerates as HID, not CDC — `arduino-cli board list` may show nothing, and that is expected.
A steady power LED plus a blinking red user LED = everything is fine.
A Halfkay enumeration with no LED = erased flash, ready to receive a sketch.
## 1. Host toolchain
1. Install `arduino-cli` (e.g. `pip install arduino-cli` or download the binary).
2. Add the Teensyduino core:
```bash
arduino-cli config init
arduino-cli config set board_manager.additional_urls https://www.pjrc.com/teensy/package_teensy_index.json
arduino-cli core update-index
arduino-cli core install teensy:avr
```
3. Verify the FQBN is available:
```bash
arduino-cli board listall teensy: | grep teensy41
```
**Exit criterion:** `teensy:avr:teensy41` appears in the list.
> Note: the `teensy:avr` package from PJRC's index includes the Teensy Loader and
> compiler toolchain (arm-none-eabi-gcc). On Linux, udev rules are required for the
> bootloader device — see PJRC's [Linux udev rules](https://www.pjrc.com/teensy/td_download.html).
> Without them, `arduino-cli upload` will fail with a permission error on `/dev/ttyACMx`.
## 2. Detect the board
1. Plug the Teensy 4.1 into USB (use the onboard USB port, not the USB host header).
2. List Arduino ports:
```bash
arduino-cli board list
```
**Exit criterion:** a port shows up as `/dev/ttyACMx` (Linux), `COMx` (Windows),
or `/dev/cu.usbmodem*` (macOS) with protocol `serial` and board `teensy:avr:teensy41`.
3. If no port appears, press the **Program button** on the Teensy once — that forces
the bootloader to enumerate. (The factory blink sketch does not expose a CDC port
by default, so the port may only show up after the first upload of a sketch that
calls `Serial.begin()`.)
## 3. Blink sketch (first upload)
Create [`firmware/teensy41/teensy41_blink.ino`](../firmware/teensy41/teensy41_blink.ino):
```cpp
// Teensy 4.1 bring-up: blink the onboard red LED on pin 13 at 1 Hz.
void setup() {
pinMode(LED_BUILTIN, OUTPUT); // LED_BUILTIN == 13 on Teensy 4.1
}
void loop() {
digitalWrite(LED_BUILTIN, HIGH);
delay(500);
digitalWrite(LED_BUILTIN, LOW);
delay(500);
}
```
Compile + upload:
```bash
arduino-cli compile --fqbn teensy:avr:teensy41 firmware/teensy41
arduino-cli upload -p /dev/ttyACM0 --fqbn teensy:avr:teensy41 firmware/teensy41
```
If upload fails with "no Teensy found", press the Program button on the board to
force the bootloader, then retry.
**Exit criterion:** the red LED toggles at exactly 1 Hz (slower than the factory
blink, which is ~5 Hz, so the change is obvious).
## 4. HelloSerial (validate the CDC-ACM transport path)
The signer's USB transport ([`plans/teensy41_signer_port.md`](teensy41_signer_port.md) §USB transport)
is TinyUSB CDC-ACM + 4-byte length-prefix framing. Before writing the framer, confirm
that a plain `Serial.print` over USB CDC works end-to-end.
Create [`firmware/teensy41/teensy41_hello_serial.ino`](../firmware/teensy41/teensy41_hello_serial.ino):
```cpp
// Teensy 4.1 bring-up: print a counter over USB CDC every second.
void setup() {
Serial.begin(115200); // USB CDC on Teensy 4.1
pinMode(LED_BUILTIN, OUTPUT);
}
void loop() {
static uint32_t n = 0;
digitalWrite(LED_BUILTIN, HIGH);
Serial.print("teensy41 alive #");
Serial.println(n++);
delay(500);
digitalWrite(LED_BUILTIN, LOW);
delay(500);
}
```
Compile + upload, then open a monitor:
```bash
arduino-cli monitor -p /dev/ttyACM0 -c baudrate=115200
# or: stty -F /dev/ttyACM0 115200 raw -echo && cat /dev/ttyACM0
```
**Exit criterion:** `teensy41 alive #0`, `#1`, `#2`… prints once per second, and the
red LED blinks in lockstep. This proves the CDC-ACM path we will reuse for the
signer's length-prefix framing.
## 5. Next milestones (covered by separate plans)
Once blink + serial are confirmed, the rest of Phase 1 from
[`plans/teensy41_signer_port.md`](teensy41_signer_port.md) proceeds:
1. **ST7796S 480×320 display** — port [`firmware/cyd_esp32_2432s028/main/ili9341.c`](../firmware/cyd_esp32_2432s028/main/ili9341.c)
with the ST7796S init sequence from [`firmware/teensy41/ST7796S_Datasheet.pdf`](../firmware/teensy41/ST7796S_Datasheet.pdf)
and the Elecrow wiki page. Wiring per the port plan: TFT SPI on pins 11/12/13,
CS=10, DC=9, RESET=8, BL=22. Exit: fill screen + draw text.
2. **XPT2046 touch** — port [`firmware/cyd_esp32_2432s028/main/touch.c`](../firmware/cyd_esp32_2432s028/main/touch.c)
with 480×320 constants. T_CS=7, T_IRQ=6. Exit: read touch coords, map to pixels.
3. **SD card + exFAT** — install SdFat via Arduino Library Manager, mount a 1 TB
SDXC card via `sd.begin(SdioConfig(FIFO_SDIO))`. Exit: write + read a test file.
## 6. Status tracking
Update [`firmware/teensy41/README.md`](../firmware/teensy41/README.md) from
"Planned — not yet implemented" to "In progress — Phase 0 bring-up" once the blink
sketch is confirmed running on the board.