I2C and Registers
I2C (Inter-Integrated Circuit), also known as TWI (Two-Wire Interface), is a communication protocol that allows multiple devices to talk over just two shared signal lines:
- SDA (Serial Data): carries the data
- SCL (Serial Clock): keeps everything in sync
On the bus, one device acts as the controller (your expansion board) and the other as a peripheral (the moddoMOUSE Main Board). The controller drives the clock and initiates all transactions whereas the peripheral only responds when addressed.
Addressing
Every I2C peripheral has a unique 7-bit address that the controller uses to identify it on the bus. The moddoMOUSE Main Board always responds at address 0x0A. Since the Front and Back boards are on separate I2C buses (I2C0 and I2C1), there is no address conflict even though both buses use the same address.
Registers
The moddoMOUSE Main Board exposes its data and settings through a register map which is a list of memory locations, each holding a specific piece of information. Registers are addressed sequentially starting at index 0, and the Main Board supports sequential (burst) reads and writes, meaning you can read or write multiple consecutive registers in a single I2C transaction rather than one at a time.
| Register | Name | Description |
|---|---|---|
| 0x00 | DEVICE_ID (low) | Unique device identifier (low byte) |
| 0x01 | DEVICE_ID (high) | Unique device identifier (high byte) |
| 0x02 | PROD_ID | Product ID (always 0x01 for moddoMOUSE) |
| 0x03 | STATUS | Not currently used |
| 0x04 | BATTERY_VOLTAGE (low) | Battery voltage in mV (low byte) |
| 0x05 | BATTERY_VOLTAGE (high) | Battery voltage in mV (high byte) |
| 0x06 | BATTERY_CAPACITY | Battery capacity in percent (0–100), or 255 if unknown |
| 0x07 | BATTERY_CHARGER_STATUS | Charger and battery status flags |
| 0x08 | MOUSE_SETTINGS | Polling rate, invert X/Y, swap XY |
| 0x09 | MOUSE_X (low) | Accumulated X motion delta (low byte) |
| 0x0A | MOUSE_X (high) | Accumulated X motion delta (high byte) |
| 0x0B | MOUSE_Y (low) | Accumulated Y motion delta (low byte) |
| 0x0C | MOUSE_Y (high) | Accumulated Y motion delta (high byte) |
| 0x0D | ANGLE_TUNE | Angle tune offset (–30 to +30 degrees) |
| 0x0E | MAIN_BUTTONS | Main button states (left, right, middle, back, forward) |
| 0x0F | V_WHEEL | Vertical scroll wheel accumulated delta |
| 0x10 | H_WHEEL | Horizontal scroll wheel accumulated delta |
| 0x11 | INT_EN | Interrupt enable flags |
| 0x12 | LIFT_DISTANCE | Lift-off distance setting (1mm or 2mm) |
| 0x13 | CPI_X (low) | X-axis DPI/CPI (low byte) |
| 0x14 | CPI_X (high) | X-axis DPI/CPI (high byte) |
| 0x15 | CPI_Y (low) | Y-axis DPI/CPI (low byte) |
| 0x16 | CPI_Y (high) | Y-axis DPI/CPI (high byte) |
| 0x17 | EXP_BOARD_BUTTONS_0 | Expansion board buttons (bits 0–7) |
| 0x18 | EXP_BOARD_BUTTONS_1 | Expansion board buttons (bits 8–15) |
| 0x19 | EXP_BOARD_BUTTONS_2 | Expansion board buttons (bits 16–23) |
| 0x1A | EXP_BOARD_BUTTONS_3 | Expansion board buttons (bits 24–31) |
💡 Motion (X/Y) and scroll wheel registers accumulate their values until read. Reading them resets the accumulator, so you always get the delta since the last read rather than an instantaneous snapshot.
Interrupt Pin (INT)
Rather than constantly polling the Main Board for updates, your expansion board can wait for the INT pin to signal that something has changed. The Main Board will assert INT when any of the following enabled events occur:
- Mouse motion detected
- Main button state changed
- Scroll wheel moved
- Battery status changed
- A fault condition occurred
Interrupt sources are individually enabled or disabled via the INT_EN register. When an interrupt fires, you read the relevant register(s) to clear it.