Skip to main content

Communicating with the fan controller

This documentation will take you through the low level details of connecting to and communicating with the fan controller. There are libraries available that do this work for you already, but if your microcontroller does not support these libraries or if you like to get more hands on with the low level protocol, this article is for you.

The I2C bus

The controller uses the ubiquitous I2C bus for communication. All that is needed for this protocol is a common ground line between the VanTurtle fan controller (refereed to as the board in this documentation) and a SCL (clock) and SDA (data) line that can be pulled low.

Connect GND to the ground on your microcontroller, and VCC to a 5v or 3.3v source. Then connect SDA and SCL to the pins on your microcontroller which support those. Usually this is almost any pins and you can define which one are used in software.

The bus will need a pull-up resistor (PUR) on both the clock and data line. For some microcontrollers like the Raspberry Pi these come integrated already. If your microcontroller does not have those build-in there are already PURs on the board, but they are not enabled by default. This is because the PUR will set the voltage to VCC, which can be higher than the microcontroller expects. If you are sure that your supplied VCC is not higher than the max input voltage for your microcontroller you can enable the PUR by bridging the two pads at the bottom of the board marked “PUR”. You could apply a little solder to permanently bridge them. After this you should be able to measure voltage between GND and SDA.

Finding the address

Each VanTurtle fan controller occupies a single 7-bit I2C address, which is selected using the three hardware address pins on the board. You’ll find these marked “I2C ADDR” on the back of the board. The pins are labeled A0, A1 and A2. By connecting these pins you determine which address the board will respond to on the I2C bus.

The default address, with all pins diconnected, is 27. You can connect (“short”) or disconnect any combination of the three pins to change the address. This allows you to use multiple different boards on the same bus. Here are the possible addresses:

A0 A1 A3 Address
Shorted Shorted Shorted 0x20
Disconnected Shorted Shorted 0x21
Shorted Disconnected Shorted 0x22
Disconnected Disconnected Shorted 0x23
Shorted Shorted Disconnected 0x24
Disconnected Shorted Disconnected 0x25
Shorted Disconnected Disconnected 0x26
Disconnected Disconnected Disconnected 0x27

Before attempting any communication, ensure that you know which address your board is configured for and that your microcontroller is using the same value. If communication fails, the address selection is the first thing to verify. On most platforms, you can also confirm the address by performing an I2C bus scan and observing which addresses acknowledge.

Initializing the board

Once the board is physically connected and the correct I2C address is known, the next step is to initialize the I/O expander on the board. Initialization sets almost all pins in write mode and the auto hold sense in input mode.

The expander exposes two independent 8-bit ports with each port corresponding to one fan. During initialization, both ports must be configured identically. This is a list of all relevant registers:

Register Address Description
Input fan 1 0x00 Read IO state, useful for autohold
Input fan 2 0x01
Output fan 1 0x02 Set output low or high
Output fan 2 0x03
Configuration fan 1 0x06 Set which pins are input and which are output
Configuration fan 2 0x07

First, it is recommended (though not strictly required) to verify that the board is responding on the bus. This can be done by reading any register from the device, for example one of the configuration registers. A successful read indicates that the address and wiring are correct.

READ FROM
0x06
RESULT
00000000

If that succeeds, congratulations! You’re talking to the board.

Next, we need to configure the direction of each pin. On both ports, pin 7 is used as an input to sense the auto hold LED state, while all other pins are outputs used to simulate button presses. To achieve this, write the value 0x01 to both configuration registers. In binary, this corresponds to 00000001, meaning bit 0 is an input and all other bits are outputs.

WRITE TO
0x06
DATA
00000001
WRITE TO
0x07
DATA
00000001

You should see the LEDs on the board go from dimly on to fully off. This signals that the board has been configured. You can test a simple command by turning the fan one LED on:

WRITE TO
0x02
DATA
00000010

Pressing buttons

All interaction with the fan is performed by simulating physical button presses using the output pins. Each button corresponds to a specific bit in the output register for the selected fan. A button press is represented by driving the associated output pin high for a short period of time and then returning it to low.

The output registers are 8-bit wide, with each bit controlling one function. Bit 0 is used as the auto hold LED input and should always remain low. The remaining bits are mapped as follows:

Bit RJ45 function RJ11 function
0 Invalid
This is the auto hold input pin
Invalid
This is the auto hold input pin
1 Fan activity LED
On the VanTurtle controller, not the fan
Fan activity LED
On the VanTurtle controller, not the fan
2 Auto
Hold temperature, also turns the fan on from sleep
Invalid
Pin floating with RJ11 connection
3 In / Out
Reverse airflow
On / Speed
Turns on, then cycles speeds 1-2-3-4
4 On / Off Close lid
5 Faster Open lid
6 Slower Off
7 Beep
Just makes the fan beep
Invalid
Pin floating with RJ11 connection
5 AND 6 Open / Close
Only on some models
Invalid
Use bits 4 and 5 instead

To press a button, you must first read the current value of the output register, modify only the bit corresponding to the desired button, and then write the updated value back. This read–modify–write sequence is important, as multiple outputs may be active at the same time and writing a fixed value could unintentionally change the state of other pins. Read current state from fan one:

READ FROM
0x02
RESULT
00000000

Then you must set the bit of the function you want to high and set the LED to on. It’s important to set the LED on in the same write to the LED is always on if a button is being pressed on the fan. If any button on the fan is held down it will ignore any other input, even on the control panel on the fan itself. It is therefore important for debugging fan issues that the LEDs can be trusted.

In this example we want to reverse the airflow of the fan, In / Out is assigned to bit 3, so we set bit 3 high and make sure that bit 1, the activity LED, is also set to high:

WRITE TO
0x02
DATA
00001010

Then we’ll have to wait a bit. The Maxxair will poll every so often, possibly every 50 milliseconds. It’s recommended to hold the button pressed for at least 150 milliseconds to make sure the button press is registered.

When the wait is over, read the output register again:

READ FROM
0x02
RESULT
00001010

This should hopefully be the same data as we read, but if any bits have been written to during our wait we do not want to overwrite them. To turn the output off again we take the read result 00001010 and set our bit 3 to 0 again. If all bits but bit 1 are 0 again, we can turn the LED on bit 1 off again to:

WRITE TO
0x02
DATA
00000000

Depending on the fan model, On / Off must be held longer (approximately 750 ms) to be detected reliably. Additionally, issuing one or two short (150ms) Beep presses immediately before pressing On / Off can significantly improve reliability on these models.

Reading the Auto Hold state

In addition to simulating button presses, the board also allows you to read back the Auto Hold state, which indicates whether the fan is currently in automatic (“hold to set”) mode.

Each fan exposes this information via one input pin on the I/O expander. As described earlier, pin 0 of each port is configured as an input and is electrically connected to the Auto Hold LED on the fan. This LED is driven by the fan itself, not by the board.

To read the Auto Hold state, you must read the input register corresponding to the fan:

READ FROM
0x00
RESULT
00000001

The register contains the state of all eight pins on the port, but only bit 0 is relevant for Auto Hold detection. The state is inverted and set to 1 if autohold is off, and 0 if the fan is in auto mode. In this case, bit 0 is set to 1, which means the Auto Hold LED is off.

You can use the autohold to “reset” the fan to a state that your microcontroller knows, as turning auto hold on will always turn the fan on but never turn it off. You can then trigger an On / Off and know for sure the fan is off.