Variable FREQUENCY(not pulse length) PWM for machine vision stepper control

I need help with coding a variable frequency PWM signal to control a TMC2208 stepper driver with the OpenMV H7 Plus. I am using this driver rather than the stepper motor shield as the TMC2208 makes for silent stepper function. I need silence for this as I am putting a cell phone on top of a turntable so that it can be rotated to follow my kid as she walks around and plays during facetime with her grandmother. The phone will be right near the motor so I cant have stepper noise blasting into the microphone.

The main issue im having is that I cannot find a way to create a realtime variable PWM frequency. I am using the blob tracking OPENMV example and want to take the center of the blob and link its position to the motor driver. When the blob center gets more than 10 pixels to the right or left of center then the motor starts stepping in the opposite direction to bring the camera back to center. If I just use a simple pyb.delay function it does not make a very nice signal on the oscilloscope because of all the other code running at the same time for the object detection, every other pulse delay is really long depending on the strain on the processor at any particular time.

How can I isolate this loop so that pin7 outputs a frequently updated pulse frequency that isnt interfered by the processing of other code running at the same time?

Of note, this works fine if I use a servo along with the chA.pulse_width() function to make variable pulse lengths but when trying to change the frequency of the pulses themselves as required to control a stepper driver it gets very messy.
Im not a programmer or engineer. Just jumping into this.

Here is a sample of what Im doing:

_________________________________________________
#Blob tracking example. "Blob" will be my kid wearing a bright red shirt

import sensor, image, time, math, pyb

threshold_index = 0 # 0 for red, 1 for green, 2 for blue

# Color Tracking Thresholds (L Min, L Max, A Min, A Max, B Min, B Max)
# The below thresholds track in general red/green/blue things. You may wish to tune them...
thresholds = [(30, 100, 15, 127, 15, 127), # generic_red_thresholds
              (30, 100, -64, -8, -32, 32), # generic_green_thresholds
              (0, 30, 0, 64, -128, 0)] # generic_blue_thresholds

motorstep = pyb.Pin("P7", pyb.Pin.OUT_PP)
enable = pyb.Pin("P8", pyb.Pin.OUT_PP)

sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.skip_frames(time = 2000)
sensor.set_auto_gain(False) # must be turned off for color tracking
sensor.set_auto_whitebal(False) # must be turned off for color tracking
clock = time.clock()
# Only blobs that with more pixels than "pixel_threshold" and more area than "area_threshold" are
# returned by "find_blobs" below. Change "pixels_threshold" and "area_threshold" if you change the
# camera resolution. "merge=True" merges all overlapping blobs in the image.
while(True):
    clock.tick()
    img = sensor.snapshot()

    for blob in img.find_blobs([thresholds[threshold_index]], pixels_threshold=200, area_threshold=400, merge=True):
        # These values depend on the blob not being circular - otherwise they will be shaky.
        if blob.elongation() > 0.5:
            img.draw_edges(blob.min_corners(), color=(255,0,0))
            img.draw_line(blob.major_axis_line(), color=(0,255,0))
            img.draw_line(blob.minor_axis_line(), color=(0,0,255))
        # These values are stable all the time.

        img.draw_cross(blob.cx(), blob.cy())

        img.draw_keypoints([(blob.cx(), blob.cy(), int(math.degrees(blob.rotation())))], size=20)
        print(clock.fps())
        print("====\nBlob %s" % blob[5])

        enable.low()   # pulls the enable pin to low and activates stepper driver
        x = blob.cx() #define x as the central blob position x axis
        if blob[5] >170:    # if center blob position is on right of center do following
        pyb.udelay(5000-(x*30))  #this will make motor turn faster as x value becomes greater (i.e. blob gets further from center of screen). A delay of 500us to 5000us between pulses makes very fast to very slow motor speed respectively. 320 is the x screen resolution so 320-170 = 150, is max value of x in this statement. 150*30 = 4500, so if the blob center is completely at the right edge of the screen the delay will be 5000-4500 = 500, which makes a very fast motor speed.  
        motorstep.low()
        pyb.udelay(5000-(x*30))  
        motorstep.high()

        elif blob[5] <150:
            # will write code that is opposite of statement above, motor spin faster as blob gets further to the left from center

        elif blob[5] <170 >150:
		enable.high() # enable pin is set to high to disable stepper driver. Nothing happens here since the object is in the center of the frame

Hi, it’s going to be really hard to do this with a stepper motor because the processor gets interrupted to capture camera data pretty much continuously all the time.

You need to use the hardware features of the camera. PWM generation or Servo PWM generation don’t require the processor to manually control anything. They are hardware modules that run by themselves and the processor just sets the waveform shape and lets it run.

So, see the Examples → Board Control → PWM example for how to generate a PWM output using a timer module.

Hey, thanks for your quick response! I really want to avoid using a servo. Can any of the OPENMV motor shields drive a stepper in this manner?

Thanks for your help.

Hi, you can just pipe the PWM output to the step signal of the stepper motor driver. It will be 100% stable. Then you can just control the Timer period to change the frequency.

Great, that sounds like a good solution. Will give it a try thank you!