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 --------- General ranges: 0x00 - 0x1f - Read-only status range 0x20 - 0x2f - Writable keyboard control range 0x70 - 0xf4 - Flashing interface 0xff - Debug log 0x00: Device ID1 (0x4b) 0x01: Device ID2 (0x42) 0x02: Firmware revision 0x03: Firmware features bit 0: USB debugger bit 1: Flashing mode bit 2: Self-test features bit 3: Stock firmware flag (only stock firmware should have this set) bit 4: Charger register read/writes are supported 0x06: bits 3-0: number of rows, bits 7-4 number of cols 0x07: CRC8 of keyboard data from 0x08-0x13 0x08: Keyboard data for column 1 ... 0x13: Keyboard data for column 12 (up to number of cols, in this case 12) 0x20: System configuration bit 0: disable KB scanning (1: scanning disabled, 0: scanning enabled) 0x21: Charger register address 0x22: Charger register value 0x23: System command Writing values into this register causes the firmware to perform certain one-shot actions: 0x72 ('r') - reset the MCU 0x69 ('i') - jump to USB bootloader 0x74 ('t') - run a self-test (results are as a text in debug log) 0x91 - read charger register 0xA1 - write charger register The register is set to 0x00 or 0xff after the operation completes. 0xff means error. 0x24: Writing value 0x53 ('S') to this register stops the main app from jumping to the user app. 0x70: 128B block of EEPROM data (either read from code memory or to be ... written) 0xef 0xf0: target address low byte 0xf1: target address high byte 0xf2: CRC8 calculated for the 128B block of data from 0x70-0xef - this must be written by the user when preparing data for write 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 so the user can check the checksum against the data read from 0x70-0xef 0xf3: Flashing mode unlock key - writing 0x46 to this register unlocks the flashing mode. - this register is cleared after command completion 0xf4: Flashing control Writing various commands to this register makes the MCU execute them, if the MCU is not executing the previous command. Available commands: 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) 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. If the operation fails, this register will contain value 0xff. If it succeeds it will contain value 0x00. 0xff: Debug log - reading from this register returns next character of the debug log or 0 - register address is not auto-advanced for the 0xff address, so you can read any number of bytes from 0xff to get the debug log text - debug log stores results of self-tests Usage ----- User can modify register 0x20 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 0x07. Data for each column start at 0x08, 0x07 contains CRC8 checksum of the 12 bytes starting from 0x08. You can verify the data by calculating CRC8 on the last 12 bytes and compare it with the 1st 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) It is necessary to execute stock firmware to flash the user firmware. Stock firmware will normally re-direct execution to user firmware if user firmware is flashed. After MCU powerup or reset, stock firmware will listen for 1s on I2C interface, before passing control to the user firmware. If 0x53 is not written to register 0x24 during that time, this will prevent execution of the user's firmware. If the user firmware execution is not prevented in this way, stock firmware will redirect interrupt vectors from 0x0000+offset to 0x4000+offset and jump to 0x4000, which will start execution of user's firmware. User firmware must not change last byte of IRAM, because it is used by the stock firmware's interrupt redirection mechanism. User's firmware should always implement some way to reset the MCU via I2C interface. This will make development and flashing easier. Failing that, I2C flashing tool also allows for manual entry to stock firmware which is done by holding the power key for > 12s to force power cycle on the MCU. Flashing steps: 1) Write 128 B of data to 0x70-0xef and data CRC8 to 0xf2 2) Write address to 0xf0 (low) and 0xf1 (high byte) (only range from 0x4000 to 0x7fff) is writeable 3) Unlock by writing 0x46 to register 0xf3 4) Write command 0x57 to 0xf4 5) Poll 0xf4 for result (either 0x00 or 0xff) ... repeat 1-5 for all memory locations to be flashed 6) Write command 0x43 to reg 0xf4 7) Poll 0xf4 for result (either 0x00 or 0xff) 8) Reset the MCU by writing command 0x72 to reg 0x23 Self-tests ---------- 1) Write command 't' to reg 0x23 2) Read repeatedly from register 0xff to get the self-test results in human readable text form