Controlling a washing machine motor with an Arduino

In a modern washing machine, the moter that spins the drum is controlled by a motor driver, which is separate from the main control board that manages the washing cycle. The main control board sends commands that set the speed of the motor, and the motor driver generates the three-phase power needed for the motor and regulates the speed of the motor. In this article I will explain how I reverse engineered the motor driver (Magnetek 4246-99-1) from a washing machine and then controlled it with an Arduino.

Reverse engineering the original setup

In the washing machine, the motor driver received mains power through a relay on the main control board. The motor driver was controlled by the main control board via a 5-pin cable. The pinout is shown in the image below:
The main control board communicates with the motor driver using an SPI bus. Data is transmitted in bytes with the most-significant-bit first. On the rising edge of the clock signal, the main board updates the signal on the MOSI pin, and the motor driver updates the signal on the MISO pin. On the falling edge of the clock, both devices sample the signals from the other device. In contrast to most implementations, a 1 is actually represented by a low voltage (0V), and a 0 is represented by a high voltage (5V). Thus, the signal on the wire is actually the complement of the transmitted data. An example waveform can be seen in the image below:
In the above image, the main board transmits 11000110 00000000, or C6 00 in hex, to the motor driver. Recall that the voltage on the wire is the complement of the transmitted signal.

The length of a clock pulse is around 0.5 ms, and the spacing between clock pulses for the same byte is 0.5 ms. The spacing between clock pulses in different bytes is 2.5 ms.

Reverse engineering the commands

To determine the commands that are needed to make the motor driver spin the motor, I connected an Arduino to the CLK, MISO, and MOSI pins and used a small sketch to listen on the SPI bus and communicate the intercepted data to my computer via the serial port. Then, I wrote a Python program to take the raw data from Arduino and extract the commands that are transmitted.

Description of the reverse-engineered protocol

Idle pattern

When neither device is transmitting anything, the main board transmits C6 00 repeatedly on the bus. Since the motor driver has no control over the clock signal, this is necessary to allow the motor driver to transmit anything on the bus. Normally, the motor driver will send 00 for every byte.

Transmission from the main board to the motor driver

The main board starts a transmission by transmitting AA in place of the idle pattern. This is followed by one byte indicating the length of the packet, the actual contents of the packet, a CRC8 computed with polynomial 0x01, and the complement of the CRC. For example, the full command to stop the motor is AA 06 11 00 00 0B 86 00 9A 65. Note that neither the start byte, the length byte, the CRC, or its complement are included in the length of the packet.

While the main board is transmitting, the motor driver will be transmitting 00. However, on the last byte (the complement of the CRC), the motor driver will respond with 0F. Thus, for the previous example command, the motor driver will respond with 00 00 00 00 00 00 00 00 00 0F.

Transmission from the motor driver to the main board

The motor driver starts a transmission by transmitting a non-zero value during the second byte of the idle pattern. This byte is the length of the packet the motor driver intends to transmit. The packet is followed by a CRC8 computed with polynomial 0x01 and a null byte, both of which are not included in the length of the packet.

The main board transmits 00 during the packet and 0F during the final null byte.

Interrupted transmission

Sometimes the motor driver will interrupt a transmission from the main board. To do this, it transmits FF at any point during the main board's transmission. The main board returns to transmitting the idle pattern, at which point the motor driver is free to begin transmitting.

Commands and responses

In this section I will try to describe all of the commands, responses, and error messages I have encountered.

Known commands

Bytes (start byte, length, and CRC omitted) Description
11 00 00 0B 86 00 Stop motor
11 01 74 00 00 80 Test the inverter by driving one of the coils only
11 xx xx 02 54 00 Run the motor in reverse. x is the speed, given as a negative two's complement value, MSB first
11 xx xx 01 2A 00 Run the motor forwards. x is the speed, MSB first
44 8r dd dd dd dd dd dd dd dd Write configuration register r. Each register has 8 bytes of data (d). A total of 16 configuration registers are known, but their functions are not known. See "Configuring the motor driver"

Unknown commands

Bytes (start byte, length, and CRC omitted) Notes
33 ff ff Query error or status message?
Transmitting this followed immediately by the "stop motor" command produces the response 88 80 00 00 14 00 00
55 In the original setup, this was transmitted about once per second.

Status message

The motor driver can be configured to transmit a status message roughly three times per second. The status message takes the form 82 xx xx yy yy with the start, length, and CRC bytes omitted. X is the speed of the motor (MSB first) and Y is proportional to the torque or power of the motor (also MSB first). The most significant bit of the speed field is 1 when the motor has reached its target speed. The torque/power field can be seen to increase when the motor is loaded.

Configuring the motor driver

When the main board starts up, it transmits the following block of messages to the controller (again, with start byte, length, and CRC omitted):

44 80 00 7c 3e d5 03 7e 3e d5
44 81 01 7e 56 7c 18 70 00 30
44 82 27 a1 01 fb 71 00 0c 63
44 83 0c 64 09 99 0a 3b 09 f6
44 84 08 88 63 8d 72 eb 63 11
44 85 5b 24 18 31 01 4b 6d 8c
44 86 0b df 03 c7 0c cd 50 00
44 87 4b c9 79 b9 73 45 32 73
44 88 40 dd 79 14 7b f6 00 05
44 89 01 6c 7f f0 00 03 00 5a
44 8a 00 46 03 e8 00 05 01 6c
44 8b 7c 71 4c be 00 02 00 0f
44 8c 00 05 30 b8 ea 60 5d c0
44 8d ff ff 00 22 ff ff ff ff
44 8e ff ff ff ff ff ff ff ff
44 8f ff ff ff ff a0 86 00 95

This block of 16 messages programs the 16 8-byte configuration registers in the motor driver board. I do not know what each of the registers does.

Miscellaneous messages

Bytes (start byte, length, and CRC omitted) Notes
BB 20 00 Produced when the motor driver turns off the relay through which the VFD is powered. When power is disconnected from the motor driver, the main capacitors will slowly discharge. When they are partially discharged, the VFD is powered off but the control circuit will continue running for a little while.
BB 04 00 Produced when the motor driver enters a lockout mode (see Results section).
BB 24 00 Produced when the relay is turned off and the motor driver is in lockout mode. This suggests that messages beginning with BB are actually some kind of status bitmask. The other bits in the bitmask are unknown.
CC 4D 30 42 30 30 31 31 35 Transmitted once per second before the motor driver is configured (as described in Configuring the motor driver).
88 xx xx uu vv yy zz Produced at several occasions to indicate the status of the drum. xx xx indicates the current speed and is interpreted like the speed field in the status message, as explained above. I do not know the interpretations for U, V, Y, and Z. Their values seem to vary based on whether the motor is currently at rest, accelerating, or braking.

Results

When testing the motor driver with the Arduino, the motor driver would occasionally lock up, sometimes in response to an invalid command, but sometimes just randomly, and would unlock only after some time. Power-cycling the motor driver did not unlock the driver. When this occurred, the motor driver would transmit BB 04 00. Since the main board of the washing machine is not working, I cannot determine which commands would have been used to unlock the motor or what error the main board would display in the event that this happens. I also do not know it the motor driver is fully functional or not, and I was not able to find any documentation for either the motor driver as a whole, or the control chip on the board.

Comments

Popular posts from this blog

Improving and calibrating the capacitive water sensor

Controlling a ceiling fan and light with an Arduino

Turn a buck converter module into a buck-boost converter with only two components