DFR0548 Driver Expansion Board for micro:bit
Hi,
I would like to use the driver FRR0548 on a micro with MicroPython. I have converted the JavaScript code to MicroPython, but it is not working. The driver works correctly under MakeCode. Can you help me? Here is the Python code:
import microbit
import time
PCA9685_ADDRESS = 0x40
MODE1 = 0x00
PRESCALE = 0xFE
LED0_ON_L = 0x06
# Énumération pour les moteurs CC
class Motors:
M1 = 0x01
M2 = 0x02
M3 = 0x03
M4 = 0x04
# Énumération pour la direction du moteur
class Dir:
cw = 1
ccw = -1
# Variable pour indiquer si le module PCA9685 a été initialisé
initialized = False
def init_pca9685():
microbit.i2c.init()
devices = microbit.i2c.scan()
for addr in devices:
print("Périphérique trouvé à l'adresse :", hex(addr))
start = 0x07
end = 0x70
print("Scanning I2C bus...")
for i in range(start, end + 1):
try:
microbit.i2c.read(i, 1)
except OSError:
pass
else:
print("Found: [%s]" % hex(i))
print("Scanning complete")
set_freq(50)
return True
def i2c_write(addr, reg : int, value):
print(value)
buf = bytearray(2)
buf[0] = reg
buf[1] = value
print("microbit.i2c.write", PCA9685_ADDRESS, buf)
microbit.i2c.write(PCA9685_ADDRESS, buf)
def i2c_read(addr: int, reg: int):
val = bytes(1)
print("i2c_read",bytes(val))
val = microbit.i2c.read(addr, 1, repeat=False)
print("i2c_read",bytes(val))
return val
def set_freq(freq):
print("set_freq")
prescaleval = 25000000
prescaleval /= 4096
prescaleval /= freq
prescaleval -= 1
prescale = int(prescaleval)
olmoode = bytes(1)
oldmode= i2c_read(PCA9685_ADDRESS, MODE1)
print("oldmode",oldmode)
newmode = (int.from_bytes(oldmode, 'big') & 0x7F) | 0x10
print("newmode",newmode)
i2c_write(PCA9685_ADDRESS, MODE1, newmode) # go to sleep
print("prescale",prescale)
i2c_write(PCA9685_ADDRESS, PRESCALE, prescale) # set the prescaler
print("oldmode", oldmode)
time.sleep(5)
i2c_write(PCA9685_ADDRESS, MODE1, int.from_bytes(oldmode, 'big') | 0xa1)
def set_pwm(channel, on, off):
if channel < 0 or channel > 15:
return
buf = bytearray(5)
buf[0] = LED0_ON_L + 4 * channel
buf[1] = on & 0xff
buf[2] = (on >> 8) & 0xff
buf[3] = off & 0xff
buf[4] = (off >> 8) & 0xff
if buf:
print("microbit.i2c.write(" + hex(PCA9685_ADDRESS) + ", " + "/".join(hex(v) for v in buf) + ")")
microbit.i2c.write(PCA9685_ADDRESS, buf)
def MotorRun(index: int, direction: int, speed: int):
speed = speed * 16 * direction;
if (speed >= 4096):
speed = 4095
if (speed <= -4096):
speed = -4095
if (index > 4 or index <= 0):
return
pn = (4 - index) * 2
pp = (4 - index) * 2 + 1
print("speed", speed, pn, pp)
if (speed >= 0):
set_pwm(pp, 0, speed)
set_pwm(pn, 0, 0)
else:
set_pwm(pp, 0, 0)
set_pwm(pn, 0, -speed)
initialized = init_pca9685()
time.sleep(3)
MotorRun(Motors.M1, Dir.cw, 100)
I am seeking your help with an issue I am facing in the development of a Python driver for the DFR0548 card. I have managed to write a first code in Python based on the existing JavaScript driver. However, I could not find any technical documentation detailing the frames to be sent in I2C, which makes the task more challenging.
My goal is to control the motors and servomotors using my Python driver. I have succeeded in making them work with makecode, but I can't get it to work in Python. I don't understand where the problem is coming from, and I would appreciate your informed opinion.
Moreover, I have been able to code the digital outputs and the analog outputs without any difficulty. On the other hand, I am encountering difficulties with the peripherals on the I2C bus.
I am attaching my Python code along with the frames sent on the I2C bus to this message. If anyone has already encountered this type of problem or if you have any ideas to help me resolve this anomaly, I am open to any suggestions.
I would also be delighted if some of you could test my first code and share your feedback with me.
Thank you in advance for your valuable help.
python code :
import microbit
import time
PCA9685_ADDRESS = 0x40
MODE1 = 0x00
PRESCALE = 0xFE
LED0_ON_L = 0x06
# Enum for DC Motors
class Motors:
M1 = 0x01
M2 = 0x02
M3 = 0x03
M4 = 0x04
# Enum for Motor Direction
class Dir:
cw = 1
ccw = -1
class Servos:
S1 = 0x08
S2 = 0x07
S3 = 0x06
S4 = 0x05
S5 = 0x04
S6 = 0x03
S7 = 0x02
S8 = 0x01
isDebug = True
def DebugWrite(addr, buf):
if isDebug :
if buf:
print("microbit.i2c.write(" + hex(addr) +
"," + "/".join(hex(v) for v in buf) + ")")
def DebugRead(addr, result):
if isDebug :
if result :
print("microbit.i2c.read")
def DebugMess(mess):
if isDebug :
if mess :
print(mess)
# Variable to indicate if the PCA9685 module has been initialized
initialized = False
def init_pca9685():
microbit.i2c.init(freq=100000)
devices = microbit.i2c.scan()
for addr in devices:
print("Device found at address:", hex(addr))
if PCA9685_ADDRESS not in devices:
print("PCA9685 not found.")
return False
print("PCA9685 found. Initializing...")
set_freq(50)
return True
def i2c_write(addr, reg, value):
buf = bytearray(2)
buf[0] = reg
buf[1] = value
DebugWrite(addr, buf)
microbit.i2c.write(addr, buf)
def i2c_read(addr, reg):
DebugWrite(addr, bytearray([reg]))
microbit.i2c.write(addr, bytearray([reg]))
val = microbit.i2c.read(addr, 1)
DebugRead(addr, val)
return val
def set_freq(freq):
DebugMess("set_freq")
prescaleval = 25000000
prescaleval /= 4096
prescaleval /= freq
prescaleval -= 1
prescale = int(prescaleval + 0.5) # Rounding up
oldmode = i2c_read(PCA9685_ADDRESS, MODE1)
newmode = (oldmode[0] & 0x7F) | 0x10 # sleep
i2c_write(PCA9685_ADDRESS, MODE1, newmode) # go to sleep
i2c_write(PCA9685_ADDRESS, PRESCALE, prescale) # set the prescaler
i2c_write(PCA9685_ADDRESS, MODE1, oldmode[0])
time.sleep(0.005)
i2c_write(PCA9685_ADDRESS, MODE1, oldmode[0] | 0x80)
# i2c_write(PCA9685_ADDRESS, MODE1, oldmode[0] | 0xa1)
def set_pwm(channel, on, off):
if channel < 0 or channel > 15:
return
buf = bytearray(5)
buf[0] = LED0_ON_L + 4 * channel
buf[1] = on & 0xff
buf[2] = (on >> 8) & 0xff
buf[3] = off & 0xff
buf[4] = (off >> 8) & 0xff
DebugWrite(PCA9685_ADDRESS, buf)
microbit.i2c.write(PCA9685_ADDRESS, buf)
def motorRun(index, direction, speed):
DebugMess("MotorRun")
speed = speed * 16 * direction
if speed >= 4096:
speed = 4095
elif speed <= -4096:
speed = -4095
if index > 4 or index <= 0:
return
pn = (4 - index) * 2
pp = (4 - index) * 2 + 1
if speed >= 0:
set_pwm(pp, 0, speed)
set_pwm(pn, 0, 0)
else:
set_pwm(pp, 0, 0)
set_pwm(pn, 0, -speed)
def motorStop(index):
DebugMess("MotorStop")
set_pwm((4 - index) * 2, 0, 0)
set_pwm((4 - index) * 2 + 1, 0, 0)
def motorStopAll():
DebugMess("MotorStopAll")
for idx in range(1, 5, 1):
motorStop(idx)
def servo(index, degree):
DebugMess("Servo")
v_us = (degree * 1800 / 180 + 600)
value = v_us * 4096 / 20000
set_pwm(index + 7, 0, int(value))
initialized = init_pca9685()
time.sleep(1)
if initialized:
motorRun(Motors.M1, Dir.cw, 255)
time.sleep(5)
motorStopAll()
servo(Servos.S1, 20)
time.sleep(1)
servo(Servos.S1, 90)
time.sleep(1)
servo(Servos.S1, 160)
time.sleep(1)
else:
print("Initialization failed.")
Frames sent :
MicroPython v1.15-64-g1e2f0d280 on 2021-06-30; micro:bit v2.0.0 with nRF52833
Type "help()" for more information.
>>> Device found at address: 0x40
Device found at address: 0x70
PCA9685 found. Initializing...
set_freq
microbit.i2c.write(0x40,0x0)
microbit.i2c.read
microbit.i2c.write(0x40,0x0/0x31)
microbit.i2c.write(0x40,0xfe/0x79)
microbit.i2c.write(0x40,0x0/0x31)
microbit.i2c.write(0x40,0x0/0xb1)
MotorRun
microbit.i2c.write(0x40,0x22/0x0/0x0/0xf0/0xf)
microbit.i2c.write(0x40,0x1e/0x0/0x0/0x0/0x0)
MotorStopAll
MotorStop
microbit.i2c.write(0x40,0x1e/0x0/0x0/0x0/0x0)
microbit.i2c.write(0x40,0x22/0x0/0x0/0x0/0x0)
MotorStop
microbit.i2c.write(0x40,0x16/0x0/0x0/0x0/0x0)
microbit.i2c.write(0x40,0x1a/0x0/0x0/0x0/0x0)
MotorStop
microbit.i2c.write(0x40,0xe/0x0/0x0/0x0/0x0)
microbit.i2c.write(0x40,0x12/0x0/0x0/0x0/0x0)
MotorStop
microbit.i2c.write(0x40,0x6/0x0/0x0/0x0/0x0)
microbit.i2c.write(0x40,0xa/0x0/0x0/0x0/0x0)
Servo
microbit.i2c.write(0x40,0x42/0x0/0x0/0xa3/0x0)
Servo
microbit.i2c.write(0x40,0x42/0x0/0x0/0x33/0x1)
Servo
microbit.i2c.write(0x40,0x42/0x0/0x0/0xc2/0x1)
MicroPython v1.15-64-g1e2f0d280 on 2021-06-30; micro:bit v2.0.0 with nRF52833
Type "help()" for more information.
>>>
Patrick.GelinaudThanks for the python code suggestion which I tested immediately.
This new code doesn't work either. Here are the traces of the frames sent to DFR0548 Driver by the python code. Or I can find some documentation on what information to send to DFR0548 on the I2C bus.
Thanking you in advance for your assistance
MicroPython v1.15-64-g1e2f0d280 on 2021-06-30; micro:bit v2.0.0 with nRF52833
Type "help()" for more information.
>>>
>>> Device found at address: 0x40
Device found at address: 0x70
PCA9685 found. Initializing...
set_freq
microbit.i2c.write(0x40,0x0)
microbit.i2c.read
microbit.i2c.write(0x40,0x0/0x11)
microbit.i2c.write(0x40,0xfe/0x79)
microbit.i2c.write(0x40,0x0/0x11)
microbit.i2c.write(0x40,0x0/0x91)
MotorRun
microbit.i2c.write(0x40,0x22/0x0/0x0/0x40/0x6)
microbit.i2c.write(0x40,0x1e/0x0/0x0/0x0/0x0)
Patrick.GelinaudYou can edit your code like this:
import microbit
import time
PCA9685_ADDRESS = 0x40
MODE1 = 0x00
PRESCALE = 0xFE
LED0_ON_L = 0x06
# Enum for DC Motors
class Motors:
M1 = 0x01
M2 = 0x02
M3 = 0x03
M4 = 0x04
# Enum for Motor Direction
class Dir:
cw = 1
ccw = -1
# Variable to indicate if the PCA9685 module has been initialized
initialized = False
def init_pca9685():
microbit.i2c.init(freq=100000)
devices = microbit.i2c.scan()
for addr in devices:
print("Device found at address:", hex(addr))
if PCA9685_ADDRESS not in devices:
print("PCA9685 not found.")
return False
print("PCA9685 found. Initializing...")
set_freq(50)
return True
def i2c_write(addr, reg, value):
buf = bytearray(2)
buf[0] = reg
buf[1] = value
microbit.i2c.write(addr, buf)
def i2c_read(addr, reg):
microbit.i2c.write(addr, bytearray([reg]))
val = microbit.i2c.read(addr, 1)
return val
def set_freq(freq):
prescaleval = 25000000
prescaleval /= 4096
prescaleval /= freq
prescaleval -= 1
prescale = int(prescaleval + 0.5) # Rounding up
oldmode = i2c_read(PCA9685_ADDRESS, MODE1)
newmode = (oldmode[0] & 0x7F) | 0x10 # sleep
i2c_write(PCA9685_ADDRESS, MODE1, newmode) # go to sleep
i2c_write(PCA9685_ADDRESS, PRESCALE, prescale) # set the prescaler
i2c_write(PCA9685_ADDRESS, MODE1, oldmode[0])
time.sleep(0.005)
i2c_write(PCA9685_ADDRESS, MODE1, oldmode[0] | 0x80)
def set_pwm(channel, on, off):
if channel < 0 or channel > 15:
return
buf = bytearray(5)
buf[0] = LED0_ON_L + 4 * channel
buf[1] = on & 0xff
buf[2] = (on >> 8) & 0xff
buf[3] = off & 0xff
buf[4] = (off >> 8) & 0xff
microbit.i2c.write(PCA9685_ADDRESS, buf)
def MotorRun(index, direction, speed):
speed = speed * 16 * direction
if speed >= 4096:
speed = 4095
elif speed <= -4096:
speed = -4095
if index > 4 or index <= 0:
return
pn = (4 - index) * 2
pp = (4 - index) * 2 + 1
if speed >= 0:
set_pwm(pp, 0, speed)
set_pwm(pn, 0, 0)
else:
set_pwm(pp, 0, 0)
set_pwm(pn, 0, -speed)
initialized = init_pca9685()
time.sleep(1)
if initialized:
MotorRun(Motors.M1, Dir.cw, 100)
else:
print("Initialization failed.")
Thanks for the python code suggestion which I tested immediately.
This new code doesn't work either. Here are the traces of the frames sent to DFR0548 Driver by the python code. Or I can find some documentation on what information to send to DFR0548 on the I2C bus.
Thanking you in advance for your assistance
MicroPython v1.15-64-g1e2f0d280 on 2021-06-30; micro:bit v2.0.0 with nRF52833
Type "help()" for more information.
>>>
>>> Device found at address: 0x40
Device found at address: 0x70
PCA9685 found. Initializing...
set_freq
microbit.i2c.write(0x40,0x0)
microbit.i2c.read
microbit.i2c.write(0x40,0x0/0x11)
microbit.i2c.write(0x40,0xfe/0x79)
microbit.i2c.write(0x40,0x0/0x11)
microbit.i2c.write(0x40,0x0/0x91)
MotorRun
microbit.i2c.write(0x40,0x22/0x0/0x0/0x40/0x6)
microbit.i2c.write(0x40,0x1e/0x0/0x0/0x0/0x0)