CircuitPython

The examples in this guide are no longer supported. Check out the PCA9685 guide if you're using the breakout: https://learn.adafruit.com/16-channel-pwm-servo-driver or the FeatherWing guide if you're using the Wing: https://learn.adafruit.com/adafruit-stepper-dc-motor-featherwing/circuitpython
This guide is for version 3.0.0 of the PCA9685 library. Make sure to use a bundle from 20180110 or later.

Adafruit CircuitPython Module Install

To use the PCA9685 with your Adafruit CircuitPython board you'll need to install the Adafruit_CircuitPython_PCA9685 module on your board. Remember this module is for Adafruit CircuitPython firmware and not MicroPython.org firmware!

First make sure you are running the latest version of Adafruit CircuitPython for your board.  Next you'll need to install the necessary libraries to use the hardware--read below and carefully follow the referenced steps to find and install these libraries from Adafruit's CircuitPython library bundle (version 20180110 or later). 

Bundle Install

For express boards that have extra flash storage, like the Feather/Metro M0 express and Circuit Playground express, you can easily install the necessary libraries with Adafruit's CircuitPython bundle.  This is an all-in-one package that includes the necessary libraries to use the PCA9685 and motors with CircuitPython.  To install the bundle follow the steps in your board's guide, like these steps for the Feather M0 express board.

Remember for non-express boards like the Trinket M0, Gemma M0, and Feather/Metro M0 basic you'll need to manually install the necessary libraries from the bundle:

  • adafruit_pca9685
  • adafruit_bus_device
  • adafruit_register
  • adafruit_motor

If your board supports USB mass storage, like the M0-based boards, then simply drag the files to the board's file system. Note on boards without external SPI flash, like a Feather M0 or Trinket/Gemma M0, you might run into issues on Mac OSX with hidden files taking up too much space when drag and drop copying, see this page for a workaround.

If your board doesn't support USB mass storage, like the ESP8266, then use a tool like ampy to copy the file to the board. You can use the latest version of ampy and its new directory copy command to easily move module directories to the board.

Before continuing make sure your board's lib folder or root filesystem has the adafruit_pca9685adafruit_bus_device, adafruit_motor, and adafruit_register folders/modules copied over.

Usage

The following section will show how to control the PCA9685 from the board's Python prompt / REPL.  You'll learn how to interactively control DC Motors and Steppers by typing in the code below. 

First connect to the board's serial REPL so you are at the CircuitPython >>> prompt.

I2C Initialization

First you'll need to initialize the I2C bus for your board. First import the necessary modules:

Download: file
import board
import busio

Now run this command to create the I2C instance using the default SCL and SDA pins (which will be marked on the boards pins if using a Feather or similar Adafruit board):

Download: file
i2c = busio.I2C(board.SCL, board.SDA)

DC Motors

After initializing the I2C interface you need to import and initialize the PCA9685 class to use it in your own code. We'll use it as our PWM source.

We provide the I2C address here explicitly because the Adafruit Motor FeatherWing adjusts its default address to 0x60 so it doesn't conflict with the Adafruit Servo FeatherWing.

Setting the frequency to 1600 helps smooth the motor control.

Download: file
import adafruit_pca9685
pca = adafruit_pca9685.PCA9685(i2c, address=0x60)
pca.frequency = 1600

Next, we'll import and initialize the DCMotor class from adafruit_motor. This class uses the pwm channels to control the throttle of the motor. Think of it as the gas pedal from a car.

To control the motor, DCMotor needs two PWM channels, one for each wire from the motor. These should never be connected directly to PCA9685 or microcontroller because DCMotors use lots of current. Instead, use a motor driver chip, such as the TB6612, to connect to the motor. The Motor FeatherWing has these built in. This chip is a little weird because it provides a third PWM pin marked PWMX in addition to XIN1 and XIN2. They make this available in case the controller can only PWM on a single pin. Since we can PWM two pins, we hold PWMX high.

Keeping track of which three channels of the PCA9685 to use can be tricky. If you are using the FeatherWing use the MotorFeatherWing class in the Adafruit CircuitPython FeatherWing library to make your life easier. If not, here is the convention for many motor related shields:

  • Motor 1 is channels 10 and 9 with 8 held high.
  • Motor 2 is channels 11 and 12 with 13 held high.
  • Motor 3 is channels 4 and 3 with 2 held high.
  • Motor 4 is channels 5 and 6 with 7 held high.

We'll use motor 1 in our example:

Download: file
from adafruit_motor import motor
pwm_channel = pca.channels[8]
channel1 = pca.channels[10]
channel2 = pca.channels[9]

pwm_channel.duty_cycle = 0xffff # hold high
motor1 = motor.DCMotor(channel1, channel2)

Note: For small DC motors like sold in the shop you might run into problems with electrical noise they generate and erratic behavior on your board.  The SAMD21 Feather M0 boards in particular have been susceptible to this issue.  If you see erratic behavior like the motor not spinning or the board resetting at high motor speeds this is likely the problem. See this motor guide FAQ page for information on capacitors you can solder to the motor to reduce noise.

Now to move a motor you can set the throttle attribute. We don't call it speed because it doesn't correlate to a particular number of revolutions per minute (RPM). RPM depends on the motor and the voltage which is unknown.

For example to drive motor M1 forward at a full speed you set it to 1.0:

Download: file
motor1.throttle = 1.0

To run the motor at half throttle forward use a decimal:

Download: file
motor1.throttle = 0.5

Or to reverse the direction use a negative throttle:

Download: file
motor1.throttle = -0.5

You can stop the motor with a throttle of zero:

Download: file
motor1.throttle = 0

To let the motor coast and then spin freely set throttle to None.

Download: file
motor1.throttle = None

That's all there is to controlling DC motors with CircuitPython!  With DC motors you can build fun moving projects like robots or remote controlled cars that glide around with ease.

Stepper Motors

To control stepper motors you'll need to import the stepper module from adafruit_motor and create an instance of the Stepper class inside of it. Unipolar and Bipolar stepper motors function by PWMing four wires in a particular sequence.

Like DCMotors, stepper motors use a lot of current to function and therefore also need a driver chip. Again, we'll need to hold the pwm pins high for each pair of control wires.

Keeping track of which six channels of the PCA9685 to use can be tricky. If you are using the FeatherWing use the MotorFeatherWing class in the Adafruit CircuitPython FeatherWing library to make your life easier. If not, the convention for many stepper related shields is:

  • Stepper 1 is a combination of Motor 1 and Motor 2 as above.
  • Stepper 2 is a combination of Motor 3 and Motor 4 as above.
Download: file
from adafruit_motor import stepper
# First part of Stepper 1 is Motor 1 above.
pwma = pca.channels[8]
ain1 = pca.channels[10]
ain2 = pca.channels[9]
# Second part of Stepper 1 is Motor 2 above.
pwmb = pca.channels[13]
bin1 = pca.channels[11]
bin2 = pca.channels[12]
stepper1 = stepper.Stepper(ain1, ain2, bin1, bin2)

# Hold PWM pins high for TB6612 driver
pwma.duty_cycle = 0xffff
pwmb.duty_cycle = 0xffff

Now you can call the onestep function to move the stepper one 'step'.  This function takes two keyword arguments:

  • Direction, this should be the constant value stepper.FORWARD or stepper.BACKWARD.
  • Style, this should be one of the values:
    • stepper.SINGLE for a full step rotation to a position where one single coil is powered
    • stepper.DOUBLE for a full step rotation to position where two coils are powered providing more torque
    • stepper.INTERLEAVED for a half step rotation interleaving single and double coil positions and torque
    • stepper.MICROSTEP for a microstep rotation to a position where two coils are partially active.

A single coil forward step is default:

Download: file
stepper1.onestep()

The function returns the current step 'position' in microsteps which can be handy to understand how far the stepper has moved, or you can ignore the result.

To take a double-coil step backward call:

Download: file
stepper1.onestep(direction=stepper.BACKWARD, style=stepper.DOUBLE)

You can even use a loop to continuously call onestep and move the stepper, for example a loop of 200 microsteps forward for smooth movement:

Download: file
for i in range(200):
    stepper1.onestep(style=stepper.MICROSTEP)

That's all there is to controlling a stepper motor from CircuitPython!  Steppers are handy motors for when you need smooth or precise control of something--for example 3D printers and CNC machines use steppers to precisely move tools around surfaces.

This guide was first published on Oct 28, 2016. It was last updated on Oct 28, 2016.
This page (CircuitPython) was last updated on Jun 03, 2020.