2021-06-19 15:15:38 -04:00
|
|
|
I2C interface to the firmware
|
|
|
|
-----------------------------
|
|
|
|
|
|
|
|
To control the operation of the keyboard's firmware, the firmware
|
|
|
|
exposes some "registers" that the user can read/write using the
|
|
|
|
two kinds of I2C transfers.
|
|
|
|
|
|
|
|
1) set values of consecutive block of registers starting from REG_ADDR:
|
|
|
|
|
|
|
|
START TX(DEV_ADDR+WR REG_ADDR [REG_DATA REG+1_DATA REG+2_DATA ...]) STOP
|
|
|
|
|
|
|
|
2) read values of consecutive block of registers starting from REG_ADDR:
|
|
|
|
|
|
|
|
START TX(DEV_ADDR+WR REG_ADDR) STOP
|
|
|
|
START TX(DEV_ADDR+RD) RX(REG_ADDR [REG_DATA REG+1_DATA REG+2_DATA ...]) STOP
|
|
|
|
|
|
|
|
Device address is 0x15.
|
|
|
|
|
|
|
|
|
|
|
|
Registers
|
|
|
|
---------
|
|
|
|
|
|
|
|
0x00: Device ID1 (0x4b)
|
|
|
|
0x01: Device ID2 (0x42)
|
|
|
|
0x02: Firmware revision
|
|
|
|
0x03: System configuration
|
|
|
|
bit 0: disable KB scanning (1: scanning disabled, 0: scanning enabled)
|
|
|
|
bit 1: poll mode
|
|
|
|
1: don't rely on row change detection, poll the matrix periodically
|
|
|
|
(prevents MCU power down)
|
|
|
|
0: power down the MCU when no key is pressed, and rely on change
|
|
|
|
detection on row inupts to wake the MCU up
|
|
|
|
bit 2: enable USB debug interface
|
|
|
|
1: enabled
|
|
|
|
0: disabled
|
|
|
|
|
|
|
|
0x10: Keyboard data for column 1
|
|
|
|
...
|
|
|
|
0x0b: Keyboard data for column 12
|
|
|
|
0x0c: CRC8 of keyboard data from 0x10-0x0b
|
|
|
|
|
2021-06-19 15:42:52 -04:00
|
|
|
0x20: Writing value 0x53 ('S') to this register stops the main app from
|
|
|
|
jumping to the user app.
|
2021-06-19 15:15:38 -04:00
|
|
|
|
|
|
|
0x70: Flashing mode unlock key
|
|
|
|
(writing 0x46 to this register unlocks the flashing mode.)
|
2021-06-19 15:23:03 -04:00
|
|
|
|
2021-06-19 15:15:38 -04:00
|
|
|
0x71: Flashing control
|
|
|
|
Writing various commands to this register makes the MCU execute them,
|
|
|
|
if the MCU is not executing the previous command. Available commands:
|
2021-06-19 15:23:03 -04:00
|
|
|
|
2021-06-19 15:15:38 -04:00
|
|
|
0x52 - read a block of data from code ROM
|
|
|
|
0x57 - write a block of data to code ROM
|
|
|
|
0x45 - erase the code rom memory block (128B)
|
|
|
|
0x43 - confirm the validity of the firmware and enable redirection
|
|
|
|
to it from the main app (this redirection is automatically
|
|
|
|
disabled before executing the 0x57 command)
|
2021-06-19 15:23:03 -04:00
|
|
|
|
|
|
|
This register will ignore further commands as long as the last operation
|
|
|
|
is still in progress. This register will contain the code of the
|
|
|
|
currently executed operation, and will be cleared after the operation
|
|
|
|
finishes. Completion is also signalled by pulsing the INT pin shortly.
|
|
|
|
|
|
|
|
If the operation fails, this register will contain value 0xff. If it
|
|
|
|
succeeds it will contain value 0x00.
|
|
|
|
|
2021-06-19 15:15:38 -04:00
|
|
|
0x7d: target address low byte
|
|
|
|
0x7e: target address high byte
|
2021-06-19 15:23:03 -04:00
|
|
|
|
2021-06-19 15:15:38 -04:00
|
|
|
0x7f: CRC8 calculated for the 128B block of data from 0x80-0xff
|
|
|
|
- this must be written by the user when preparing data for write
|
2021-06-19 15:23:03 -04:00
|
|
|
operation, MCU checks the CRC8 of the data and compares it against
|
|
|
|
the value in this register before starting the execution of
|
|
|
|
0x57 command
|
|
|
|
|
|
|
|
- this is updated by the MCU after reading the data from flash memory
|
|
|
|
|
2021-06-19 15:15:38 -04:00
|
|
|
0x80: 128B block of EEPROM data (either read from code memory or to be
|
|
|
|
... written)
|
|
|
|
0xff
|
2021-06-19 15:42:52 -04:00
|
|
|
|
|
|
|
|
|
|
|
Usage
|
|
|
|
-----
|
|
|
|
|
|
|
|
User can modify register 0x03 to choose how the firmware should operate.
|
|
|
|
The settings are not persistent across resets.
|
|
|
|
|
|
|
|
To read the keyboard matrix status, the user can perform a 13B read transaction
|
|
|
|
from address 0x10 and calculate CRC8 on the first 12 bytes and compare it with
|
|
|
|
the 13th byte.
|
|
|
|
|
|
|
|
Bit 0 corresponds to row 1, bit 5 to row 6, bits 6 and 7 are always 0.
|
|
|
|
|
|
|
|
|
|
|
|
Flashing
|
|
|
|
--------
|
|
|
|
|
|
|
|
The firmware is split into 3 parts:
|
|
|
|
|
|
|
|
0x0000 - 0x2000: Stock USB bootloader
|
|
|
|
0x2000 - 0x4000: Stock FOSS firmware (flashable from stock bootloader)
|
|
|
|
0x4000 - 0x8000: User app (optional, flashable over I2C from stock FOSS firmware)
|
|
|
|
|
|
|
|
When the stock FOSS firmware runs after MCU powerup or reset, it will wait for 200ms
|
|
|
|
and listen on I2C. If 0x53 is not written to register 0x20 during that time and
|
|
|
|
the user's app is flashed and commited, it will redirect interrupt vectors to
|
|
|
|
0x4000+offset and jump to 0x4000, which will start executing user's app.
|
|
|
|
|
|
|
|
User app should always return value 0x00 when reading register 0x20, to make it
|
|
|
|
easy to distinguish that the "stay in stock app" command succeeded.
|
|
|
|
|
|
|
|
Flashing steps:
|
|
|
|
|
|
|
|
1) Unlock by writing 0x46 to register 0x70
|
|
|
|
2) Write address to 0x7d/0x7e
|
|
|
|
3) Write data to 0x80-0xff and CRC8 to 0x7f
|
|
|
|
4) Write command 0x57 to 0x71
|
|
|
|
5) Poll 0x71 for result (either 0x00 or 0xff)
|
|
|
|
... repeat 2-5 for all memory locations to be flashed
|
|
|
|
6) Write command 0x43 to reg 0x71
|
|
|
|
7) Wait for success
|
|
|
|
|
|
|
|
Reset the MCU.
|