Page 1 of 2

TypeError in Viper routine but no floats in sight

Posted: Tue Aug 24, 2021 9:30 pm
by nedkonz
Perhaps someone could help me figure out why I'm getting an exception in my ISR code.

I've been working on a stepper motor library which calculates timer periods on the fly during acceleration.
I'm currently limited to about 600 pulses/second on each of three motors; past that I run out of the micropython.schedule() queue. I'm calling micropython.schedule() to handle a floating point expression after each timer interrupt.

I'm trying to use the Viper emitter to get better speed out of the ISR. The 'micropython.native' emitter worked OK but I need more speed.

The problem that I'm running into is this: During execution I get an exception from the interrupt handler that looks like this:

Code: Select all

uncaught exception in Timer(8) interrupt handler
TypeError: can't convert float to int
uncaught exception in Timer(13) interrupt handler
TypeError: can't convert float to int
uncaught exception in Timer(4) interrupt handler
TypeError: can't convert float to int
I've put casts on everything I could find in the routine, and made sure that none of my object's instance variables hold floats.

So I'm at a loss as to what exactly is causing this complaint.

My ISR looks like this:

Code: Select all

    @micropython.viper
    def _compute_new_speed(self, t):
        self._step_pin.value(int(1))
        # are we at the target speed  yet?
        self._at_speed = False
        if bool(self._decelerating):
            self._at_speed = ((int(self._direction) == int(self._target_direction)) \
                and (int(self._speed) <= int(self._target_speed)))
            if int(self._n) >= int(0):   # we've hit int(0) speed; check for a change in direction
                # will print after ISR
                # micropython.schedule(self._cached_debug, self._cached_msg2)
                self._direction = int(self._target_direction)
                self._decelerating = False
                if int(self._direction) == DIRECTION_CW:
                    self._direction_pin.value(int(1))
                    self._reverse_direction_pin.value(int(0))
                else:
                    self._direction_pin.value(int(0))
                    self._reverse_direction_pin.value(int(1))
        else:
            self._at_speed = bool(int(self._speed) >= int(self._target_speed))

        if bool(self._at_speed):
            # micropython.schedule(self._cached_debug, self._cached_msg)
            # self.pulse_debug_pin()
            self._n = int(0)
            self._speed = int(self._target_speed)
            self._position = int(self._position) + int(self._direction) # update position
            # set the timer period
            if int(self._target_speed) != int(0):
                self._cn = int(int(TIMER_FREQUENCY) // int(self._target_speed))
                t.period(int(self._cn) - int(1))
                t.callback(self._cached_update_position)
            else:
                # stop timer output (and callbacks)
                t.deinit()
                self._cn = int(0)
            return

        # update speed and timer period
        self._speed = int(int(TIMER_FREQUENCY) // int(self._cn))
        t.period(int(self._cn) - int(1))

        # update position
        self._position = int(self._position) + int(self._direction)

        # update _cn and _n after ISR:
        micropython.schedule(self._cached_update_cn, None)

        self._step_pin.value(int(0))
Can anyone spot the float? I can't.
Thanks!

Re: TypeError in Viper routine but no floats in sight

Posted: Wed Aug 25, 2021 5:52 am
by Roberthh
What ate the initial values in self?

Re: TypeError in Viper routine but no floats in sight

Posted: Wed Aug 25, 2021 9:17 am
by pythoncoder
I've never tried Viper in an ISR, but it should work. I suggest including

Code: Select all

import micropython
micropython.alloc_emergency_exception_buf(100)
This might give you a line number where the fault is occurring. One shot in the dark is that Viper likes type hints. Failing all this, the "brute force and ignorance" way to locate the offending line is to comment out bits of your ISR until the error goes away.

Re: TypeError in Viper routine but no floats in sight

Posted: Wed Aug 25, 2021 1:02 pm
by nedkonz
Roberthh wrote:
Wed Aug 25, 2021 5:52 am
What ate the initial values in self?
Assuming you meant 'are', not 'ate':

Here's a list (taken after a move finished, so several of the values are 0, which they wouldn't be in the ISR):

Code: Select all

_step_pin: Pin(Pin.cpu.A6, mode=Pin.OUT)
_direction_pin: Pin(Pin.cpu.B6, mode=Pin.OUT)
_reverse_direction_pin: Pin(Pin.cpu.C7, mode=Pin.OUT)
_debug_pin: Pin(Pin.cpu.C7, mode=Pin.OUT)
_name: motor3
_position: 0 # signed integer
_speed: 0 # unsigned integer
_direction: 1 # -1 or 1
_target_speed: 500 # unsigned integer
_target_direction: 1 # -1 or 1
_n: 0 # signed integer
_cn: 6169 # unsigned integer
_c0: 6169 # unsigned integer
_cmin: 60 # unsigned integer
_max_speed: 2400 # unsigned integer
_max_acceleration: 4800 # unsigned integer

Re: TypeError in Viper routine but no floats in sight

Posted: Wed Aug 25, 2021 1:09 pm
by nedkonz
pythoncoder wrote:
Wed Aug 25, 2021 9:17 am
I've never tried Viper in an ISR, but it should work. I suggest including

Code: Select all

import micropython
micropython.alloc_emergency_exception_buf(100)
This might give you a line number where the fault is occurring. One shot in the dark is that Viper likes type hints. Failing all this, the "brute force and ignorance" way to locate the offending line is to comment out bits of your ISR until the error goes away.
Thanks for the suggestions!

I have an emergency buffer allocated already. But unfortunately I am not getting a line number.

As you can see from my code, I've type-hinted everything in the ISR.

I've tried commenting out the lines with the divisions but it didn't help.

I'm now trying to write the ISR in C but am not sure how to extend a Python class with C.
I'll make a new post about that.

Re: TypeError in Viper routine but no floats in sight

Posted: Wed Aug 25, 2021 1:48 pm
by Roberthh
What's about self._decelerating?

Re: TypeError in Viper routine but no floats in sight

Posted: Wed Aug 25, 2021 3:35 pm
by nedkonz
Roberthh wrote:
Wed Aug 25, 2021 1:48 pm
What's about self._decelerating?
it's a bool.

Re: TypeError in Viper routine but no floats in sight

Posted: Wed Aug 25, 2021 5:05 pm
by dhylands
Have you tried renaming your callback and then make _compute_new_speed be a non-viper python function which just calls the renamed _compute_new_speed with a try/catch and then put a print of the exception in the catch. Something like:

Code: Select all

def _compute_new_speed(self, t):
  try:
      self._viper_compute_new_speed(t)
  except Exception as err:
      sys.print_exception(err)

Re: TypeError in Viper routine but no floats in sight

Posted: Wed Aug 25, 2021 5:46 pm
by pythoncoder
nedkonz wrote:
Wed Aug 25, 2021 1:09 pm
...
As you can see from my code, I've type-hinted everything in the ISR...
Not in the code you posted. I'd expect to see (for example)

Code: Select all

        self._at_speed : bool = False
I also wonder if a type hint on the first line would help

Code: Select all

    def _compute_new_speed(self : ptr32, t : ptr32):
but I'm not sure if those types are right. Objects are passed by reference, but perhaps in place of ptr32 you need your class name and Timer.

Please see this doc re Viper and type hints.

Re: TypeError in Viper routine but no floats in sight

Posted: Wed Aug 25, 2021 6:22 pm
by nedkonz
pythoncoder wrote:
Wed Aug 25, 2021 5:46 pm
nedkonz wrote:
Wed Aug 25, 2021 1:09 pm
...
As you can see from my code, I've type-hinted everything in the ISR...
Not in the code you posted. I'd expect to see (for example)

Code: Select all

        self._at_speed : bool = False
I just tried that exact line in a Viper function, and it crashed mpy-cross with an assertion:

Code: Select all

MPY accelstepper.py
Assertion failed: (vtype_val == VTYPE_PYOBJ), function emit_native_store_attr, file ../py/emitnative.c, line 1733.
make: *** [build/accelstepper.mpy] Abort trap: 6