Using PWM for motor on H7 Portenta

I want to control a regular 5V DC motor using H7 Portenta, but haven’t figured how PWM works on OpenMV. I checked Examples > Board Control > pwm_control.py and read how only PWM7/PH15 pin is available for the task on Portenta, which happens to be one of the high-density pins. What’s the name of this pin to use in

timer = pyb.Timer(4, freq=1000)
ena = timer.channel(1, pyb.Pin.OUT_PP, pin=**PWM PIN NAME HERE**)

When I use pyb.Pin(“PH15”), I get ValueError: Pin(PH15) doesn't have an alt for Timer(4)

Regards,
PC

It’s Timer8 on the Portenta:

Could you try to use one of the nonnegative channels? You generally want to use the non-N channels.

Thanks for that! I should have known about Timer8.

Could you please help me figure out how PWM works to power a motor on micropython? I have connected D0 to the motor driver and am running the following code that I got from what you suggested someone here:

import time
from pyb import Pin, Timer

tim = Timer(8, freq=1000) # Frequency in Hz
ch1 = tim.channel(1, Timer.PWM, pin=Pin("D0"), pulse_width_percent=75)

while (True):
    time.sleep(1000)

Am I missing something fundamental in understand how this works compared to Arduino/Raspberry Pi’s PWM?

PC

It’s Timer8 channel 3.

import time
from pyb import Pin, Timer

tim = Timer(8, freq=1000) # Frequency in Hz
ch1 = tim.channel(3, Timer.PWM, pin=Pin("PH15"), pulse_width_percent=75)

while (True):
    time.sleep(1000)

Sorry but I still don’t get how I can connect PWM7/PH15 to the motor in this case with a wire?

I saw another tutorial on getting this running on Youtube, based on which I have tried the following (still doesn’t work):

import pyb

# Define PWM pin
tim = pyb.Timer(8, freq=1000)
ch1 = tim.channel(3, pyb.Timer.PWM, pin=pyb.Pin("PH15"))

# Declare pin connected to motor driver
motor= pyb.Pin("D5", pyb.Pin.OUT_PP, pyb.Pin.PULL_NONE)

# Test in a loop
while True:
    print("ON")
    motor.value(1)
    ch1.pulse_width_percent(100)
    pyb.delay(1000)
    
    print("OFF")
    motor.value(0)
    pyb.delay(1000)

PC

Can you post a picture of your setup? The Portenta would normally drive PWM into the speed input on the motor driver and then also apply a direction pin to control forward and backwards. Note that the devices need to share a ground and the motor driver needs to be powered. The Portenta would not power the motor driver.

Here’s my setup:

To clarify further:

  1. Portenta Pin D5 to Driver Pin IN4
  2. Portenta Gnd to common ground
  3. Driver powered by the powerbank
  4. Driver MotorB to DC motor
  5. Motor driver: MX1508 DC Motor Driver with PWM Control Pinout, Datasheet, Features, Working

I have confirmed that all wires and components are working fine.

EDIT insufficient voltage was causing the problem. Changed the power source, tested on a multimeter, worked like a charm on this program:

import time, pyb
 
tim = pyb.Timer(8, freq=1000) # Frequency in Hz
ch1 = tim.channel(3, pyb.Timer.PWM, pin=pyb.Pin("PH15"))
carousel = pyb.Pin("D5", pyb.Pin.OUT_PP, pyb.Pin.PULL_DOWN)

while True:
    print("carousel on")
    carousel.value(1)
    pyb.delay(1000)
    
    print("carousel off")
    carousel.value(0)
    pyb.delay(1000)

Thanks for your support, @kwagyeman!

PC

1 Like

Hi @kwagyeman, could you please help me understand how I can slow down the motor using PWM as described in this thread? I have tried tweaking the freq parameter in Timer() and pulse_width_percent in Timer.channel() but that has not worked.

PC

It would be the pulse_width_percent value. Freq doesn’t really matter as long as it’s high enough to be integrated by the motor winding into an analog value. Freq also controls how much you can hear the whining of the system.

Anyway, for the motor controller you are using… it’s a pure h-bridge… so, it actually doesn’t really work the best with a dir/pwm input like you are trying to do.

See the chip we are using for our new driver shield: DRV8876 H-Bridge Motor Driver With Integrated Current Sense and Regulation datasheet (Rev. B). It explains the different drive modes one would want. The chip you are using only supports H-bridge mode which is hard to control.

Thanks for that! We have ordered heaps of the said H-bridge driver so I am pretty tied to it for the project though.

I was tweaking the program with the example pwm_control program to realise that pulse_width_percent=50 does work fine if I use the following code:

import time, pyb
from machine import LED

tim = pyb.Timer(8, freq=1000)                               # Set Timer for PWM
ch = tim.channel(3, pyb.Timer.PWM, pin=pyb.Pin("PH15"), pulse_width_percent=50)    # Only Pin PH15 is free to use when Vision Shiled is used
#carousel = pyb.Pin("D0", pyb.Pin.OUT_PP, pyb.Pin.PULL_DOWN) # Define GPIO pin to control motor

# Test in a loop
while True:
#    # ON
#    LED("LED_GREEN").on()
#    carousel.value(1)
#    pyb.delay(1000)
#    LED("LED_GREEN").off()

#    # OFF
#    LED("LED_RED").on()
#    carousel.value(0)
#    pyb.delay(1000)
#    LED("LED_RED")

    time.sleep_ms(1000)

I coded the variable carousel to be able to control when to turn the motor on and off. Can you please help me find a way to get that done with just PWM if that’s possible?

P.S., experimentally, I realised that using the carousel variable just disables (or rather overwrites) PWM in a way. The following program works fine with 100% motor intensity:

import time, pyb
from machine import LED

#tim = pyb.Timer(8, freq=1000)                               # Set Timer for PWM
#ch = tim.channel(3, pyb.Timer.PWM, pin=pyb.Pin("PH15"), pulse_width_percent=50)    # Only Pin PH15 is free to use when Vision Shiled is used
carousel = pyb.Pin("D0", pyb.Pin.OUT_PP, pyb.Pin.PULL_DOWN) # Define GPIO pin to control motor

# Test in a loop
while True:
    # ON
    LED("LED_GREEN").on()
    carousel.value(1)
    pyb.delay(1000)
    LED("LED_GREEN").off()

    # OFF
    LED("LED_RED").on()
    carousel.value(0)
    pyb.delay(1000)
    LED("LED_RED")

    time.sleep_ms(1000)

PC

Question, what are the pins attached to? From the picture you only attached 1 pin. You need two pins on both IN inputs of the H-bridge.

If you check the datasheet: MX1508_Datasheet.pdf

You’ll see that each channel is separate. So, if both inputs are low the motor windings are grounded. If one channel goes high then that supplies voltage to spin the motor. However, when the input goes low again (as PWM does), that grounds both motor windings causing it to break.

Anyway, this should be all you need. The PWM 50% example you post as you mention works. Just change the pulse_width_percent in the loop to change the speed.

If you want to turn the motor on/off just set the PWM width to 0%.

Portenta D0/PH15 → Driver INT1

I have connected only 1 pin for input here 'cause the motor for my project will turn only in one direction (anticlockwise). Good observation there on the channels being separate. I wanted to keep GPIO pins free for other sensors so thought this is good.

Works! Thanks for the advice.

Quick query: why does pulse_width_percent(100) turn the motor off and pulse_width_percent(0) runs it at 100% capacity? Quite counterintuitive.

Nonetheless, the following code is great for testing:

import time, pyb
from machine import LED

tim = pyb.Timer(8, freq=1000)                               # Set Timer for PWM
ch = tim.channel(3, pyb.Timer.PWM, pin=pyb.Pin("PH15"))     # Only Pin PH15 is free to use when Vision Shiled is used

# Test in a loop
while True:
    # ON
    LED("LED_GREEN").on()
    ch.pulse_width_percent(0)
    pyb.delay(1000)
    LED("LED_GREEN").off()

    # OFF
    LED("LED_RED").on()
    ch.pulse_width_percent(100)
    pyb.delay(1000)
    LED("LED_RED").off

PC

It’s because it’s the negative channel. So, it’s inverted.

@prithulc

1 Like

Everyday I learn something new! Thanks for all the guidance, Kwabena!