Using Adafruit "FeatherWing" board (PCA9685 + 2x TB6612) to drive stepper motor

Hemi345

Senior Member
The code snippet below is the early stages of driving a stepper motor to wind/unwind a sun shade inside my greenhouse/coldframe project. It was written to background receive a serial transmission from the main board to tell the 18M2 what to do. The stepper motor is connected to ports "M3" and "M4" on Adafruit's FeatherWing DC/Stepper board.

Code:
#PICAXE 18m2
#no_data
#terminal 38400
setfreq m32

'CONSTANTS (c)
symbol cPCA9685    = %11000000
symbol cBaseAddr= 6        'first LEDx register (LED0_ON_L); 4 registers per LED
symbol cPWM        = 2048    'half speed (higher the number, the slower the speed)
symbol cFullOn    = 4096    'full on
symbol cSteps    = 400    'one turn using half stepping
symbol cPause    = 50    'amount of time inbetween steps

'VARIABLES (b=bit,v=byte,w=word)
symbol bA1        = bit0
symbol bA2        = bit1
symbol bB1        = bit2
symbol bB2        = bit3
symbol vPhases    = b0        'bB2,bB1,bA2,bA1
symbol vPause    = b1        'amount of time inbetween steps
symbol vCurPos    = b2        'current position of stepper motor

symbol vDir        = b6        'direction to run stepper motor
symbol vNextStep= b7

symbol vPin        = b9        'port connected to PWM pin on TB6612

symbol vPosRx    = b11        'position of the sun shade, (1=open,2=closed)
symbol vNewaddr    = b12        'register on PCA9685 to change

symbol wPwmVal0        = w7     '(b14,b15)
symbol vPwmVal0L    = b14    'low byte
symbol vPwmVal0M    = b15    'high byte

symbol wMotorRx        = w8     'b16,b17 stepper motor to work with (if there's more than one)
symbol vMotorRxCheck= b17    'high byte of wMotorRx, just to determine if valid data rx'd

symbol wSteps        = w9     'b18,b19
symbol vGenVar0        = b27    'general use variable
#rem
M3 = PWM LED2:
    A1 = LED4
    A2 = LED3  
M4 = PWM LED7:
    B2 = LED6
    B1 = LED5
M1 = PWM LED8:
    A1 = LED10
    A2 = LED9  
M2 = PWM LED13:
    B2 = LED12
    B1 = LED11
#endrem

wPwmVal0 = 1
pause 4000    'give the serial terminal time to start up

sertxd ("Author: Hemi345",13,10)
sertxd ("Program: ",ppp_filename,13,10)
sertxd ("Downloaded: ",ppp_date,13,10)
#rem various help links
'https://motion.schneider-electric.com/technology-blog/stepper-motor-basics-half-and-micro-stepping/

'https://www.adafruit.com/product/2927 - link to module w/ PCA9685 chip
#endrem

hi2csetup i2cmaster, cPCA9685, i2cfast_32, i2cbyte

hi2cin 0, (vGenVar0)
sertxd ("Mode 1a: ",#vGenVar0,13,10)
hi2cout 0, (%00100000)
#rem
bit 7:0 0 Restart enabled
bit 6:0 0 Use internal clock
bit 5:0 1 Auto increment on
bit 4:1 0 Normal Mode on (sleep disabled)
bit 3:0 0 (don't use)
bit 2:0 0 (don't use)
bit 1:0 0 (don't use)
bit 0:1 0 AllCall (do not respond)
#endrem
pause 1500               'give the device time to start the oscillator
hi2cin 0, (vGenVar0)
sertxd ("Mode 1b: ",#vGenVar0,13,10)

hi2cin 1, (vGenVar0)
sertxd ("Mode 2a: ",#vGenVar0,13,10)
hi2cout 1, (%00010100)
#rem
bit 7:0: 0 reserved
bit 6:0: 0 reserved
bit 5:0: 0 reserved
bit 4:0: 1 Logic state inverted (1), state not inverted (0)
bit 3:0: 0 LEDs change on ACK (1), change on STOP (0)
bit 2:1: 1 totem-pole (1), open-drain (0)
bit 1:0: 0 umm, what?
bit 0:0: 0 umm, what?
#endrem
pause 1500               'give the device some time
hi2cin 1, (vGenVar0)
sertxd ("Mode 2b: ",#vGenVar0,13,10)
pause 4000
init:
    wPwmVal0 = cPwm        'set PWM high value to default
    vGenVar0 = 0
    do while vGenVar0 < 4
        lookup vGenVar0,(2,7,8,13),vPin    'ports connected to PWM pins on TB6612
        gosub setPWM    'on ports LED2,LED7,LED8,LED13
        inc vGenVar0
    loop

hsersetup B9600_32, %000    'setup hardware serial Baud rate to 9600, %00 = true inverted (idle high), clear the buffer
Pause 1500
sertxd("Ready.",13,10)

main:

do
    if pinc.2 = 1 then
        gosub allOff
        reset
    end if
    wPwmVal0 = cFullOn
    vPause = 40
    wMotorRx    = $FF    'set the var to a non-valid value
    vPosRx        = $FF    'set the var to a non-valid value
    HSerIn wMotorRx        'read first byte from buffer, this will be sent as ASCII ('S' for the Shade stepper)
    HSerIn vPosRx        'read second byte from buffer, this will be sent as decimal (1,2 for the shade stepper)
    'comment out the two HSerIn lines above and uncomment "wMotorRx = "S" : vPosRx = 1" below to operate stepper manually
    'wMotorRx = "S" : vPosRx = 1 'change to 2 to run the other direction
    if vMotorRxCheck = 0 Then    'valid character received for motor, data is in the low byte of wMotorRx
        hsersetup B9600_32, %000    'clear the buffer so if something comes in while the shade is moving it can act on it later.
        pause 1500
        if wMotorRx <> $FF then 'for multiple steppers, this will identify the correct one (future use). the ASCII letter 'S' is for Shade stepper
            sertxd("Received ",wMotorRx,#vPosRx,13,10)
            sertxd("Current Position ",#vCurPos,13,10)
            if vPosRx = vCurPos then
                sertxd("Already at ",#vCurPos,13,10) 'already in position, do nothing
            else
                wSteps = 0
                if vPosRx = 1 then
                    vDir = 0
                else if vPosRx = 2 then
                    vDir = 1
                end if
                gosub stepMotor
                gosub allOff
            endif
        endif
    endif
loop
allOff:
    vPhases = 0
    gosub setPins
    sertxd("----",13,10)
    return
  
setPWM:    'sets PWM value for current going through phases; uses vPin and wPwmVal0
    vNewaddr = 4 * vPin + cBaseAddr 'jump to the LEDx_ON_L register
    sertxd("Set PWM on Pin ",#vPin," to ",#wPwmVal0,13,10)
    hi2cout vNewaddr,(0,0,vPwmVal0L,vPwmVal0M)
    return
  
setPins:    'sets state of phases on stepper motor; uses vPhases
    if bA1 = 1 then
        hi2cout 22,(vPwmVal0L,vPwmVal0M,0,0)
        'sertxd("A1=1 ")
    else
        hi2cout 22,(0,0,0,0)
        'sertxd("A1=0 ")
    end if
    'vPin = 3
    if bA2 = 1 then
        hi2cout 18,(vPwmVal0L,vPwmVal0M,0,0)
        'sertxd("A2=1 ")
    else
        hi2cout 18,(0,0,0,0)
        'sertxd("A2=0 ")
    end if
    'vPin = 5
    if bB1 = 1 then
        hi2cout 26,(vPwmVal0L,vPwmVal0M,0,0)
        'sertxd("B1=1 ")
    else
        hi2cout 26,(0,0,0,0)
        'sertxd("B1=0 ")
    end if
    'vPin = 6
    if bB2 = 1 then
        hi2cout 30,(vPwmVal0L,vPwmVal0M,0,0)
        'sertxd("B2=1 ")
    else
        hi2cout 30,(0,0,0,0)
        'sertxd("B2=0 ")
    end if
    return

#rem
M3 = PWM LED2:
    A1 = LED4
    A2 = LED3  
M4 = PWM LED7:
    B1 = LED5
    B2 = LED6

M1 = PWM LED8:
    A1 = LED10
    A2 = LED9  
M2 = PWM LED13:
    B1 = LED11
    B2 = LED12
#endrem
  
stepMotor:    'acts on wStep
        vNextStep = 1
        do while wSteps < cSteps
            if vNextStep > 8 then
                vNextStep = 1
            end if
            if vDir = 0    then     'CW
                lookup vNextStep,(0,10,8,9,1,5,4,6,2),vPhases
            else                'CCW
                lookup vNextStep,(0,2,6,4,5,1,9,8,10),vPhases
            end if
             gosub setPins
            pause vPause    'amount of time inbetween steps
            inc wSteps
            inc vNextStep
        loop
    return
 
Last edited:
Top