I'm still relatively new to the STM32 family (a couple months now, previously worked exclusively in ARM7 family). I'm working on a very time constrained code. All is coded in GAS, no C, no OS. I'm using the STM32F730Z8, and clocking it at 200 MHz. All code is copied into ITCM SRAM at boot and executed from there for speed (VTOR maps the vector table appropriately as well).
The problem is that I'm getting double calls to interrupt handlers. I have searched here and on the ST knowledge base, and see a few references, but what they suggest doesn't fix it.
A minimized example is to set the clocking to 200 MHz, enable only TIM7 interrupts. TIM7 is setup by:
write TIM7_CNT,0
write TIM7_PSC,9
write TIM7_ARR,99
write TIM7_DIER,1
write TIM7_CR1,1
The TIM7 handler looks like:
push {lr}
write GPIOD_BSRR,1<<13
write TIM7_SR,0
b <label> to jump over a bunch of crap
write GPIOD_BSRR,1<<29
POP {pc}
"write" is just a simple macro:
.macro write addr, value
ldr r1,=\addr
ldr r0,=\value
str r0,[r1]
.endm
The use of PD13 is as a timing fiducial -- I look at that pin on my scope. What I see is pairs of pulses. They are properly 10us apart, so each pair is produced by a single reload of TIM7. Each pair consists of two 25ns pulses with a gap of 100ns between.
This is unacceptable. I need to have only a single call to the handler on each timer tick. I've tried writing twice to TIM7_SR to clear the UIF bit. I've tried writing to TIM7_SR at entry to the handler and at exit. I've tried clearing the pending bit in NVIC_ICPR1. I've tried inserting extra nonsense code to give it more time to propagate the clearing action. I can't believe that there is no fix for this. Help!?!
Jeff Casey / Rockfield Research Inc. / [email protected] / Las Vegas, NV
ok, I think I have it figured out. I don't like it, but this is consistent. Executive summary: yes, you need nonsense code while the interrupt clear propagates to the clock. however, the clock base speed is not the same as the bus speed that transfers that information.
first off, the clocking is very complex on this chip. I have HCLK (AHB=SYS) running at 200 MHz. The APB2 bus has a max of 100 MHz, so needs a divider of 2. The APB1 bus has a max of 50 MHz, so needs a divider of 4.
I initially had a typo in the divisor for the APB1 bus setup, and was giving it a divider of 8.
All this was further confused by my setting TIMPRE=1. That is a parameter for setting up the clock acceleration. When off, it gives clocks a 2x speed boost over the bus unless the bus prescale is 1, when it doesn't. When TIMPRE is on, it lets the clock run at HCLK if the prescale is 1/2/4, otherwise it sets a 4x boost over the bus. Got that?
So initially I had APB1 at /8, or 25 MHz and TIMPRE=1. This gave a 4x boost, so the base for the clock was 100 MHz. I needed 70 ns worth of nonsense NOP delay to allow the interrupt reset to propagate and avoid a double entry to the handler.
Fixing this to give APB1 /4 for 50 Mhz, and TIMPRE=1 gave a base of 200 MHz for the clock. I now need only 7-8 NOPs of nonsense added, for a scope fiducial of 45 ns. Note the difference here -- the APB1 bus is now running 2x faster.
The TIM7 sits on the APB1 bus. I then switched to using TIM9, which sits on the APB2 bus....that has a max speed of 100 MHz, so I have the divisor set to 2. In all other respects this is the same -- note that both TIM7 and TIM9 are running at 200 MHz base for the clock ticks, but with TIM9, the interrupt clears with only 4-5 NOPs of nonsense added, for a scope fiducial of 35 ns. Running on the faster peripheral bus gives me faster response to clearing the interrupt.
This is a TERRIBLE feature. This is not a happy solution I am posting, it is a hacky workaround. I don't dare code interrupt services (at least short ones) now without checking for double-taps on the scope. ST should be massively ashamed of themselves. I will apologize for that if somebody finds a better fix - ideally some setup parameter that I missed to make these behave the way they should. If this is unavoidable due to architecture, perhaps ST could hang a timer on the AHB bus which might solve the problem completely.
I pulled out hair over this one. I hope my post saves somebody else's scalp.