feat(kernel): add debounced (glitch-filtered) sense-line reads #5
@ -94,10 +94,10 @@ the 1 ms ATN ack and the per-byte ack — both forgiving. The tight constraint i
|
||||
|
||||
| IEC signal | Pi GPIO (BCM) | Header pin | Direction | Logic note |
|
||||
|------------|---------------|------------|-----------|------------|
|
||||
| ATN | GPIO 2 | 3 | input (divider) | bus low = Pi low = asserted |
|
||||
| CLK | GPIO 17 | 11 | input (divider) | bus low = Pi low = asserted |
|
||||
| DATA (in) | GPIO 18 | 12 | output → 7406 → bus | Pi HIGH = bus asserted (inverted) |
|
||||
| RESET | GPIO 3 | 5 | input (divider) | bus low = Pi low = asserted |
|
||||
| ATN | GPIO 4 | 7 | input (divider) | bus low = Pi low = asserted |
|
||||
| CLK | GPIO 3 | 5 | input (divider) | bus low = Pi low = asserted |
|
||||
| DATA (in) | GPIO 2 | 3 | output → 7406 → bus | Pi HIGH = bus asserted (inverted) |
|
||||
| RESET | GPIO 17 | 11 | input (divider) | bus low = Pi low = asserted |
|
||||
| GND | — | 6 (or any) | — | tie to IEC pin 2 |
|
||||
|
||||
> Convention used in code: a helper layer converts electrical reads/writes into
|
||||
|
||||
@ -59,11 +59,11 @@ at global number 0 — it's `gpiochip512`, **base 512**:
|
||||
$ cat /sys/class/gpio/gpiochip*/base # -> 512 (pinctrl-bcm2835), 566 (exp-gpio)
|
||||
```
|
||||
|
||||
The old code used `gpio_to_desc(2/3/17/18)`, i.e. the *global* numberspace
|
||||
The old code used `gpio_to_desc(2/3/4/17)`, i.e. the *global* numberspace
|
||||
assuming base 0. Those small numbers now fall outside the chip's range
|
||||
(512–565), so every `gpio_to_desc()` returned `NULL`, the descriptor check
|
||||
tripped, and init bailed with `-ENODEV`. The `(chip, hwnum)` lookup passes the
|
||||
**BCM number as the chip-relative offset** (ATN=2, RESET=3, CLK=17, DATA=18),
|
||||
**BCM number as the chip-relative offset** (ATN=4, RESET=17, CLK=3, DATA=2),
|
||||
which is base-independent and survives kernel bumps / gpiochip renumbering.
|
||||
|
||||
Notes:
|
||||
|
||||
@ -25,20 +25,26 @@ The shifter is **non-inverting**: bus low (asserted) ⇒ Pi reads LOW.
|
||||
|
||||
| IEC signal | IEC DIN pin | Pi GPIO (BCM) | Header pin | Direction |
|
||||
|------------|-------------|---------------|------------|-----------|
|
||||
| ATN | 3 | GPIO 2 | 3 | input (via shifter) |
|
||||
| CLK | 4 | GPIO 17 | 11 | input (via shifter) |
|
||||
| DATA | 5 | GPIO 18 | 12 | **bidirectional** (via shifter) |
|
||||
| RESET | 6 | GPIO 3 | 5 | input (via shifter) |
|
||||
| ATN | 3 | GPIO 4 | 7 | input (via shifter) |
|
||||
| CLK | 4 | GPIO 3 | 5 | input (via shifter) |
|
||||
| DATA | 5 | GPIO 2 | 3 | **bidirectional** (via shifter) |
|
||||
| RESET | 6 | GPIO 17 | 11 | input (via shifter) |
|
||||
| GND | 2 | GND | 6 (or any) | — |
|
||||
| SRQ | 1 | — | — | not connected |
|
||||
|
||||
> ℹ️ **DATA (GPIO2) and CLK (GPIO3) are the Pi's ARM I²C pins** and carry the
|
||||
> SoC's fixed ~1.8 kΩ pull-ups (benign — DATA is open-drain). Keep
|
||||
> `dtparam=i2c_arm` **off** in `/boot/firmware/config.txt` (the default) so I²C
|
||||
> does not claim these pins. This layout matches a confirmed-working reference
|
||||
> listener.
|
||||
|
||||
## DATA open-drain emulation
|
||||
|
||||
GPIO 18 is never a push-pull driver of the bus. The module flips its direction:
|
||||
GPIO 2 is never a push-pull driver of the bus. The module flips its direction:
|
||||
|
||||
- **assert** (pull bus low): GPIO 18 = output **LOW** → shifter pulls bus to 0 V.
|
||||
- **release / read**: GPIO 18 = **input (Hi-Z)** → bus pull-ups float it to 5 V,
|
||||
and GPIO 18 reads the level the *talker* (C64) is driving — this is how bits
|
||||
- **assert** (pull bus low): GPIO 2 = output **LOW** → shifter pulls bus to 0 V.
|
||||
- **release / read**: GPIO 2 = **input (Hi-Z)** → bus pull-ups float it to 5 V,
|
||||
and GPIO 2 reads the level the *talker* (C64) is driving — this is how bits
|
||||
are sampled during receive.
|
||||
|
||||
Logical mapping (handled in `kernel/iec_lines.h`): asserted ⇔ Pi reads LOW.
|
||||
|
||||
@ -92,18 +92,21 @@ Constants are defined in [`iec_listener.h`](iec_listener.h); the ioctl number is
|
||||
|
||||
### ⚠️ Bare-board caveat
|
||||
|
||||
With **nothing connected**, the expected result is **`0x15`**, *not* a fault:
|
||||
With **nothing connected**, the expected result is **`0x0B`**, *not* a fault:
|
||||
|
||||
- `DATA_ASSERT_OK` (`0x01`) passes — it's internal to the Pi.
|
||||
- `ATN_RELEASED` (`0x04`) and `RESET_RELEASED` (`0x10`) pass **only because
|
||||
GPIO2/GPIO3 have fixed ~1.8 kΩ pull-ups built into the BCM2710 SoC** (they are
|
||||
the I²C0 pins; the pull-ups can't be disabled). They read high even with
|
||||
nothing wired, so on a bare board these two bits prove **nothing** about your
|
||||
wiring.
|
||||
- `DATA_FLOAT_OK` (`0x02`) and `CLK_RELEASED` (`0x08`) read low because GPIO17/18
|
||||
have no such built-in pull-up and nothing is attached.
|
||||
- `DATA_FLOAT_OK` (`0x02`) and `CLK_RELEASED` (`0x08`) pass **only because
|
||||
DATA=GPIO2 and CLK=GPIO3 have fixed ~1.8 kΩ pull-ups built into the BCM2710
|
||||
SoC** (they are the I²C pins; the pull-ups can't be disabled). They read high
|
||||
even with nothing wired, so on a bare board these two bits prove **nothing**
|
||||
about your wiring. In particular `DATA_FLOAT_OK` now floats high via the SoC
|
||||
pull-up even without the shifter, so it no longer confirms the shifter's DATA
|
||||
pull-up — it's only meaningful once the shifter is wired.
|
||||
- `ATN_RELEASED` (`0x04`) and `RESET_RELEASED` (`0x10`) read low because
|
||||
ATN=GPIO4 and RESET=GPIO17 have no such built-in pull-up and nothing is
|
||||
attached.
|
||||
|
||||
So on a bare board the only meaningful signal is `DATA_ASSERT_OK`. A full `0x1F`
|
||||
is only reachable once the level shifter (with its CLK/DATA pull-ups) is wired
|
||||
and powered. To make ATN/RESET meaningful, briefly ground each at the connector
|
||||
and confirm the corresponding bit *drops*.
|
||||
So on a bare board the only fully internal signal is `DATA_ASSERT_OK`. A full
|
||||
`0x1F` is only reachable once the level shifter (with its ATN/RESET pull-ups) is
|
||||
wired and powered. To make ATN/RESET meaningful, briefly ground each at the
|
||||
connector and confirm the corresponding bit *drops*.
|
||||
|
||||
@ -1,10 +1,15 @@
|
||||
/*
|
||||
* iec-overlay.dts - pin reservation + pull configuration for the IEC listener.
|
||||
*
|
||||
* GPIO 2 = ATN (input, pull-up: bus idle = 5 V = high)
|
||||
* GPIO 17 = CLK (input, pull-up)
|
||||
* GPIO 3 = RESET (input, pull-up)
|
||||
* GPIO 18 = DATA (bidirectional; starts as input/Hi-Z, the module flips it)
|
||||
* GPIO 4 = ATN (input, pull-up: bus idle = 5 V = high)
|
||||
* GPIO 3 = CLK (input, pull-up)
|
||||
* GPIO 17 = RESET (input, pull-up)
|
||||
* GPIO 2 = DATA (bidirectional; starts as input/Hi-Z, the module flips it)
|
||||
*
|
||||
* NOTE: DATA (GPIO2) and CLK (GPIO3) are the ARM I2C pins and carry the SoC's
|
||||
* fixed ~1.8 kOhm pull-ups, which the overlay's pull settings cannot fully
|
||||
* override. Benign here (DATA is open-drain). Keep dtparam=i2c_arm OFF so I2C
|
||||
* does not claim these pins.
|
||||
*
|
||||
* The module drives GPIO via direct registers, so this overlay's main job is to
|
||||
* reserve the pins and set sane pull defaults. Build & install:
|
||||
@ -25,12 +30,12 @@
|
||||
target = <&gpio>;
|
||||
__overlay__ {
|
||||
iec_input_pins: iec_input_pins {
|
||||
brcm,pins = <2 17 3>; /* ATN, CLK, RESET */
|
||||
brcm,pins = <4 3 17>; /* ATN, CLK, RESET */
|
||||
brcm,function = <0>; /* 0 = input */
|
||||
brcm,pull = <2>; /* 2 = pull-up */
|
||||
};
|
||||
iec_data_pin: iec_data_pin {
|
||||
brcm,pins = <18>; /* DATA */
|
||||
brcm,pins = <2>; /* DATA */
|
||||
brcm,function = <0>; /* start as input (Hi-Z) */
|
||||
brcm,pull = <0>; /* 0 = none (shifter drives) */
|
||||
};
|
||||
|
||||
@ -10,8 +10,8 @@
|
||||
* bus released (5 V) <=> Pi GPIO reads HIGH
|
||||
*
|
||||
* DATA is open-drain emulated on a single bidirectional pin:
|
||||
* assert : drive GPIO18 OUTPUT LOW -> shifter pulls bus to 0 V
|
||||
* release : set GPIO18 INPUT (Hi-Z) -> bus pull-ups float it to 5 V;
|
||||
* assert : drive GPIO2 OUTPUT LOW -> shifter pulls bus to 0 V
|
||||
* release : set GPIO2 INPUT (Hi-Z) -> bus pull-ups float it to 5 V;
|
||||
* the talker's bits can now be read back through the shifter.
|
||||
*
|
||||
* The hot path uses direct BCM register access (ioremap'd), which the kernel
|
||||
@ -30,10 +30,10 @@
|
||||
#include <linux/io.h>
|
||||
|
||||
/* --- GPIO assignment (BCM numbering, PLAN.md §3.2) ----------------------- */
|
||||
#define IEC_GPIO_ATN 2 /* header pin 3 - input */
|
||||
#define IEC_GPIO_RESET 3 /* header pin 5 - input */
|
||||
#define IEC_GPIO_CLK 17 /* header pin 11 - input */
|
||||
#define IEC_GPIO_DATA 18 /* header pin 12 - bidirectional (open-drain) */
|
||||
#define IEC_GPIO_ATN 4 /* header pin 7 - input */
|
||||
#define IEC_GPIO_RESET 17 /* header pin 11 - input */
|
||||
#define IEC_GPIO_CLK 3 /* header pin 5 - input */
|
||||
#define IEC_GPIO_DATA 2 /* header pin 3 - bidirectional (open-drain) */
|
||||
|
||||
/* --- BCM2710A1 / BCM2837 (Pi Zero 2 W) peripheral map ------------------- */
|
||||
/* Same peripheral base as RPi 3. RPi 1 = 0x20000000, RPi 4 = 0xFE000000. */
|
||||
|
||||
@ -189,8 +189,9 @@ if [ "$ST" -eq 0 ]; then
|
||||
ok "self-test PASSED (0x1F) - all four lines wired correctly"
|
||||
else
|
||||
info "self-test did not fully pass."
|
||||
info "On a BARE board 0x15 is expected and fine: only DATA_ASSERT_OK is"
|
||||
info "meaningful; ATN/RESET pass via the SoC's fixed GPIO2/3 pull-ups."
|
||||
info "On a BARE board 0x0b is expected and fine: DATA_FLOAT_OK + CLK_RELEASED"
|
||||
info "pass via the SoC's fixed GPIO2/3 (DATA/CLK) pull-ups, and DATA_ASSERT_OK"
|
||||
info "is internal; ATN/RESET read low (GPIO4/17 have no built-in pull-up)."
|
||||
info "Re-run once the level shifter is wired + powered; you want 0x1F."
|
||||
fi
|
||||
exit "$ST"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user