How can I increase the callback priority/importance on my Timer? (STM32F401)

Discussion and questions about boards that can run MicroPython but don't have a dedicated forum.
Target audience: Everyone interested in running MicroPython on other hardware.
nmz787
Posts: 29
Joined: Sun Jul 10, 2016 7:57 am

How can I increase the callback priority/importance on my Timer? (STM32F401)

Post by nmz787 » Mon Mar 20, 2017 6:27 am

I have an STM32F401RET6 (on a G30Th dev board) that I've programmed TIM1 with one pulse mode (OPM), and have enabled n-pulse mode by setting a number of pulses to the repetition count register (RCR). I also attach a callback (interrupt function) to the Timer object at creation time, and by using OPM, the interrupt fires only at the end of the pulse-series, with the update event (UEV).

This is all great for my purpose. But, I am seeing up to 8.7 microseconds of variation between when the UEV occurs, and when the interrupt runs. This is not great.

From what I have read, there should be a way to increase the importance of this Timer interrupt, I believe this should be in the EXTI register, and according to the STM32F401RET6 datasheet (this is in the G30TH dev board) on page 203:
"TIM1_UP_TIM10" should be at 0x000000A4

but when I read:
stm.mem16[stm.EXTI + 0xA4]

I get zeros, and writing a value there doesn't have any effect.

Code: Select all

import pyb
from pyb import Timer
import micropython
import stm
from machine import Pin

micropython.alloc_emergency_exception_buf(100)

period = 10000
width = 1000

def adjust_tim1_pulses(number_pulses):
  stm.mem16[stm.TIM1 + stm.TIM_RCR] = (stm.mem16[stm.TIM1 + stm.TIM_RCR]
                                       & 0xff<<8) | ((number_pulses - 1)
                                       & 0xff)

def adjust_tim1(period, width, number_pulses=None):
  stm.mem16[stm.TIM1 + stm.TIM_ARR] = period
  stm.mem16[stm.TIM1 + stm.TIM_CCR1] = period - width
  if number_pulses != None:
  	adjust_tim1_pulses(number_pulses)

p32_pin = Pin('JP32', Pin.OUT)
p32_pin.value(0)

def tim1_opm_end_cb(t):
  p32_pin.value(0)

# Timer 1 to repeat a burst every burst_period counting up:
t1 = pyb.Timer(1, prescaler=11, period=period, mode=Timer.UP, callback=tim1_opm_end_cb)

stm.mem16[stm.TIM1 + stm.TIM_CR1] &= ~1 & 0xFFFF # disable Clock-Enable

adjust_tim1_pulses(8) # pulse tim1 8 times before the next UEV
stm.mem16[stm.TIM1 + stm.TIM_CR1]  |= (1 << 3)   # want one-time mode

t1ch1 = t1.channel(1, pyb.Timer.PWM, pulse_width=1,
                   polarity=pyb.Timer.LOW, pin=pyb.Pin.board.JP17)

def pulse():
  stm.mem16[stm.TIM1 + stm.TIM_CNT] = 0  # set the counter to 0
  stm.mem16[stm.TIM1 + stm.TIM_EGR] |= 1 # generate an event to ensure any shadow registers are updated
  p32_pin.value(1)
  stm.mem16[stm.TIM1 + stm.TIM_CR1] |= 1 # Clock Enable

nmz787
Posts: 29
Joined: Sun Jul 10, 2016 7:57 am

Re: How can I increase the callback priority/importance on my Timer? (STM32F401)

Post by nmz787 » Mon Mar 20, 2017 6:31 am

another odd issue with that code, is that the board locks up if I try to set the default period to something small, like 100

This is odd especially because if I start the board with higher period and width settings, then adjust things later, with the adjust_tim1 function, it works to decrease things, but then you see the variation between UEV and the interrupt-function.

User avatar
dhylands
Posts: 3821
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

Re: How can I increase the callback priority/importance on my Timer? (STM32F401)

Post by dhylands » Mon Mar 20, 2017 4:05 pm

The TIM1_UP_TIM10 that you're referring to is from the vector table and controls the interrupt which runs. This is in flash and can't be changed.

In stmhal, this can be found here:
https://github.com/micropython/micropyt ... m32.S#L213
This is then implemented in C here:
https://github.com/micropython/micropyt ... #L570-L575

The default priorities of the interrupts are set here:
https://github.com/micropython/micropyt ... irq.h#L101

To change the priorities you need to change registers in the NVIC. The stm module doesn't know about the NVIC, so you'll need to add your own definitions. I wrote a little tool here which dumps out the NVIC priorities:
https://github.com/dhylands/upy-example ... er/nvic.py

You can use the interrupt number from the CMSIS files to determine the correct index:
https://github.com/micropython/micropyt ... 1xe.h#L118

The C code which initializes the NVIC for the timers can be found here:
https://github.com/micropython/micropyt ... #L605-L607

This can be confirmed, by initializing timer 1 with a callback and then dumping th NVIC table. So with this snippet of code:

Code: Select all

import pyb

LED = pyb.LED(4)

def callback(tim):
    LED.toggle()

tim = pyb.Timer(1, freq=2, callback=callback)

import nvic
I get this output:

Code: Select all

>>> import tim1
NVIC_PRIO = 00000000 @ e000e400
VTOR      = 08000000 @ e000ed08
System IRQs
 -2:15
Regular IRQs
  4:2
 25:14
 27:14
 50:6
 67:6
So we can see that TIM1_UP_TIM10_IRQn (25) and TIM1_CC_IRQn (27) have been initialized with a priority of 14 (which agrees with irq.h)

User avatar
dhylands
Posts: 3821
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

Re: How can I increase the callback priority/importance on my Timer? (STM32F401)

Post by dhylands » Mon Mar 20, 2017 4:13 pm

You'll probably find that the systick timer, which fires every millisecond, may be contributing to your problem.

Systick has a priority of 0 currently. So you might want to try setting SysTick to 1 and Timer1 to 0.

nmz787
Posts: 29
Joined: Sun Jul 10, 2016 7:57 am

Re: How can I increase the callback priority/importance on my Timer? (STM32F401)

Post by nmz787 » Mon Mar 20, 2017 4:30 pm

Thanks Dave!

I'll give it a try this evening :)

nmz787
Posts: 29
Joined: Sun Jul 10, 2016 7:57 am

Re: How can I increase the callback priority/importance on my Timer? (STM32F401)

Post by nmz787 » Wed Mar 22, 2017 5:02 am

I couldn't see the SysTick interrupt at level 0 in my output:

Code: Select all

NVIC_PRIO = 00000000 @ e000e400
VTOR      = 08000000 @ e000ed08
System IRQs
 -2:15
Regular IRQs
  4:2
 25:14
 27:14
 50:6
 67:6
and my board didn't like when I tried setting the callback function's priority to 0.

It did however seem to be OK with being set at 1:

Code: Select all

stm.mem8[0xe000e400+25]=1<<4
as far as I can tell, from mashing on my keyboard to fire the 'pulse()' triggering function from the REPL... I am not seeing any jitter at the end :)

So now please tell me how you figured those addresses and/or offsets? I can't seem to find any of the offsets or bases that you coded, or were in my REPL output after importing nvic. I have been reading these:
http://www.st.com/content/ccc/resource/ ... 096844.pdf
http://www.st.com/content/ccc/resource/ ... 102166.pdf

Are these simply undocumented, and only in the CMSIS code?

User avatar
dhylands
Posts: 3821
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

Re: How can I increase the callback priority/importance on my Timer? (STM32F401)

Post by dhylands » Wed Mar 22, 2017 5:23 am

NVIC and SysTick are common to all Cortex-M processors.

STM has document PM0214: http://www.st.com/resource/en/programmi ... 046982.pdf which covers off the STM32F3 and STM32F4 series. This document includes the NVIC, SysTick, the instruction set and registers.

User avatar
dhylands
Posts: 3821
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

Re: How can I increase the callback priority/importance on my Timer? (STM32F401)

Post by dhylands » Wed Mar 22, 2017 5:46 am

I modified nvic.py to add the nvic_set_prio function.

Code: Select all

import machine

SCS = 0xE000E000
SCB = SCS + 0x0D00
NVIC = SCS + 0x0100
VTOR = SCB + 0x08

SCB_SHP = SCB + 0x18
NVIC_PRIO = NVIC + 0x300

def dump_nvic():
    print('NVIC_PRIO = {:08x} @ {:08x}'.format(machine.mem32[NVIC_PRIO], NVIC_PRIO))
    print('VTOR      = {:08x} @ {:08x}'.format(machine.mem32[VTOR], VTOR))

    print('System IRQs')
    for i in range(12):
        irq = -(16 - (i + 4))
        prio = machine.mem8[SCB_SHP + i] >> 4
        if prio > 0:
            print('{:3d}:{:d}'.format(irq, prio))

    print('Regular IRQs')
    for irq in range(80):
        prio = machine.mem8[NVIC_PRIO + irq] >> 4
        if prio > 0:
            print('{:3d}:{:d}'.format(irq, prio))

def nvic_set_prio(irq, prio):
    if irq < 0:
        idx = (irq & 0x0f) - 4
        machine.mem8[SCB_SHP + idx] = prio << 4
    else:
        machine.mem8[NVIC_PRIO + irq] = prio << 4

dump_nvic()
Everything seems to be working fine:

Code: Select all

>>> import nvic
NVIC_PRIO = 00000000 @ e000e400
VTOR      = 08000000 @ e000ed08
System IRQs
 -2:15
Regular IRQs
  4:2
 50:6
 67:6
>>> import tim1
>>> nvic.dump_nvic()
NVIC_PRIO = 00000000 @ e000e400
VTOR      = 08000000 @ e000ed08
System IRQs
 -2:15
Regular IRQs
  4:2
 25:14
 27:14
 50:6
 67:6
>>> nvic.nvic_set_prio(-1, 1)
>>> nvic.nvic_set_prio(25, 0)
>>> nvic.dump_nvic()
NVIC_PRIO = 00000000 @ e000e400
VTOR      = 08000000 @ e000ed08
System IRQs
 -2:15
 -1:1
Regular IRQs
  4:2
 27:14
 50:6
 67:6
>>> 
The dump_nvic routine doesn't print 0 entries, so any entry that doesn't show up can be assumed to be zero. You can see that the SysTick_IRQn (-1) now has a priority of 1, and TIM1_UP_TIM10_IRQn (25) doesn't show up any more which means it has a priority of zero.

User avatar
dhylands
Posts: 3821
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

Re: How can I increase the callback priority/importance on my Timer? (STM32F401)

Post by dhylands » Wed Mar 22, 2017 5:52 am

nmz787 wrote:another odd issue with that code, is that the board locks up if I try to set the default period to something small, like 100

This is odd especially because if I start the board with higher period and width settings, then adjust things later, with the adjust_tim1 function, it works to decrease things, but then you see the variation between UEV and the interrupt-function.
Have you tried hooking up a logic analyzer and seeing how long your interrupt routine takes?

If the time between back-to-back firings of the timer IRQ is less than the time that the IRQ takes to run, then your code will be running the timer IRQ for 100% of the time and will never run the foreground app.

nmz787
Posts: 29
Joined: Sun Jul 10, 2016 7:57 am

Re: How can I increase the callback priority/importance on my Timer? (STM32F401)

Post by nmz787 » Wed Mar 22, 2017 8:31 am

dhylands wrote:NVIC and SysTick are common to all Cortex-M processors.

STM has document PM0214: http://www.st.com/resource/en/programmi ... 046982.pdf which covers off the STM32F3 and STM32F4 series. This document includes the NVIC, SysTick, the instruction set and registers.
Ah, ok, thanks! More to read :lol:

Post Reply