My previous post was about how to receive serial signal data from a (pre-bound) SPM9645 remote receiver with RPi's GPIO. Now I will show you how to control an ESC based on the received remote control data using an Adafruit 16-Channel 12-bit PWM driver. Maybe this information can be useful to you or it can save you some time. I am happy for some feedback or optimization proposals etc.

The PWM driver should be connected to the following RPi GPIO Pins (*):

  • [P1-01]  3.3V -> VCC
  • [P1-03]  I2C0_SDA -> SDA
  • [P1-05]  I2C0_SCL -> SCL
  • [P1-09]  GROUND -> GND

The SPM9645 receiver should be connected to the following RPi GPIO Pins (*):

  • [P1-17]  3.3V
  • [P1-06]  GROUND
  • [P1-10]  GPIO 15 (RXD)

Before you are able to control the PWM driver you have to make sure that I2C-support is enabled within the RPi Linux system settings. Remove the following line from your /etc/modprobe.d/raspi-blacklist.conf:

blacklist i2c-bcm2708

Add the following line to your /etc/modules:

Reboot the device to apply the changes.

ID815_MED.jpgThe python module smbus is used to control the PWM driver via the I2C interface. All I2C control functionality needed for the driver is based on two smbus functions: write_byte_data() and read_byte_data(). After you have set the PWM frequency the PWM value of each PWM-channel can simply be set with two write_byte_data() function calls.

For the I2C communication the following functions are used:

def I2C_read(reg):
    return I2CBus.read_byte_data(I2CAddress, reg)
  except IOError, err:
    print err

def I2C_write(reg, value):
    I2CBus.write_byte_data(I2CAddress, reg, value)
  except IOError, err:
    print err

Before you can send PWM pulses to the ESC you initially need to setup the PWM frequency used. The frequency defines the total length of a PWM frame and also the length of a PWM tick. The PWM_freq() function might look a bit complicated due to the fact that the current mode of the PWM chip is stored, the chip is put into sleep state and then back up again.

def PWM_freq(freq):
  MODE1 = 0x00

  prescaleval = 25000000.0
  prescaleval /= 4096.0
  prescaleval /= float(freq)
  prescale = floor(prescaleval - 0.5)

  oldmode = I2C_read(MODE1);
  I2C_write(MODE1, (oldmode & 0x7F) | 0x10)
  I2C_write(PRESCALE, int(prescale))
  I2C_write(MODE1, oldmode)
  I2C_write(MODE1, oldmode | 0x80)

Now you should be able to control the RPM of motor connected with your ESC by using the PWM_set() function. The value range depends on the chosen PWM frequency and the minimum/maximum supported PWM pulse lengths of your ESC (firmware). A higher PWM frequency can get a higher control resolution (number of steps).

Sample calculations of PWM_set() ranges:

  Minimum PWM pulse length (ESC firmware): 1400 microseconds
  Maximum PWM pulse length (ESC firmware): 2000 microseconds

  Min @ 60Hz: 1400 / (1000000.0/4096/60) = 344.06
  Max @ 60Hz: 2000 / (1000000.0/4096/60) = 491.52

  Min @ 100Hz: 1400 / (1000000.0/4096/100) = 573.44
  Max @ 100Hz: 2000 / (1000000.0/4096/100) = 819.2

  Min @ 400Hz: 1400 / (1000000.0/4096/400) = 2293.76
  Max @ 400Hz: 2000 / (1000000.0/4096/400) = 3276.8

Finally you must choose the DSMX channel to use and find out its value range. You can use the following script for this purpose. Download the script (dx6i_info.py)

 DSMX Channel Summary:
  THR : 306 - 1738 (1432)
  AIL : 316 - 1724 (1408)
  ELE : 326 - 1734 (1408)
  RUD : 318 - 1738 (1420)


Download the POC code here (dx6i_rc.py)

(Default PWM Frequency: 400Hz,  Channel: THR ~ 300-1750, ESC connected PWM-Channel: 0)

(Test Hardware: TURNIGY PLUSH 6A (original firmware) - Hacker A10-12S - Power Supply: 7.5V/20A)

! Test WITHOUT PROPELLER - please !

Have fun and stay tuned.



  • A Spektrum DX6i transmitter was used for the communication with the receiver
  • All Spekrum DX6i channel trims were set to 100%
  • The Adafruit PWM driver does not a (separate) power supply connected
  • It is not possible to use the suggested baudrate of 125000

(* of course you can use any other 3.3V or GROUND Pin)

E-mail me when people leave their comments –

You need to be a member of diydrones to add comments!

Join diydrones