Timer stalls - Page 1
Forum section: electronics / general

author: zer0c00l
author_rank: Contributor
timestamp: August 04, 2020, 11:49:47 pm
content: 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 thisCode:static __irq __arm void TIMER_handler0(void) {DWORD T0int;T0int = T0IR;if (T0int & IIR_CR0) { // interrupt due to rising edgeT0IR_bit.CR0INT = 1; // acknowledge interrupt//Do stuff to figure out frequency of input signal}if ((T0int & IIR_MR0) || (T0int & IIR_MR1)) { // interrupt due to matchT0IR_bit.MR0INT = 1; // acknowledge interruptT0CCR_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 registerT0TC = 0;timer0busy = 0;}VICADDRESS = 0x0;}While loop in my main code checks "timer0busy" flag and looks like thisCode:while(timer0busy) {//Do stuff}"timer0busy" flag is set to 1 when the timer0 is enable which is done before this while loopOn 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

author: cv007
author_rank: Frequent Contributor
timestamp: August 05, 2020, 06:37:07 am
content: T0IR_bit.CR0INT = 1; // acknowledge interruptT0IR_bit.MR0INT = 1; // acknowledge interruptThe 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 flagT0IR = 1<<0; //clear MR0 flagNot sure if that is the cause of your problem, but it is a problem.

author: zer0c00l
author_rank: Contributor
timestamp: August 06, 2020, 03:55:01 am
content: Quote from: cv007 on August 05, 2020, 06:37:07 amThanks 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

author: cv007
author_rank: Frequent Contributor
timestamp: August 06, 2020, 04:55:31 am
content: 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/EWfeTvCode:#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; //incorrectT0IR = 1<<0; //correctwhile(1);}/*main://T0IR_bit.MR0INT = 1;ldr r3, .L3ldrb r2,  //readorr r2, r2, #1 //modify -> |= 1strb r2,  //write//T0IR = 1<<0;mov r2, #1 //bit0 is all we want clearedstr r2,  //a single register write will result in only bit0 cleared.L2:b .L2.L3:.word -536854528*/