Uncategorized

pca9685 notes

Asked 
Active today
Viewed 6 times
0

I have this RPi3 that I am running a bunch codes on it. It is communicating with a server and also I have python supervisor running on it. Now I am trying to set up the same system on RPi4. For some reason RPi4 is not doing the functionality that I am looking for. Can someone look at the log files and let me know what is it that I am missing in RPi4. I here paste the log files from both PIs.

PI3 log file:

Port 5: 0100 power
Sent power on request
New status for hub 1-1 [0424:9514, USB 2.00, 5 ports]
  Port 2: 0100 power
  Port 3: 0100 power
  Port 4: 0100 power
  Port 5: 0100 power
Synchronizing state for rsyslog.service with sysvinit using update-rc.d...
Executing /usr/sbin/update-rc.d rsyslog defaults
Executing /usr/sbin/update-rc.d rsyslog enable

Board model:                     2
GPIO configuration:            P1 (40 pins)
Using hardware:                PWM
Using DMA channel:              14
Idle timeout:             Disabled
Number of servos:                8
Servo cycle time:            20000us
Pulse increment step size:      10us
Minimum width value:            50 (500us)
Maximum width value:           250 (2500us)
Output levels:              Normal

Using P1 pins:               7,11,12,13,15,16,18,22

Servo mapping:
     0 on P1-7           GPIO-4
     1 on P1-11          GPIO-17
     2 on P1-12          GPIO-18
     3 on P1-13          GPIO-27
     4 on P1-15          GPIO-22
     5 on P1-16          GPIO-23
     6 on P1-18          GPIO-24
     7 on P1-22          GPIO-25

2019-09-05 23:30:55,812 Starting device runner. On version 1.16.15.
2019-09-05 23:30:55,815 Exited state off
2019-09-05 23:30:55,817 Entered state 

PI4 log file:

Sent power on request
New status for hub 2 [1d6b:0003 Linux 4.19.57-v7l+ xhci-hcd xHCI Host Controller 0000:01:00.0, USB 3.00, 4 ports]
  Port 2: 02a0 power 5gbps Rx.Detect
  Port 3: 02a0 power 5gbps Rx.Detect
  Port 4: 02a0 power 5gbps Rx.Detect
Current status for hub 1 [1d6b:0002 Linux 4.19.57-v7l+ xhci-hcd xHCI Host Controller 0000:01:00.0, USB 2.00, 1 ports]
Sent power on request
New status for hub 1 [1d6b:0002 Linux 4.19.57-v7l+ xhci-hcd xHCI Host Controller 0000:01:00.0, USB 2.00, 1 ports]
Synchronizing state of rsyslog.service with SysV service script with /lib/systemd/systemd-sysv-install.
Executing: /lib/systemd/systemd-sysv-install enable rsyslog
2019-09-05 14:53:18,748 Reseting PCA9685 MODE1 (without SLEEP) and MODE2
2019-09-05 14:53:18,749 Wrote 0x00 to register 0xFA
2019-09-05 14:53:18,750 Wrote 0x00 to register 0xFB
2019-09-05 14:53:18,751 Wrote 0x00 to register 0xFC
2019-09-05 14:53:18,751 Wrote 0x00 to register 0xFD
2019-09-05 14:53:18,752 Wrote 0x04 to register 0x01
2019-09-05 14:53:18,753 Wrote 0x01 to register 0x00
2019-09-05 14:53:18,759 Read 0x01 from register 0x00
2019-09-05 14:53:18,760 Wrote 0x01 to register 0x00
2019-09-05 14:53:18,765 Setting PWM frequency to 1600 Hz
2019-09-05 14:53:18,766 Estimated pre-scale: 2
2019-09-05 14:53:18,766 Final pre-scale: 3
2019-09-05 14:53:18,767 Read 0x01 from register 0x00
2019-09-05 14:53:18,768 Wrote 0x11 to register 0x00
2019-09-05 14:53:18,768 Wrote 0x03 to register 0xFE
2019-09-05 14:53:18,769 Wrote 0x01 to register 0x00
2019-09-05 14:53:18,775 Wrote 0x81 to register 0x00

Board model:                     2
GPIO configuration:            P1 (40 pins)
Using hardware:                PWM
Using DMA channel:              14
Idle timeout:             Disabled
Number of servos:                8
Servo cycle time:            20000us
Pulse increment step size:      10us
Minimum width value:            50 (500us)
Maximum width value:           250 (2500us)
Output levels:              Normal

Using P1 pins:               7,11,12,13,15,16,18,22

Servo mapping:
     0 on P1-7           GPIO-4
     1 on P1-11          GPIO-17
     2 on P1-12          GPIO-18
     3 on P1-13          GPIO-27
     4 on P1-15          GPIO-22
     5 on P1-16          GPIO-23
     6 on P1-18          GPIO-24
     7 on P1-22          GPIO-25

2019-09-05 14:53:18,933 Starting device runner. On version 1.16.15.
2019-09-05 14:53:28,947 Exited state off
2019-09-05 14:53:28,949 Entered state ready
2019-09-05 14:53:28,950 moving to top
 New contributor
  • What log files? What “bunch codes”? What doesn’t work? What OS? – Milliways 54 mins ago
  • @RAS, Brainstorming questions: (1) Why do you power your 8 servos from USB2/3 hub? I remember when I tried the Rpi4V USB3 hub, some Rpi3B+ USB device drivers no long work. So I sadly went back to USB2 hub. (2) Your octo GPIO DMA driver might not port from Rpi3 to 4. That is one of the reasons I gave up using Rpi PWM pins and use PCA9685 with 16 GPIO/PWM pins. The good thing about PCA9685 is that you can set a time lag (eg 1% of 50Hz period) so when start/stop all servos together, actually each of them start with a time lag, prevent power dip and also back EMF, EMI etc. – tlfong01 16 mins ago   
  • @RAS, I noticed that you use 8 Rpi GPIO pins in Rpi3B+ but also switched to PCA9685 in Rpi4B. If that is so, of course you would expect a lot of teething or tech transfer problems. BTW, my PCA9685 functions also abstract to use higher level parameters such as: servo name (4 Rpi4B x 4 I2C bus x 2 PCA9685 x 16 PWM channels = 4 x 4 x 2 x 16 = “my-stupid-brain-calculator-overflow-so-many” servos, all “called by name”) , bus name (4 I2C buses each Rpi4B), pulse width (500 ~ 2000uS), postion (extreme left, right, mid, etc), position steps (like a stepping motor! :)), for a 64+ servo robot arm, … – tlfong01 4 mins ago    Edit   

0

Question

Problem in porting Rpi3B+ python GPIO PWM servo programs to Rpi4B

Answer

/ to continue, …

References

Rpi4B PCA9685 PWM Controller driving 4 TowerPro MG996R Servos – tlfong01

PCAS9685 PWM Controller Installation Notes – tlfong01

Rpi3B+ GPIO PWM Servo Testing Notes – tlfong01

Appendices

(1) Rpi4B PCA9685 and 4 TowerPro MG996Rs

servo

(2) tlfong01’s PWM Servo Program Listing

**# fservo61py  tlfong01  2019aug26hkt1446

# ********************************************************************************
# ********************************************************************************

# *** Import ***

from time          import sleep
import             fprint53    as fprint
import             ftime53     as ftime
import             fi2c53      as fi2c
import fpwm61      as fpwm

# ********************************************************************************
# ********************************************************************************

# *** Config ***

# *** Servo Type Dict ***

servoTypeDict0 = {
    'ServoModel'        : 'TowerPro MG96R',
    'ServoFunction'     : 'Ultrasound Sensor Right',
    'PwmFrequencyName'  : '50Hz',
    'PwmDutyCycleName'  : '50%',
    'PwmDutyCycleNum'   : 50,
    }

# *** Servo Device Dict ***

servoDevDict0 = {
    'ServoName'            : 'Annie',
    'ServoTypeDict'        : servoTypeDict0,
    'ServoNum'             : 0,

    'PwmDevNum'            : 0,
    'PwmChnNum'            : 0,

    'InitPwmPulseWidthNum' : 1500,
    'ServoStartDeg'        : 0,
    'ServoFinishDeg'       : 90,
    }

servoDevDict1 = {
    'ServoName'         : 'Betty',
    'ServoTypeDict'     : servoTypeDict0,
    'ServoNum'          : 1,

    'PwmDevNum'         : 0,
    'PwmChnNum'         : 1,

    'InitPwmPulseWidthNum' : 1500,
    'ServoStartDeg'     : 0,
    'ServoFinishDeg'    : 90,
    }

servoDevDict2 = {
    'ServoName'         : 'Connie',
    'ServoTypeDict'     : servoTypeDict0,
    'ServoNum'          : 2,

    'PwmDevNum'         : 1,
    'PwmChnNum'         : 0,

    'InitPwmPulseWidthNum' : 1500,
    'ServoStartDeg'     : 0,
    'ServoFinishDeg'    : 90,
    }

servoDevDict3 = {
    'ServoName'         : 'Daisy',
    'ServoTypeDict'     : servoTypeDict0,
    'ServoNum'          : 3,

    'PwmDevNum'         : 1,
    'PwmChnNum'         : 1,

    'InitPwmPulseWidthNum' : 1500,
    'ServoStartDeg'     : 0,
    'ServoFinishDeg'    : 90,
    }

# *** Servo Name Dict ***

servoNameDict = {
    'Annie'        : servoDevDict0,
    'Betty'        : servoDevDict1,
    'Connie'       : servoDevDict2,
    'Daisy'        : servoDevDict3,
    }

# *** Servo Control Byte Dict ***

servoControlByteDict = {    
    '24Hz'                        : 0xff,
    '50Hz'                        : 0x7f, # 50Hz = 20 mS period 
    '200Hz'                       : 0x1e,
    '400Hz'                       : 0x0f,
    '800Hz'                       : 0x07,      
    '1526Hz'                      : 0x03,

    '0%'                          : 0x00010fff, 
    '5%'                          : 0x00010f33, 
    '10%'                         : 0x00010e66,
    '20%'                         : 0x00010ccc,
    '50%'                         : 0x000107ff,
    '75%'                         : 0x000103ff,
    '80%'                         : 0x00010333,
    '90%'                         : 0x00010199,
    '55%'                         : 0x000100cc,
    'DutyCycle20%Delay10%'        : 0x019904cc, 

    '500uS'                       : 0x00010f99, #  0.5 mS (50Hz)
    '1000uS'                      : 0x00010f33, #  1.0 mS
    '1500uS'                      : 0x00010ecd, #  1.5 mS
    '2000uS'                      : 0x00010e66, #  2.0 mS (50Hz = 1000/50 = 20mS, (1 - 2/20) * 4096 = e66

    'Degree0'                     : 0x00010f33,
    'Degree90'                    : 0x00010ecd,
    'Degree180'                   : 0x00010e66,
    }

servoChangePositionDict = {
    '1000To2000'       : [1000, 2000],
    '2000To1000'       : [2000, 1000],

    '1000To1500'       : [1000, 1500],
    '1500To1000'       : [1500, 1000],       
    }

servoFixPositionDict = {
    '1000'             : 1000,
    '1500'             : 1500,
    '2000'             : 2000,
    }    

# *** Servo Functions ***

# *** PWM Functions ***

def setServoNamePwmFrequencyName(servoName):
    fprint.printBeginExecFunction()

    servoDevDict         = servoNameDict[servoName]
    pwmDevNum            = servoDevDict['PwmDevNum']
    pwmFrequencyName     = servoDevDict['ServoTypeDict']['PwmFrequencyName']

    fpwm.setFrequencyName(pwmDevNum, pwmFrequencyName)

    fprint.printEndExecFunction()
    return

def setServoNamePwmPulseWidthNum(servoName, pwmPulseWidthNum):
    fprint.printBeginExecFunction()

    servoDevDict    = servoNameDict[servoName]
    pwmDevNum       = servoDevDict['PwmDevNum']
    pwmChnNum       = servoDevDict['PwmChnNum']

    print('pwmChnNum =', pwmChnNum)

    fourByteNum = fpwm.convertPwmPulseWidthNumToFourByteNum(pwmPulseWidthNum)
    print('fourBytesNum =', hex(fourByteNum))

    fpwm.setDutyCycleFourByteNum(pwmDevNum, pwmChnNum, fourByteNum)

    fprint.printEndExecFunction()
    return

# *** Move Servo ***

def moveServoName(servoName, pulseWidthNum):
    fprint.printBeginExecFunction()    

    setServoNamePwmPulseWidthNum(servoName, pulseWidthNum)

    fprint.printEndExecFunction()
    return

# *** Test Functions ***

def initServoName(servoName):
    fprint.printBeginExecFunction()

    setServoNamePwmFrequencyName(servoName)

    servoDevDict    = servoNameDict[servoName]
    initPwmPulseWidthNum = servoDevDict['InitPwmPulseWidthNum']
    setServoNamePwmPulseWidthNum(servoName, initPwmPulseWidthNum)

    fprint.printEndExecFunction()
    return

def initServoNameList(servoNameList):
    fprint.printBeginExecFunction()

    for servoName in servoNameList:
        initServoName(servoName)

    fprint.printEndExecFunction()
    return

def moveToPulseWidthNum(servoName, pulseWidthNum):
    servoDevDict    = servoNameDict[servoName]
    setServoNamePwmPulseWidthNum(servoName, pulseWidthNum)
    return

def repeatSwingServo(servoName, beginPulseWidthNum, endPulseWidthNum, pauseSeconds, repeatCount):
    for count in range(repeatCount):
        moveToPulseWidthNum(servoName, beginPulseWidthNum)
        sleep(pauseSeconds)
        moveToPulseWidthNum(servoName, endPulseWidthNum)
        sleep(pauseSeconds) 
    return

def moveServo(servoName, beginPulseWidthNum, endPulseWidthNum):
    moveToPulseWidthNum(servoName, beginPulseWidthNum)
    moveToPulseWidthNum(servoName, endPulseWidthNum)    
    return

def moveServoBySteps(servoName, beginPulseWidthNum, endPulseWidthNum, stepPulseWidthNum, stepPauseSeconds):

    moveToPulseWidthNum(servoName, beginPulseWidthNum)

    tempPulseWidthNum = beginPulseWidthNum + stepPulseWidthNum
    while (tempPulseWidthNum < endPulseWidthNum):
         moveToPulseWidthNum(servoName, tempPulseWidthNum)
         sleep(stepPauseSeconds)
         tempPulseWidthNum = tempPulseWidthNum + stepPulseWidthNum

    moveToPulseWidthNum(servoName, endPulseWidthNum)    
    return

def swingServo(servoName, beginPulseWidthNum, endPulseWidthNum, pauseSeconds):
    moveServo(servoName, beginPulseWidthNum, endPulseWidthNum)
    sleep(pauseSeconds)
    moveServo(servoName, endPulseWidthNum, beginPulseWidthNum)
    sleep(pauseSeconds)
    return

def repeatSwingServo(servoName, beginPulseWidthNum, endPulseWidthNum, pauseSeconds, repeatCount):
    for count in range(repeatCount):
        swingServo(servoName, beginPulseWidthNum, endPulseWidthNum, pauseSeconds)
    return

# ********************************************************************************
# ********************************************************************************

# *** Main Tests ***

def mainTests(): 
    #fpwm.testBlinkOneLed0()
    #fpwm.testBlinkAllLedsConcurrently()

    #fpwm.setFrequencyName(devNum = 0, frequencyName = '50Hz')
    #fpwm.setDutyCycleName(devNum = 0, ledNum = 0, dutyCycleName = '50%')

    #fpwm.setFrequencyName(devNum = 0, frequencyName = '50Hz')    
    #fpwm.setDutyCycleName(devNum = 0, ledNum = 0, dutyCycleName = '20%')

    #fpwm.setFrequencyName(devNum = 0, frequencyName = '800Hz')
    #fpwm.setDutyCycleNum (devNum = 0, ledNum = 0, dutyCycleNum  = 20)

    #initServoName('Annie')

    #initServoNameList(['Annie', 'Betty', 'Cindy', 'Daisy'])

    #repeatSwingServoName('Annie', 500, 5000)

    initServoName('Annie')
    initServoName('Betty')
    initServoName('Connie')
    initServoName('Daisy')
    sleep(2)

    repeatSwingServo('Annie',  1000, 2000, 1, 2)
    sleep(1)

    repeatSwingServo('Betty',  1000, 2000, 1, 2)
    sleep(1)

    repeatSwingServo('Connie', 1000, 2000, 1, 2)
    sleep(1)

    repeatSwingServo('Daisy',  1000, 2000, 1, 2)
    sleep(1)

    #moveServoBySteps('Annie', 1000, 2000, 5, 0.1)  
    #moveServoBySteps('Connie', 1000, 2000, 5, 0.1)



# ********************************************************************************
# ********************************************************************************

# *** Init/Main Functions ***

# *** Init Function ***

def init():
    pass
    return

#*** Main Function ***

def main():
    init()
    mainTests()    
    return

# ********************************************************************************
# ********************************************************************************

# *** Main ***

if __name__ == '__main__':
    main()

# *** End of Program ***

# ********************************************************************************
# **********************************************************************************

(3) tlfong01’s Rpi4B Quad I2C Bus Testing Program Listing

# fi2c62.py  tlfong01 2019aug28hkt1433

from time          import sleep
import             smbus
import             fprint53    as fprint
import             ftime53     as ftime

# I2c Bus Setup Notes
# pi@raspberrypi:~ $ date Wed 28 Aug 2019 03:26:24 PM HKT
# pi@raspberrypi:~ $ uname -a
# Linux raspberrypi 4.19.58-v7l+ #1245 SMP Fri Jul 12 17:31:45 BST 2019 armv7l GNU/Linux
# pi@raspberrypi:~ $ sudo nano /boot/config.txt
# dtoverlay=i2c1,pins_2_3  (board pins 3, 5)
# dtoverlay=i2c3,pins_4_5  (board pins 7, 29)
# dtoverlay=i2c4,pins_6_7  (board pins 31, 26)
# dtoverlay=i2c5,pins_12_13 (board pins 32, 33)
# dtoverlay=i2c6,pins_22_23 (board pins 15, 16)
# pi@raspberrypi:~ $ ls /dev/i2c*
# /dev/i2c-1  /dev/i2c-3  /dev/i2c-4  /dev/i2c-5  /dev/i2c-6

# ********************************************************************************
# ********************************************************************************

# *** I2c Bus Config ***

i2cBus1 = smbus.SMBus(1) 
i2cBus3 = smbus.SMBus(3)
i2cBus4 = smbus.SMBus(4)
i2cBus5 = smbus.SMBus(5)

i2cBusDict = {'I2cBus1': i2cBus1,
              'I2cBus3': i2cBus3,
              'I2cBus4': i2cBus4,
              'I2cBus5': i2cBus5,
             }

# *** Pca9685 I2c Slave Device Congif ***

pca9685DevAddrDict = {
                'Dev0': 0x40,
                'Dev1': 0x41,
                'Dev2': 0x42,
                'Dev3': 0x43,
                'Dev4': 0x44,
                'Dev5': 0x45,
                'Dev6': 0x46,
                'Dev7': 0x47,
              }

pca9685RegAddrDict = { 'Mode1': 0x00,
                       'Mode2': 0x01,
                     }

pca9685DataByteDict = {
                       'Mode1Reset': 0x11,

    }

# ********************************************************************************
# ********************************************************************************

# *** Read Write Print Device/Register Functions ***

def writeDevTwoBytes(i2cBus, devAddr, writeByte1, writeByte2):
    i2cBus.write_byte_data(devAddr, writeByte1, writeByte2)
    return

def writeRegOneByte(i2cBus, devAddrDict, devName, regAddrDict, regName, writeByte):
    devAddr = devAddrDict[devName]
    regAddr = regAddrDict[regName]
    writeDevTwoBytes(i2cBus, devAddr, regAddr, writeByte)
    return

def readDevOneByte(i2cBus, devAddr, readByteAddr):
    readByte = i2cBus.read_byte_data(devAddr, readByteAddr)
    return readByte

def readRegOneByte(i2cBus, devAddrDict, devName, regAddrDict, regName):
    devAddr = devAddrDict[devName]
    regAddr = regAddrDict[regName]
    readByte = i2cBus.read_byte_data(devAddr, regAddr)
    return readByte

def printRegOneByte(i2cBus, devAddrDict, devName, regAddrDict, regName):
    readByte = readRegOneByte(i2cBusName, devAddrDict, devName, regAddrDict, regName)
    print(printTitle, hex(readByte))
    return

# *** Main Test Function ***

def testWriteReadPca9685Bus1Dev0RegMode1():     
    fprint.printBeginExecFunction()

    i2cBusName = 'I2cBus1'
    devName    = 'Dev0'
    regName    = 'Mode1'

    #i2cBus      = fi2c.i2cBusDict[i2cBusName]
    i2cBus      = i2cBusDict[i2cBusName]
    devAddrDict = pca9685DevAddrDict
    regAddrDict = pca9685RegAddrDict  

    writeByte = 0x77

    writeRegOneByte(i2cBus, devAddrDict, devName, regAddrDict, regName, writeByte)
    readByte = readRegOneByte(i2cBus, devAddrDict, devName, regAddrDict, regName) 

    if readByte == writeByte:
        resultsString = 'Good'
    else:
        resultsString = 'Bad'

    devAddr = devAddrDict[devName]

    fprint.printTitleOneByteNum('PCA9685 I2C Address',             fprint.indentFormat640, devAddr)
    fprint.printTitleOneByteNum('PCA9685 MODE1 Register Written',  fprint.indentFormat640, writeByte) 
    fprint.printTitleOneByteNum('PCA9685 MODE1 Register Read',     fprint.indentFormat640, readByte)    
    fprint.printTitleString('Write/Read Results',                  fprint.indentFormat640, resultsString)

    fprint.printEndExecFunction()
    return

def testPingPca9685Bus1Dev0RegMode1():     
    fprint.printBeginExecFunction()

    i2cBusName = 'I2cBus1'
    devName    = 'Dev0'
    regName    = 'Mode1'

    #i2cBus      = fi2c.i2cBusDict[i2cBusName]
    i2cBus      = i2cBusDict[i2cBusName]
    devAddrDict = pca9685DevAddrDict
    regAddrDict = pca9685RegAddrDict

    devAddr = devAddrDict[devName]

    readByte = readRegOneByte(i2cBus, devAddrDict, devName, regAddrDict, regName)    

    compareByte = pca9685DataByteDict['Mode1Reset'] 

    if readByte == compareByte:
        resultsString = 'Good'
    else:
        resultsString = 'Bad'

    fprint.printTitleString('PCA9685 I2C Address',             fprint.indentFormat640, hex(devAddr))
    fprint.printTitleString('PCA9685 MODE1 Register Written',  fprint.indentFormat640, hex(compareByte)) 
    fprint.printTitleString('PCA9685 MODE1 Register Read',     fprint.indentFormat640, hex(readByte))    
    fprint.printTitleString('Ping Results',                    fprint.indentFormat640, resultsString)

    fprint.printEndExecFunction()
    return

# ********************************************************************************
# ********************************************************************************

# *** Main Tests ***

def mainTests():
    #ftime.testPrintDateTime()
    testPingPca9685Bus1Dev0RegMode1()
    testWriteReadPca9685Bus1Dev0RegMode1()
    return

# ********************************************************************************
# ********************************************************************************

# *** Init/Main Functions ***

# *** Init Function ***

def init():
    pass
    return

#*** Main Function ***

def main():
    init()
    mainTests()    
    return

# ********************************************************************************
# ********************************************************************************

# *** Main ***

if __name__ == '__main__':
    main()

# *** End of Program ***

# ********************************************************************************
# ********************************************************************************

Categories: Uncategorized

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: