After some study, trial and error, I created a simple project for a NXP LPC1768, to test its timer interrupt. This project contains only startup_LPC17xx.s, system_LPC17xx.c, C-main.c, and timer.c.
C-main.c:
#include "lpc17xx.h" #include "timer.h" extern uint32_t SystemFrequency; int main(void) { SystemInit(); Timer_Init_n_Enable( LPC_TIM0, (SystemFrequency/8-1) ); NVIC_EnableIRQ(TIMER0_IRQn); /* LED Init */ LPC_GPIO2->FIODIR |= 0x000000FF; /* P2.0 to P2.7 LEDs defined as output */ while(1); }
timer.c:
#include "lpc17xx.h" #include "timer.h" void TIMER0_IRQHandler(void) { LPC_TIM0->IR = (1u<<0); // Reset the MR0 Interrupt; Writing a zero has no effect. LPC_GPIO2->FIOPIN ^= (1<<7); // Toggle LED. } void Timer_Init_n_Enable( LPC_TIM_TypeDef * TimerX, uint32_t TimerInterval ) { TimerX->MR0 = TimerInterval; TimerX->MCR |= (1u<<0) | (1u<<1); // Interrupt and Reset on MR0 TimerX->TCR |= (1u<<0); // Enable Timer Counter and Prescale Counter }
This project seemed to work.
But if I change the timer.c to:
void TIMER0_IRQHandler(void) { LPC_GPIO2->FIOPIN ^= (1<<7); // Toggle LED. LPC_TIM0->IR = (1u<<0); // Reset the MR0 Interrupt; Writing a zero has no effect. }
It doesn't work.
If I change the timer.c to:
void TIMER0_IRQHandler(void) { LPC_GPIO2->FIOPIN ^= (1<<7); // Toggle LED. LPC_TIM0->IR = (1u<<0); // Reset the MR0 Interrupt; Writing a zero has no effect. NVIC_ClearPendingIRQ(TIMER0_IRQn); }
It seemed to works.
I guess that, it doesn't work because I clear the LPC_TIM0->IR interrupt flag too late, so the NVIC generates a pending interrupt for LPC_TIM0->IR.
I don't have a LPC23xx now, so I can't verify my guess. I guess that, it will still work:
void Timer0Handler(void) __irq { FIO2PIN ^= (1<<7); // Toggle LED. T0IR = 1; /* Clear Interrupt Flag */ VICVectAddr = 0; /* Acknowledge Interrupt */ }
I think it is usual that, programmer needs to do something to identify which kind of interrupt was triggered, before clear the interrupt flag.
So, if my understanding is correct, how do I know that, I did NOT clear the interrupt flag too late within an ISR?
It is quite frustrated that, I can't even handle a simple timer interrupt properly. Maybe my understanding has never been correct.
Hi John,
Quite likely the issue here is that the ISR ends before the bus cycle for accessing the interrupt flag has completed. Just spending a bit more time in the ISR and clearing the flag as early as possible should help. You might also try if a synchronization barrier (DSB) after clearing the flag helps. Pulse interrupts also help but might not always be available.
Regards Marcus http://www.doulos.com/arm/
That would be a possibilty that NXP would need to answer - it has nothing specifically to do with Keil.
It might also be specific to NXP's implementation - so that ST's examples would not be applicable...
"It might also be specific to NXP's implementation - so that ST's examples would not be applicable..."
I don't think so. I don't think NXP have any options open to them in this case, given the integration of the NVIC in the core.
But the help function in the ST example may represent extra clock cycles explaining the problem with the NXP chip and inlined acknowledge of the timer flag directly before the return.
"I don't think so. I don't think NXP have any options open to them in this case, given the integration of the NVIC in the core."
You may well be right; but NXP would be the ones to confirm it - rather than Keil.
Or, perhaps, the core documentation from ARM.
Or The Definitive Guide to the ARM Cortex-M3 by Joseph Yiu - see: http://www.keil.com/books/armbooks.asp
Or it might be an interaction between the NVIC and the Timer (which is NXP-specific)...?
View all questions in Keil forum