---
# System prepended metadata

title: ARM split

---

# ARM split

**Note: This document does not cover a *"start over from scratch"* solution, but does highlight potential discussion points.**

# Observations

Split common has has progressed slightly to unify across platforms. However in its current state, there are quite a few blocks which stop it from working.

***Primary issues:***
* Master/slave detection is hard coded to always assume master
* Transport does not exist
* No method to set eeprom handedness

***Secondary issues:***
* ARM has only controller based RGB and Backlight support
* Transport API does not fully encapsulate master to slave communication
* Split keyboard logic leaks out of split_common

## master/slave detection
Split code currently expects to run different routines on slave and master. The assumption is that devices cannot run both a requester and responder concurrently. The current process is that the master pulls the matrix and encoder data from the slave, and pushes rgb and backlight settings to the slave.

Current AVR init order:
```
lufa/lufa.c::main
    keyboard.c::keyboard_setup
        split_util.c::matrix_setup
            'usb check'
                init i2c/serial slave/master
    setup_usb
```

Current ARM init order:
```
chibios/main.c::main
    keyboard.c::keyboard_setup
        split_util.c::matrix_setup
            'usb check'
                init i2c/serial slave/master
    init_usb_driver
```

As shown above, 'usb check' cannot simply check "Do I currently have a USB connection". AVR assumes a hardware specific method of checking the usb power. **Note: This check fails on some hardware, as shown here <https://geekhack.org/index.php?topic=89674.0>**

### vitimins_included
Old split code modified to use a slightly different process. Both sides idle as slaves, then one is promoted to master. The main advantage here is that the transport init runs after usb has been configured. 
```
lufa/lufa.c::main
    keyboard.c::keyboard_setup
        vitamins_included::matrix_setup
            "nothing important"
    setup_usb
    keyboard.c::keyboard_init
        vitamins_included::matrix_init
            init i2c/serial slave
            "wait for usb"
                run slave tasks
            init i2c/serial master
```

### Potential Solutions


#### USB connected based
Wrapping up similar behavior to `WAIT_FOR_USB`

* adapt vitimins_included code into split_common
  * Maybe simplify with just a `wait_for_usb_with_timeout`
* init usb earlier
  * allows existing split code to be retained by pushing change elsewhere
* delay usb check check till after setup_usb
    * lazy init of transport to first matrix_scan
    * some processes might assume too much
        * rgblight clips to left and right hand and would need to handle it at a later point
        * pending support for split rgb matrix would need to handle left/right hand changing at a later point

#### Other
Find alternative "usb connected" methods, that allow "meetup RGB demo mode". The keyboard can be connected to a battery pack and thus have no usb connection but still maintain the master/slave connection.

* Using similar method to AVR VBUS detection
  * Fine for custom board where the additional circuitry can be added
  * Bad for Proton C as hardware has already shipped
* Using similar method to SPLIT_HAND_PIN
  * Would allow a `MASTER_LEFT` `MASTER_RIGHT` setup
  * Proton C is limited to bridging pins on the snap off section
    * Less flexible due to hard coded master/slave
    * Provides battery powered "demo mode"

## Transport

Current issues include
* drivers/arm/i2c_serial.[ch] not implemented
  * ChibiOS patch has at least been verified against current QMK fork
      * needs verification against latest release
      * self contained master/slave example might help testing
* split_common/serial.[ch] does not compile for ARM

Requirements
* 1 wire protocol
  * Serial
    * complete implementation required
* 2 wire protocol
  * I2C
    * boards may have wired the I2C bus to both a split slave and device like OLED

Upgrading ChibiOS, maintain patch - could break
Potential to lock in to current version if patch cannot be applied going forward

> Think of the current I2C slave code like a patch file, if the code changes the patch might not apply. Or the surrounding code could change behavior, patch applies fine but fails somehow at runtime.

Requires more in-depth knowledge of ChibiOS than "Contributors/Members" have?

### I2C
Pulling the muon code as a intial example, I2C slave support is reasonably self contained. The current implementation manages one block of memory, and reads/writes at offsets. Each offset is handled as a I2C register. The currently exposed API poses an issue due to ChibiOS not providing a mechninism to know the requested number of bytes. When an I2C callback fires, the amount of data to send is unknown.

Potential Solutions
* Stash offsets -> size, sniff register and map to size
* Refactor api to use a structure which can map data with size
    * Each I2C register can then map 
* Refactor to one block, one register
    * Simple
    * No more offsets, transmit/receive all data in one go
    * More overhead
        * chunking based X bytes

### Serial
Currently coded to only support atmega32u4, and contains timings and various settings which are both compiler. Uses AVR specific interrupts and register configuration. Porting it in its current form would be extremely unlikely. Extracting the existing serial.[ch] into a master/slave under `drivers/avr`, with an exposed API. This can then be implemented for ARM, using the relevant ChibiOS calls.

### Alternatives
While outside of current AVR support, anything that is either simple enough to implement, or bundled as part of ChibiOS could be considered. If it can help bootstrap the project, then its on the table.

* RS232/RS485
  * No ChibiOS support
* SPI
  * Untested patch exists on ChibiOS forum

## eeprom Handedness
Existing AVR implementation relies on flashing another file to set a particular eeprom bit. This may not be possible with dfu-util due to the emulated eeprom paging.

For boards that use `SPLIT_HAND_PIN` or users who accept `MASTER_RIGHT` or `MASTER_LEFT`, this will not be a blocking issue.

*Investigation of other solutions is required.*

Possible solutions include:
* Bootmagic and Magic keycodes
    * Independent of flashing utility
    * Potentially easier for QMK toolbox users
* Fake behaviour of `dfu-util-split-left` etc by conditionally compiling in extra initialisation code

## other

### Transport API does not fully encapulate master to slave communication
* Pushes Backlight/RGB/Encoder logic within each of the Transport implementations

### Split keyboard logic leaks out of split_common
* Many features are becoming aware of split using `#ifdef SPLIT_KEYBOARD` or `is_keyboard_master()`
 
# Project Plan
Minimum Viable Feature vs Minimum Marketable Feature

End Goal:
> Proton C drop in replacement for all current Pro Micro split keyboards

Short Term Goal:
> Proton C replacement for subset of Pro Micro split keyboards with documented limitations


Phase POC/Alpha
* At least 1 working transport
  * A whatever easiest approach
  * Could be something other than i2c/serial (any 1 or 2 wire protocol)
  * Stubs and warnings to allow compilation
* Hard coded master detection
  * Bridge pins and override weak has_usb function
* No eeprom handedness support
* No split RGB/Backlight

Phase 1
* At least 1 compatible transport
  * I2C looks the most promising
  * 1wire covers recent "dual OLED" splits
* Slave detection uses USB connected state

Phase 2
* Both existing transports
  * serial and I2C 
* eeprom handedness

Phase N
* Refactor
    * Transport
    * TBD
* Slave detection works for Teensy2
* Slave detection allows for "meetup RGB demo mode"
* Validation of split RGB
* Validation of split Backlight
* Interoperability of proton-c master with arv slave

## Work Items

1. Merge ChibiOS I2C slave patch
2. Implement ARM i2c_slave
3. Implement slave detection
4. Implement ARM serial transport
5. Investigate eeprom setting via dfu-util
