5.7 KiB
Volvo LIN-to-IR Controller (ATtiny84)
This project implements the production firmware for the ATtiny84 to interface a Volvo V50 Steering Wheel Module (SWM) LIN bus with a Raspberry Pi running LineageOS (Android).
It decodes steering wheel navigation buttons from the vehicle's LIN bus and translates them into bit-banged RC-6 Mode 6A (MCE) remote control commands sent over a direct wire connection.
Pin Configurations (ATtiny84)
| ATtiny84 Pin | Digital Pin (Arduino) | Function | Description |
|---|---|---|---|
| PA0 | 10 |
IR Output | Direct-wired to Raspberry Pi GPIO 24 |
| PB2 | 2 |
LIN RX | SoftwareSerial RX from MCP2004 RXD |
| PB0 | 0 |
LIN TX | SoftwareSerial TX (Unused dummy) |
| PB1 | 1 |
LIN FAULT/TXE | MCP2004 Fault Detect / Transmit Enable |
| PB3 | 11 |
LIN CS | MCP2004 Chip Select (Active High) |
| PA7 | 3 |
Debug LED | Flash on command transmission |
Key Mapping
The Steering Wheel Module (SWM) sends frames on LIN ID 0x20 with the navigation key statuses. The firmware decodes these and maps them to the following Microsoft MCE remote scancodes:
| Button | LIN Frame Trigger | Active Button Code | MCE Scancode | Action on LineageOS |
|---|---|---|---|---|
| UP | d0 & 0x01 |
1 |
0x800f041e |
Navigate Up |
| DOWN | d0 & 0x02 |
2 |
0x800f041f |
Navigate Down |
| LEFT | d0 & 0x04 |
3 |
0x800f0420 |
Navigate Left |
| RIGHT | d0 & 0x08 |
4 |
0x800f0421 |
Navigate Right |
| ENTER | d1 & 0x08 |
5 |
0x800f0422 |
Select / OK |
| BACK | d1 & 0x01 |
6 |
0x800f0423 |
Back / Exit |
| Volume Up (Shutdown) | LIN Silent > 5s | 7 |
0x800f0410 |
Trigger Shutdown (via KeyMapper) |
Note: In previous revisions, ENTER and BACK were reversed. This has been corrected so that pressing ENTER maps to 0x800f0422 and BACK maps to 0x800f0423.
Car-Off (Shutdown) Detection
To automatically power off the Raspberry Pi when the car is turned off:
- Activity Monitor: The ATtiny monitors LIN bus activity. The Central Electronic Module (CEM) continuously polls the LIN bus when the ignition is on.
- Timeout: If no LIN serial data is received for 5 seconds, the ATtiny assumes the car is off.
- Shutdown Signal: It transitions the car status to "off" and sends the MCE code
0x800f0410(mapped toKEY_VOLUMEUP) 3 times to ensure transmission reliability. - State Protection: It will not send the shutdown command again until the car is turned back on and LIN traffic resumes (which sets
is_car_onback totrue).
Raspberry Pi Configuration
1. Keymap Setup
Remap the MCE remote codes on the Raspberry Pi:
- The custom TOML configuration is saved at
/data/rc-rc6-mce.tomlon the Pi. - To apply it dynamically:
/vendor/bin/ir-keytable -w /data/rc-rc6-mce.toml
2. KeyMapper Setup
Instead of MacroDroid, KeyMapper is used to intercept the KEY_VOLUMEUP trigger from the direct-wired IR receiver and execute the shutdown command.
To configure KeyMapper completely via command-line:
- Enable Accessibility Service:
adb shell settings put secure accessibility_enabled 1 adb shell settings put secure enabled_accessibility_services io.github.sds100.keymapper/.system.accessibility.MyAccessibilityService - Grant Do Not Disturb Access (to prevent warnings on volume key mapping):
adb shell settings put secure enabled_notification_policy_access_packages io.github.sds100.keymapper - Map Trigger and Action:
The preconfigured KeyMapper SQLite database is pushed directly to the device. The Volume Up key is mapped to run the command:
reboot -p
3. Wi-Fi Hotspot Auto-start Setup
To enable the Wi-Fi hotspot (VolvoC70_AndroidAuto with passphrase 123456789) automatically at startup:
- A boot shell script
/system/bin/start_hotspot.shis defined to wait for boot completion and start the SoftAP. - A custom Android init service configuration
/system/etc/init/start_hotspot.rcstarts it whensys.boot_completedtransitions to1.
Script (/system/bin/start_hotspot.sh):
#!/system/bin/sh
while [ "$(getprop sys.boot_completed)" != "1" ]; do
sleep 1
done
sleep 5
cmd wifi start-softap VolvoC70_AndroidAuto wpa2 123456789
Init Service (/system/etc/init/start_hotspot.rc):
service start_hotspot /system/bin/sh /system/bin/start_hotspot.sh
class main
user root
group root system wifi
oneshot
disabled
on property:sys.boot_completed=1
start start_hotspot
Protocol and Timing
- Protocol: RC-6 Mode 6A (MCE).
- Time Unit (1T):
444us. - Modulation: None. Timing is bit-banged directly since the output pin is wired directly to the Pi's IR receiver GPIO (which expects demodulated active-low signals).
- Idle (Space):
HIGH(3.3V). - Active Pulse (Mark):
LOW(0V). - Toggle Bit: Alternates state on each new button press, but remains constant for repeated holds.
- Repeat Interval: Holds trigger repeat IR commands sent every
250ms.
Software Architecture
- SoftwareSerial Interrupt Isolation:
Since SoftwareSerial RX interrupts consume about 1ms per byte, they will disrupt the precise microsecond-level timing of bit-banged IR frames. To avoid this, interrupts are disabled (
noInterrupts()) during the 37ms window of IR transmission and re-enabled (interrupts()) immediately afterward. - Release detection:
The SWM continuously transmits frames on the LIN bus. If no button frames are detected or a frame with all 0s is received, the current active button resets to idle. A timeout of
200msensures that if the LIN bus goes quiet, button repeats cease immediately.