I²Ccommunication specification
Inside FP01, the Arduino (I²C master) interprets commands received over RS485 and issues instructions over I²C to the PSoC 4 (output control), the EEPROM (settings storage) and the DMX drivers (on FP01 Rev1.6 the OLED is also on I²C). This page summarizes the communication settings, the PSoC 4 registers and the byte sequence of each command, based on an analysis of the FP01 firmware Rev13 and PSoC Creator project sources.
I²CBus configuration
FP01 has two I²C buses. The Arduino-side I²C connects the PSoC 4 and EEPROM on the FP01 board (and the OLED on FP01 Rev1.6) and is also routed to the main board through FFC pins 21 and 22. The PSoC-side I²C is routed to FFC pins 19 and 20; on DIMX4 it is assigned to the temperature sensor (TEMP/SDA, SCL).
Pin numbers follow the FFC connector specification (FFC_Rev2). The DMX driver addresses are defined in the firmware; driver 1 is the board closest to the ribbon cable.
Communication settings
The Arduino is the only master. Wire.begin() is called without arguments, so the Arduino joins the bus as master. No speed is specified, so it runs at the Arduino default of 100 kHz. The OLED library (U8x8) raises the clock to 400 kHz unless told otherwise, so setBusClock(100000) keeps it at 100 kHz.
PSoC 4
Register-type slave to which dimming levels, fade times and the module ID are written. Write only; the Arduino does not read from it.
i2cDIMMER.cpp · PSOC_SLAVE_ADDRESS
EEPROM (AT24C256C)
Stores the module address, per-circuit settings, groups and scenes. Addressed with a 2-byte memory address (high → low).
i2cEEPROM.cpp · SLAVE_ADDRESS_EEPROM
OLED (SH1106)
U8X8_SH1106_128X64_NONAME_HW_I2C of the U8x8 library. The address is the library default. Enters power-save mode after about 5 minutes without operation.
On FP01 Rev2.1 the OLED is connected via SPI (SCK, MOSI, CS + DC, RST) and does not use this I²C address.
screen.cpp
DMX drivers 1–4
Sends fixed 4-byte packets to the address of the driver number (1–4) set for each circuit.
Rev13.ino · I2C_SLAVEADDR_1–4
Settings list
| Item | Value | Defined in | Notes |
|---|---|---|---|
| Role | Arduino = master | Wire.begin() | No argument = master. It is called twice in setup(), with the same effect. |
| Clock | 100 kHz | Arduino default | A comment in the DMX version reads “I²C speed 100 kbps (Arduino default, so not specified)”. |
| OLED clock | 100 kHz | u8x8.setBusClock(100000) | On FP01 Rev1.6 the OLED was on the same bus, so the speeds are matched. |
| Address format | 7-bit | — | All values in the table are 7-bit (the 8-bit value on write is doubled: 0x08 → 0x10). |
| Byte order | Big-endian | — | 2-byte values (dimming level, EEPROM address, DMX channel) are sent high byte first. |
| Wait before PSoC transfer | delay(5) | i2cDIMMER.cpp | Each write waits 5 ms before endTransmission(). |
| EEPROM write wait | 10–20 ms | i2cEEPROM.cpp | 1 byte: 5 ms + 10 ms; 2 bytes: 5 ms + 20 ms; multiple bytes: number of bytes × 5 ms. |
PSoC 4register map
The PSoC 4 is a register-type slave that takes the first byte as the register address and writes the following data to it. Only circuits with local addresses 0–7 are sent to the PSoC 4; addresses 8 and above are not.
| Register | Name | Size | Value | Send function |
|---|---|---|---|---|
0x00 | Module ID | 1 byte | 1:IGBTX4 2:DIMX4 3:PWMX4 4:RELAYX8 5:RRX8 6:CTRL1 7:RS485X | i2c_psoc_write_reg_module_id() |
0x01–0x09 | Unused | — | Not written in Rev13 | — |
0x0A + LA0x0A–0x11 | Fade time | 1 byte × 8 | 0–255 (units of 0.1 s; 2 = 0.2 s) | i2c_psoc_write_reg_fade_time() |
0x12 + LA×20x12–0x21 | Dimming level (DIRECT) | 2 byte × 8 | 0–1000 (actual % × 0.1%; 0 = off, 1000 = 100%), high byte first | i2c_psoc_write_reg_light() |
LA = local address (circuit number within the module, 0–7). Earlier versions had MIN and MAX level registers (0x12, 0x22), but in Rev13 they are commented out, and MIN/MAX conversion is done with the conversion table on the Arduino side.
Transmit frames
i2c_psoc_write_reg_light(LA, level)i2c_psoc_write_reg_fade_time(LA, time)i2c_psoc_write_reg_module_id(id)Calculate the byte sequence
The logical level (0–1000, specified in the RS485 command) is converted to actual % with a conversion table built from each circuit's MIN and MAX before it is sent. Logical 0 maps to 0, logical 1 to MIN, logical 1000 to MAX, and values in between are mapped linearly (when MIN = MAX it is treated as 1–1000).
EEPROM read and write
All settings are stored in an external EEPROM (AT24C256C-SSHL-T, 256 Kbit = 32 KB, 64-byte pages) and read at startup. Memory addresses are 2 bytes (0x0000–0x7FFF), and each circuit has its own block at local address × 0x100 + offset. The 64 circuits LA0–63 (0x0000–0x3FFF, 16 KB) fit within the capacity, and the firmware page length EEPROM_PAGE_LENGTH = 64 matches the page size of this EEPROM.
i2c_eeprom_write_byte / _2byte / _nbyteAfter writing, wait until the EEPROM's internal write completes (1 byte 10 ms, 2 bytes 20 ms, N bytes N × 5 ms).
i2c_eeprom_read_byte / _2byteThe address is written, followed by a STOP, then the data is read with requestFrom() (no repeated start is used).
Main stored items
| Offset | Item | Size | Value |
|---|---|---|---|
0x0000 | Module address | 2 | 0–255 (LA0 block only) |
0x000E | Response mode | 1 | Reply type (LA0 block only) |
0x000F | OLED power | 1 | 0:OFF 1:ON (LA0 block only) |
0x0011 | Module type ID | 1 | 1–7 (also written to PSoC register 0x00) |
0x18 | Power-on level | 2 | 0–1000 (logical) |
0x1C / 0x1E | MIN / MAX level | 2 + 2 | 0–1000 (actual %) |
0x22 | Stored level | 2 | Level before OFF (restored by on__) |
0x24 / 0x25 | UP/DOWN step 1 / 2 | 1 + 1 | For wall switches / for HA (× 0.1%) |
0x27 | Fade time | 1 | 0–255 (forwarded as is to PSoC and DMX) |
0x29 | On-delay | 1 | 0–255 (× 0.1 s) |
0x2B | Circuit description | 16 | ASCII |
0x3B | Circuit address | 2 | Address specified over RS485 |
0x40 | Member groups ×16 | 32 | Group n = 0x40 + n×2 |
0x7A / 0x7B | DMX driver number / channel | 1 + 2 | 1–4 / 1–512 |
0x80 | Scene table ×32 | 64 | 0–1000; -1 (0xFFFF) = no change |
Offsets from 0x18 onward are per-circuit values; the actual address is LA × 0x100 + offset.
Packets to the DMX drivers
For circuits with a DMX channel set, a 4-byte packet is sent to the DMX driver at the same time as the transfer to the PSoC 4. The destination is determined by the “DMX driver number” in EEPROM: 1→0x0A, 2→0x0B, 3→0x0C, 4→0x0D.
i2c_DMX(LA, level) → i2c_send_4byte_n()Brightness is the actual % (0–1000) divided by 4. The maximum is 250 and does not reach the DMX maximum of 255. For UP/DOWN operations the fade time is fixed at 2 (0.2 s).
The firmware still contains a polling routine (Polling_Slave_1–4) that reads 12 bytes from a driver and relays them to RS485, but its call from loop() is commented out, so it does not run in Rev13.
RS485 commands and I²C transfers
RS485 commands are 12 ASCII characters (8 for the v command) in the form [1 mode character][3-digit address][4-character instruction][4-digit argument]. The table shows what is sent over I²C when each command is received.
| Command | Description | PSoC 4 (0x08) | DMX | EEPROM |
|---|---|---|---|---|
m dire / a sccc / g sccc | Direct level setting, scene recall | Level | Send | Read only |
v on__ / v off_ / v togg | Group ON, OFF, toggle | Level | Send | Writes the stored level on OFF |
v up__ / down / up_2 / dn_2 | Group UP, DOWN | fade=2 level | Send | Reads the step value |
a fade / g fade | Temporary fade time | Fade | — | Not written |
s wftt / x wftt | Set fade time | Fade | — | 0x27 |
a idon | Start identification blink | fade=15 → alternating 0 / 1000 | — | — |
a idof | Stop identification blink | level=0 | — | — |
| OLED type selection | Change module type | Module ID | — | 0x0011 |
s wmin / wmax / wpol etc. | Write setting values | — | — | Each item |
When raising the level (sending a value greater than 0), the firmware waits for the on-delay (× 0.1 s) before sending.
Startup sequence
Read settings
Reads the module address, type ID, response mode and OLED power from EEPROM.
Fade time
Reads the fade times of LA0–7 from EEPROM and writes them to PSoC 0x0A+LA.
Power-on level
Reads the power-on levels and writes them to PSoC 0x12+LA×2 at 30 ms intervals to turn the circuits on.
Module ID
Reads MIN and MAX to build the conversion table, and finally writes the type ID to PSoC 0x00.
I²C settings of the PSoC projects
The PSoC 5LP projects of the switches (ROTARY03, ROTARY02N) still contain I²C component settings. However, in the current build the place-and-route report shows 0% I²C usage, and communication with FP01 uses RS485 (UART). This is left over from an earlier design that matched FP01's address 0x08 and 100 kbps.
| Project | Component | Mode | Speed | Address | Status |
|---|---|---|---|---|---|
| ROTARY03 Rev1.1.5 CY8C5888LTQ-LP097 | I2C | Master (UDB) | 100 kbps | (0x08) | Unused calls are commented out |
I2C_1 | Multi-master | 100 kbps | 0x08 | Unused | |
| ROTARY02N Rev1.3 | EZI2C_Slave / EZI2C_1 | EZI2C slave (8-bit sub-address) | 100 kbps | 0x08 | Unused |
The firmware of the PSoC 4 (CY8C4245PVI-482) on FP01 is not included in this analysis. The PSoC 4 register map is derived from what the master (Arduino) sends.
Implementation notes
Points to watch, found by reading the Rev13 source.
- Only LA0–7 are sent to the PSoC 4. Even on types with many circuits such as RS485X, the PSoC 4 registers and the conversion table cover only 8 circuits. LA8 and above bypass the conversion table and are sent to DMX only.
- Address used for group reads. In the handling of
a joi1anda gclr, the first argument ofi2c_eeprom_read_2byte()is passedEEPROM_ADDRESS_FOR_GROUP(0x40) instead of0x50. - Position of the transmit wait. Wire sends everything at once when
endTransmission()is called, so thedelay(5)placed before it does not space out the transmission. The interval between consecutive transfers is determined by the wait at the end of each function.