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 0x20: Writing value 0x53 ('S') to this register stops the main app from jumping to the user app. 0x70: Flashing mode unlock key (writing 0x46 to this register unlocks the flashing mode.) 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: 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. 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. 0x7d: target address low byte 0x7e: target address high byte 0x7f: CRC8 calculated for the 128B block of data from 0x80-0xff - 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 0x80: 128B block of EEPROM data (either read from code memory or to be ... written) 0xff 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.