cancel
Showing results for 
Search instead for 
Did you mean: 

Missing update/compare interrupts from same timer

daniele239955
Associate II

Hi, I'm evaluating the STM8 UART emulation library (STSW-STM8051). I'm using the STM8SVLDISCOVERY board. Instead of the TIM3 I'm using the TIM2 timer since the TIM3 is not available on the STM8S003K3: I configured the project to communicate at a baudrate of 19200bps 8N1. The library uses both UPDATE and CAPTURE/COMPARE interrupts from the same timer. It seems that if the two interrupt flags are set in the same time only one ISR is serviced; it seems that only one interrupt from the same peripheral is serviced while the second one is not kept in queue. I have tried also with different priorities without success. The problem seems to arise if the second interrupt flag is set while the first ISR is evaluating the TIMx->SR1 register and clearing the flag (therefore if the compare register value is near the autoreload value).

In the errata this issue is not described. Can you please tell me what can I do to solve the problem? This problem must be solved to allow for full-duplex communication with the sw emulation library.

Thank you, best regards.

1 ACCEPTED SOLUTION

Accepted Solutions
Cristian Gyorgy
Senior III

Hi Daniele!

Well, than I guess you should use the "mov" instruction instead of "bres".

What happens might be that while the bres instruction is being decoded (with the CCiF flag still not set, 0) the interrupt takes place, the CCiF flag is set so when the bres instruction is being executed in the next clock cycle, it will write 0 to the CCiF flag (now set, 1) and reset it.

In the decode stage of the instruction the TIM2_SR1 register is being read, than in the execute stage the bit is reset in the read 8-bit value and the full 8-bit value is written back to TIM2_SR1.

Please try instead of bres to use: mov TIM2_SR1, #~(1<<UIF).

The 2 instructions, bres and mov, have the same size and execution cycles, so it is anyway better to use mov in such a case.

Can you please try it, I'm curious if this is what happens.

View solution in original post

5 REPLIES 5
Cristian Gyorgy
Senior III

Hello Daniele!

I know nothing of the library you mention, but I guess you just need to pay attention on how you clear your TIM2_SR1 flags. These flags are cleared by writing 0 to them. So, if for example in the ISR you clear the UIF by writing 0x00 to the TIM2_SR1 register, you loose all other set flags in the register - also the CCxIF; and vice-versa. So, don't use values like: (0<<FLAG_BIT_POSITION); as this will write 0x00.

The safest way of clearing the flags is to write ~(1<<FLAG_BIT_POSITION) in the TIM2_SR1 register, but you can also use the "bres" instruction.

If you still have problems, post your code here so we can see what it is about and the instructions/coding you use.

daniele239955
Associate II

Hello, thank you for your response. The ISR flags are cleared correctly with the bres instruction.

I've done some more investigation:

For my investigation I used the attached demo code. Here, PD3 is set as input capture on falling edge, while PD4 is set as output compare. The PD4 output is put into the PD3 input.

For timer TIM2 both overflow and input capture interrupts are enabled and both priorities are set to level 2.

As you can see, overflow interrupt is set when the counter reaches 0x01A1 (autoreload) value while the pin PD4 is toggled when the counter reaches the value 0x000A therefore ten clock cycle after the overflow interrupt. All the code is configured to force the input capture interrupt to be fired while the overflow interrupt service routine is clearing the overflow interrupt flag in the SR1 register.

Probably, while the CPU is writing to the SR1 register to clear the UIF flag, the TIM2 HW peripheral should have access the same register to set the CCI2F flag but, since the CPU is accessing the same register, the input capture event is lost and the CCIF2 flag is not set. Every time the interrupts are fired, a specific GPIO PIN is toggled so with an oscilloscope you can check if the interrupt routine has been called. If you toggle the PD4 pin at, fo example, 0x0020 instead of 0x000A or, if before clearing the interrupt flag you add one or two NOP instructions, the problem is solved.

I'm using the COSMIC compiler without any code optimization.

Therefore the problem seems a concurrent access to the SR1 register by both CPU and TIM peripheral.

Cristian Gyorgy
Senior III

Hi Daniele!

Well, than I guess you should use the "mov" instruction instead of "bres".

What happens might be that while the bres instruction is being decoded (with the CCiF flag still not set, 0) the interrupt takes place, the CCiF flag is set so when the bres instruction is being executed in the next clock cycle, it will write 0 to the CCiF flag (now set, 1) and reset it.

In the decode stage of the instruction the TIM2_SR1 register is being read, than in the execute stage the bit is reset in the read 8-bit value and the full 8-bit value is written back to TIM2_SR1.

Please try instead of bres to use: mov TIM2_SR1, #~(1<<UIF).

The 2 instructions, bres and mov, have the same size and execution cycles, so it is anyway better to use mov in such a case.

Can you please try it, I'm curious if this is what happens.

daniele239955
Associate II

Hi Cristian!

Yes you are right; I've implemented your suggestion. With mov instruction instead of bres instruction the problem is now solved. It is far better to use mov instruction to clear the flags.

Thank you very much for your very very useful contribution.

Best regards.

Cristian Gyorgy
Senior III

Glad it helped!

You're welcome!