Author Topic: Timer stalls  (Read 1799 times)

0 Members and 1 Guest are viewing this topic.

Offline zer0c00lTopic starter

  • Contributor
  • Posts: 27
  • Country: us
Timer stalls
« on: August 04, 2020, 11:49:47 pm »
I am using an LPC2378 (ARM7TDMI-S) uC for a project. Timer0 on the uC is being used to measure frequency of a signal on one of the inputs of the uC. It is setup to interrupt on the rising edge of the signal (input capture) as well as interrupt on match register. The match register interrupt is set such that an interrupt occurs every 50mS. In my main code I have a while loop, which will only exit if a variable is set which only happens whenever the match interrupt of timer0 occurs. My ISR looks like this

Code: [Select]

static __irq __arm void TIMER_handler0(void) {
 
  DWORD T0int;
  T0int = T0IR;
 
  if (T0int & IIR_CR0) {          // interrupt due to rising edge
    T0IR_bit.CR0INT = 1;    // acknowledge interrupt
//Do stuff to figure out frequency of input signal

  }
 
  if ((T0int & IIR_MR0) || (T0int & IIR_MR1)) {    // interrupt due to match
    T0IR_bit.MR0INT = 1;    // acknowledge interrupt
    T0CCR_bit.CAP0I = 0;    // turn off both interrupts (capture & match)
    T0MCR_bit.MR0I = 0;   
    T0TCR_bit.CE = 0;       // turn off the counter and reset the counter register
    T0TC = 0;
    timer0busy = 0;
  }
  VICADDRESS = 0x0;   
}


While loop in my main code checks "timer0busy" flag and looks like this

Code: [Select]

while(timer0busy) {
       //Do stuff
}


"timer0busy" flag is set to 1 when the timer0 is enable which is done before this while loop

On to my issue. On some occasions I have noticed that my uC would stop sending output through the UART. On further invertigation I found that it was stuck in the above while loop because "timer0busy" flag never became 0. I did some more testing and figured that this usually happens when the frequency of the input signal (which is measured by timer0) is increased. Now my understanding is that as the frequency of the input signal is increased the interrupts due to rising edge will also increase, but what I cannot figure out is that why does at some point the interrupt due to match register stops happening. The match register is setup to interrupt every 50mS regardless of the frequency of the input signal, and when this interrupt happens, interrupts are disabled and flag is set to 0. For both capture and match register interrupts the ISR is the same. Is the timer overshooting the match value without getting caught?. I don' know how that could happen. What would happen if the rising edge and match happens at the same time?. Could this be the result when that happens

 

Offline cv007

  • Super Contributor
  • ***
  • Posts: 1068
Re: Timer stalls
« Reply #1 on: August 05, 2020, 06:37:07 am »
T0IR_bit.CR0INT = 1;    // acknowledge interrupt
T0IR_bit.MR0INT = 1;    // acknowledge interrupt

The result of this bit access will be read/modify/write which will also clear any other flag that is set.

You have to watch out for flag registers, and friendly bit access is usually a problem because of the r/m/w.

T0IR = 1<<4; //clear CR0 flag
T0IR = 1<<0; //clear MR0 flag

Not sure if that is the cause of your problem, but it is a problem.
 

Offline zer0c00lTopic starter

  • Contributor
  • Posts: 27
  • Country: us
Re: Timer stalls
« Reply #2 on: August 06, 2020, 03:55:01 am »
T0IR_bit.CR0INT = 1;    // acknowledge interrupt
T0IR_bit.MR0INT = 1;    // acknowledge interrupt

The result of this bit access will be read/modify/write which will also clear any other flag that is set.

You have to watch out for flag registers, and friendly bit access is usually a problem because of the r/m/w.

T0IR = 1<<4; //clear CR0 flag
T0IR = 1<<0; //clear MR0 flag

Not sure if that is the cause of your problem, but it is a problem.

Thanks for the response. How does friendly bit access result in r/m/w?. Is there some place I can read more about this like what kind of bit access does and does not do this
 

Offline cv007

  • Super Contributor
  • ***
  • Posts: 1068
Re: Timer stalls
« Reply #3 on: August 06, 2020, 04:55:31 am »
You need to see the asm output to understand. The following will show what is happening.

Although the bit access looks like it should only be dealing with a single bit, it has to read the peripheral register, modify the temp copy to set 1 particular bit, then store it back to the peripheral register. When reading the T0IR register, all bits (flags) are being read, a single bit is set via an orr instruction, then the value is written back- but these flags are cleared by writing its bit with a 1 so any other flag that was set now has its bit cleared because any bit that was 1 when read also writes that same value back.

The answer is to simply write a 1 to a bit position you want cleared via a single register write. Writing a bit with a 0 has no effect.

So anytime you find a register that has flags, in many cases they tend to be write 1 to clear, which means you will not be writing individual bits, but the whole register.

Clearing flags unintentionally will result in strange problems. Not sure if it is your problem currently, but if corrected it will at least be 1 less than you had before.


https://godbolt.org/z/EWfeTv

Code: [Select]
#include <stdint.h>

typedef struct { uint32_t MR0INT : 1; } bit_t;

#define T0IR_bit (*(volatile bit_t*)0xE0004000)
#define T0IR (*(volatile uint32_t*)0xE0004000)

int main(){

    T0IR_bit.MR0INT = 1; //incorrect
   
    T0IR = 1<<0; //correct

    while(1);

}

/*
main:
        //T0IR_bit.MR0INT = 1;
        ldr     r3, .L3

        ldrb    r2, [r3]    //read
        orr     r2, r2, #1  //modify ->  |= 1
        strb    r2, [r3]    //write

        //T0IR = 1<<0;
        mov     r2, #1 //bit0 is all we want cleared
        str     r2, [r3]  //a single register write will result in only bit0 cleared
.L2:
        b       .L2
.L3:
        .word   -536854528
*/
 
The following users thanked this post: zer0c00l


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf

 

- - -
-->