Hello,
Here:
rmmod: ERROR: Module pca9685 is not currently loaded
is the output of rmmod pca9685
.
So, it seems that it was not loaded after all.
Seth
Hello,
Here:
rmmod: ERROR: Module pca9685 is not currently loaded
is the output of rmmod pca9685
.
So, it seems that it was not loaded after all.
Seth
Hello Sir,
@benedict.hewson , okay about these ideas and me trying to get them put into source to handle the ServoCape. Thank you!
Outside of that idea:
Traceback (most recent call last):
File "/home/debian/servo/./PCA_First.py", line 8, in <module>
pwm_controller = Pca9685(i2c_bus, 0b111111)
File "/home/debian/servo/PCA.py", line 20, in __init__
self.write_reg( MODE1, 1 << 5 ) # initialize MODE1 register
File "/home/debian/servo/PCA.py", line 29, in write_reg
return self.write_regs( reg, [ value ] )
File "/home/debian/servo/PCA.py", line 38, in write_regs
return self.bus.write_i2c_block_data( self.addr, reg, values )
File "/usr/local/lib/python3.9/dist-packages/smbus2/smbus2.py", line 643, in write_i2c_block_data
ioctl(self.fd, I2C_SMBUS, msg)
OSError: [Errno 16] Device or resource busy
So far, this is the error encountered from my specific source:
#!/usr/bin/python3
from smbus2 import SMBus, i2c_msg
from time import sleep
from PCA import *
i2c_bus = SMBus('/dev/bone/i2c/2')
pwm_controller = Pca9685(i2c_bus, 0b111111)
x = pwm_controller
class Pca9685:
def servo():
angle = int(input("Please type a numerical value between 0 and 180: "))
if angle >= 0 or angle <= 180:
angle = x
print ("Your angle, sir: %d " % x)
Pca9685.servo()
So far, even w/ all my changes to smbus2.py from their source and the current driver, I cannot get past errors. If you see an error that is not listed in my source, please let me know.
Also, here is the updated driver in python3 for handling random class-function-definitions.
from smbus2 import SMBus
from time import sleep
from pathlib import Path
# relevant registers
MODE1 = 0x00
MODE2 = 0x01
LED = 0x06
ALL_LED = 0xFA
PRE_SCALE = 0xFE
set_pin = Path("/sys/class/gpio/gpio68/direction")
set_pin.write_text("low")
class Pca9685:
def __init__( self, bus, addr ):
self.addr = 0b111111 | addr
self.bus = bus
self.write_reg( MODE1, 1 << 5 ) # initialize MODE1 register
sleep( 500e-6 ) # wait 500us to allow oscillator to power up
set_pin.write_text("high")
sleep(1)
def read_reg( self, reg ):
return self.read_regs( reg, 1 )[0]
def write_reg( self, reg, value ):
return self.write_regs( reg, [ value ] )
def read_regs( self, reg, count ):
assert reg in range( 0, 256 )
assert count in range( 1, 257-reg )
return self.bus.read_i2c_block_data( self.addr, reg, count )
def write_regs( self, reg, values ):
assert reg in range( 0, 256 )
return self.bus.write_i2c_block_data( self.addr, reg, values )
def get_pwm( self, output ):
assert output in range( 0, 16 )
reg = LED + 4 * output
[ on_l, on_h, off_l, off_h ] = self.read_regs( reg, 4 )
on = on_l | on_h << 8
off = off_l | off_h << 8
phase = on
duty = ( off - on ) & 0xfff
if off & 0x1000:
duty = 0
elif on & 0x1000:
duty = 4096
return ( duty, phase )
def set_pwm( self, output, duty, phase=0 ):
assert duty in range( 0, 4097 )
assert phase in range( 0, 4096 )
if output == 'all':
reg = ALL_LED
else:
assert output in range( 0, 16 )
reg = LED + 4 * output
on = phase
off = ( duty + phase ) & 0xfff
if duty == 0:
off |= 0x1000
elif duty == 4096:
on |= 0x1000
on_l = on & 0xff
on_h = on >> 8
off_l = off & 0xff
off_h = off >> 8
self.write_regs( reg, [ on_l, on_h, off_l, off_h ] )
Also…
@amf99 , thank you for your time in helping. Just a reminder, I have no PCA9685 driver installed on my machine at the time outside of the written/typed up driver by some nice person from IRC.
Seth
P.S. Also:
unlink /dev/bone/i2c/2
to test if the Compatibility Layer from GSoC was getting the way. This is not the issue so far.As far as I can tell, smbus2.py does not play friendly so far w/ the Specification/Compatibility Layer.
lrwxrwxrwx 1 root root 10 Oct 10 01:46 /dev/bone/i2c/2 -> /dev/i2c-2
Would I need a udev rule to handle /dev/bone/i2c/2
or would I need to make a new user so that /dev/bone/i2c/2
can be in a new group?
Hello,
Okay…
ls -l /dev/bone/i2c/0
reports back root root
as user and group. This does not matter.NOT
move.So, I will keep trying. Thank you for the readers and participants in my short on this ServoCape.
Seth
Hi @silver2row
Are you using this cape ?
BeagleBoard.org BeagleBone Servo Cape 1 up from the bottom ?
I have just hooked up a Adafruit clone PCA9685 board to my BBB using the same I2C bus.
I initially set the address to the address for the above board using your code, but this didn’t work. Checking the signals I could see that the Python code was indeed sending data, but there was no ACK back. Wrong address.
Checking the schematic for my board, the default address is 64. Using this and everything seems to work just fine, although I haven’t tried setting a PWM, but I expect it to work.
I have run a few simple tests, see below.
On my BBB /dev/i2c-x are owned by root in group i2c
the file /lib/udev/rules.d/60-i2c-tools.rules sets this.
This is running Debian 10.3
Kernel is:
Linux beaglebone 4.19.94-ti-r42 #1buster SMP PREEMPT Tue Mar 31 19:38:29 UTC 2020 armv7l GNU/Linux
Python code
PCA96xx.py
from smbus2 import SMBus
from time import sleep
# registers!
Mode1 = 0x00
Mode2 = 0x01
LED = 0x06
All_LED = 0xFA
PRE_SCALE = 0xFE
class PCA9685:
def __init__(self, bus, addr):
self.addr = addr
self.bus = bus
self.write_reg(Mode1, 1 << 5)
sleep(500e-6)
def read_reg(self, reg):
assert reg in range(0, 256)
return self.read_regs(reg, 1)[0]
def write_reg(self, reg, value):
return self.write_regs(reg, [value])
def read_regs(self, reg, value):
assert reg in range(0, 256)
assert value in range(1, 257 - reg)
return self.bus.read_i2c_block_data(self.addr, reg, value)
def write_regs(self, reg, values):
assert reg in range(0, 256)
return self.bus.write_i2c_block_data(self.addr, reg, values)
def get_pwm(self, output):
assert output in range(0, 16)
reg = LED + 4 * output
[on_l, on_h, off_l, off_h] = self.read_regs(reg, 4)
on = on_l | on_h << 8
off = off_l | off_h << 8
phase = on
duty = (off - on) & 0xfff
if off & 0x1000:
duty = 0
elif on & 0x1000:
duty = 4096
return (duty, phase)
def set_pwm(self, output, duty, phase = 0):
assert duty in range(0, 4097)
assert phase in range(0, 4096)
if output == "all":
reg = All_LED
else:
assert output in range(0, 16)
reg = LED +4 * output
on = phase
off = (duty + phase) & 0xfff
if duty == 0:
off |= 0x1000
elif duty == 4096:
on |= 0x1000
on_l = on & 0xff
on_h = on >> 8
off_l = off & 0xff
off_h = off >> 8
self.write_regs(reg, [on_l, on_h, off_l, off_h])
-----------------------------------------------------------------------
#!/usr/bin/python3
from PCA96xx import *
from time import sleep
i2c_bus = SMBus(2)
pwm_controller = PCA9685(i2c_bus, 64)
AUTO_INC = (1 << 4)
SLEEP = (1 << 4)
print( pwm_controller.read_regs(0,2))
print( pwm_controller.read_reg(254))
# can only change frequency in sleep mode
pwm_controller.write_reg(0, AUTO_INC | SLEEP)
# set 50Hz
pwm_controller.write_reg(254,121)
pwm_controller.write_reg(0, AUTO_INC )
print( pwm_controller.read_reg(254))
-------------------------------------------------
output from above
[32, 4]
30
121
Hope that helps.
Hello Sir,
@benedict.hewson , I will test this later today. Thank you!
Seth
P.S. It seems my address is 34 on the BBB I have currently. I am using 5.10.x kernels from the newer images. And yes, one up from the bottom is the ServoCape in question.
I thought these files were located in /etc/udev/rules.d/
? I will check /lib/
.
Hello @benedict.hewson ,
Sir, I tried it and got returns on output. So, whatever you did, works. Still, w/ my current source, I am not making it work all that well.
Seth
P.S. I had to change some source in your specific entries in the code but for the most part, it works. Here is my output:
[9, 9]
0
0
I am not completely sure I understand what this means, though. So, off to learn more!
Hi @silver2row
It is impossible for the PCA9685 chip to be at address 34. I2C usually has a 7 bit address (can be 10 bits but not in this case) Address bit A6 if physycally set to a 1 in the chip, with bits A0-A5 being set externally. The address of the chip can therefore be anything from 64-127 (0x40 - 0x7f) with the default for the board at 127 (0x7f)
This can be changed by soldering across the pads on the pcb. No join and the address bit is a 1, shorted and the address bit becomes 0. This assume that the board matches the schematic.
The only thing in the above code you would need to change would be the address.
Hello,
Sorry. You were right. I changed 2 in the line, i2c_bus = SMBus(2)
, to “/dev/i2c-0” and then pwm_controller = PCA9685(I2c_bus, 64)
to pwm_controller = PCA9685(i2c_bus, 0x34)
.
Seth
P.S. I changed the address and the i2c_bus issue. I cannot get it to work unless I am using 0 and not 2 in the address space.
Hi @silver2row
According to the schematic, the cape is on I2C-2. Unless the naming of the I2C ports has changed I2C-0 can not work. Let me find a 5.1x BBB image and see if this is the case.
You do have this connected to a beaglebone black yes ? I know you are also playing around with the BBA1 64.
Again the address of the chip can not possibly be 0x34.
Are any of the address pads shorted out on your cape ?
I2C-0 is connected to the eeprom on the beaglebone board. No idea what address that is on. Also to the PMIC and HDMI chip. It is not connected to the expansion headers.
If you unplug the cape and run the program, do you still get the same results ?
There is of course an eeprom on the cape you are using, at address 0x54 according to the schematic.
Yes,
I am using the BBB for this effort w/ kernel 5.10.x. I have nothing shorted on the Cape.
I will test to see if using the board, this BBB, reports the same output w/out the Cape.
Seth
With nothing shorted on the cape, the address should be 0x7f as the resistors pull the address lines high… Might be worth checking with a DVM.
I know you are right. I know that the EEPROM is for /dev/i2c-0, P9.19/20.
W/out using /dev/i2c-0, I am useless so far, i.e. as I cannot configure the board w/ the Cape to do anything that resembles movement. To this day, I cannot attest to using it w/ it working.
But…I believe it worked once upon a time w/ an older model Compatibility Layer from the .org.
Seth
P.S. I will test more and return service. I understand that /dev/i2c-0 is the connection from BBB to ServoCape but why do I receive output when using it?
Am I basically just outputting the EEPROM on the Cape w/ /dev/i2c-0 as my fd?
Using bone-debian-11.3-iot-armhf-2022-05-10-4gb.img
Linux BeagleBone 5.10.109-ti-r45 #1bullseye
Everything still works. Device is still on I2C-2 and the output from the program is as expected.
Are you using a .dtbo or a specific .dtb?
I could not get i2c-2 to work w/out error so far. I will try again. Maybe I broke my system somehow.
Seth
I just flashed the image to an sdcard. I have no cape fitted, just wiring the I2C-2 lines to the PCA9685 board.
It is using
am335x-boneblack-uboot-univ.dtb
BB-ADC-00A0.dtbo
BB-BONE-eMMC1-01-00A0.dtbo
BB-HDMI-TDA998x-00A0.dtbo
Have you got a serial console on the board.
U-Boot probes the cape e2prom addresses, maybe it is loading something.
No serial console from UART0 debug header.
I still have the Cape on it. I have a ssh terminal so far only.
Seth
But… sudo beagle-version
reported in output this idea:
uboot_detected_capes=BBORG_SERVO
if you do
ls /proc/device-tree/chosen/overlays/
does it list any other overlays ?
Yes,
BB-ADC-00A0.kernel BB-BONE-eMMC1-01-00A0.kernel BB-HDMI-TDA998x-00A0.kernel BBORG_SERVO-00A2 name
Those are my files.
Seth
ok BBORG_SERVO-00A2 should be loading the pca9685 driver for address 0x7f
That is almost certainly why your code is not working as the address will be claimed by the driver.
I am not sure how the driver appears to the system.
You should have something in /sys/class/pwms for that chip
try
ls -l /sys/class/pwm/
lrwxrwxrwx 1 root root 0 Oct 11 09:06 pwmchip0 -> ../../devices/platform/ocp/48000000.interconnect/48000000.interconnect:segment@300000/48300000.target-module/48300000.epwmss/48300100.pwm/pwm/pwmchip0
lrwxrwxrwx 1 root root 0 Oct 11 09:06 pwmchip1 -> ../../devices/platform/ocp/48000000.interconnect/48000000.interconnect:segment@300000/48302000.target-module/48302000.epwmss/48302100.pwm/pwm/pwmchip1
lrwxrwxrwx 1 root root 0 Oct 11 09:06 pwmchip2 -> ../../devices/platform/ocp/48000000.interconnect/48000000.interconnect:segment@300000/48304000.target-module/48304000.epwmss/48304100.pwm/pwm/pwmchip2
lrwxrwxrwx 1 root root 0 Oct 11 09:06 pwmchip3 -> ../../devices/platform/ocp/48000000.interconnect/48000000.interconnect:segment@300000/48300000.target-module/48300000.epwmss/48300200.pwm/pwm/pwmchip3
lrwxrwxrwx 1 root root 0 Oct 11 09:06 pwmchip5 -> ../../devices/platform/ocp/48000000.interconnect/48000000.interconnect:segment@300000/48302000.target-module/48302000.epwmss/48302200.pwm/pwm/pwmchip5
lrwxrwxrwx 1 root root 0 Oct 11 09:06 pwmchip7 -> ../../devices/platform/ocp/48000000.interconnect/48000000.interconnect:segment@300000/48304000.target-module/48304000.epwmss/48304200.pwm/pwm/pwmchip7
That is that and this is ls -l /dev/bone/pwm/*
0:
total 0
lrwxrwxrwx 1 root root 29 Oct 11 09:06 a -> /sys/class/pwm/pwmchip3/pwm0/
lrwxrwxrwx 1 root root 29 Oct 11 09:06 b -> /sys/class/pwm/pwmchip3/pwm1/
1:
total 0
lrwxrwxrwx 1 root root 29 Oct 11 09:06 a -> /sys/class/pwm/pwmchip5/pwm0/
lrwxrwxrwx 1 root root 29 Oct 11 09:06 b -> /sys/class/pwm/pwmchip5/pwm1/
2:
total 0
lrwxrwxrwx 1 root root 29 Oct 11 09:06 a -> /sys/class/pwm/pwmchip7/pwm0/
lrwxrwxrwx 1 root root 29 Oct 11 09:06 b -> /sys/class/pwm/pwmchip7/pwm1/
Seth
P.S. I will test these instances and see if I can make them move w/ duty_cycle and period w/ enable.
Oh! I have no pwm group. Should this matter?