Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[ARM] AT91SAM7X timer configuration and interrupt problem

Status
Not open for further replies.

rezaf

Advanced Member level 4
Full Member level 1
Joined
Apr 11, 2009
Messages
106
Helped
1
Reputation
2
Reaction score
1
Trophy points
1,298
Location
Montagram
Visit site
Activity points
2,147
Hi,
I'm trying to make 1ms interrupt with RC register value compare interrupt in AT91SAM7X with a 18.432MHz crystal.
my calculations are :

Definitions: MUL=25, DIV=5, CSS(clock source selection)=PLL Clock, Prescaler=clock/2

PLLCK = Main OSC*(MUL+1)/DIV
PLLCK = 18432000*(25+1)/5 = 95846400
MCK = 95846400/2(prescaler) = 47923200 MCK = 47923200
Timer clock frequency = MCK/timer clock DIV = 47923200/2 = 23961600 Hz

and according to one of atmel's guides :

RC = t*FTC = 0.001*23961600 = 23961


now with the below code that I written, there is a problem. after powering on the board, only one interrupt occurs and the LED for interrupt function indication blinks once after blinking the LED, the chip don't execute other codes and hangs up even with reading status register of timer and acknowledging the interrupt.

Code:
void timer1_c_irq_handler (void)
{
	
	unsigned int dummy;
	
	dummy = AT91C_BASE_TC1->TC_SR;
	dummy = dummy;
	
	T_Counter++;
	
	AT91C_BASE_TC1->TC_CCR |= AT91C_TC_CLKEN | AT91C_TC_SWTRG;
	
	
	AT91F_AIC_AcknowledgeIt(AT91C_BASE_AIC);
	
        AT91F_PIO_SetOutput(AT91C_BASE_PIOA, AT91C_PIO_PA2);     //Normal work LED notification
	delay_ms(500);
	AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, AT91C_PIO_PA2);	
	
}

int main (void) 
{
	unsigned int dummy ;
	
	AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, AT91C_PIO_PA2);      //LED 1
	AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, AT91C_PIO_PA3);      //LED 2

       AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_TC1;         // Enable peripheral clock
       AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;             // Disable TC clock
       AT91C_BASE_TC1->TC_IDR = 0xFFFFFFFF;                  // Disable interrupts
       dummy = AT91C_BASE_TC1->TC_SR;                        // Clear status register
       AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK | AT91C_TC_CPCTRG;	  // Set mode

       AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN ;             // Enable the Clock counter 
       AT91C_BASE_TC1->TC_IER = AT91C_TC_CPCS;    
    
		AT91C_BASE_AIC->AIC_IDCR = 0x1 << AT91C_ID_TC1;
		AT91C_BASE_AIC->AIC_SVR[AT91C_ID_TC1] = (unsigned int) timer1_c_irq_handler;
		AT91C_BASE_AIC->AIC_SMR[AT91C_ID_TC1] = AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL | 4 ;
		AT91C_BASE_AIC->AIC_ICCR = 0x1 << AT91C_ID_TC1;
		AT91C_BASE_AIC->AIC_IECR = 0x1 << AT91C_ID_TC1;
		
    AT91C_BASE_TC1->TC_RC = 23961; 
    AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG;

  while(1)
		{
			AT91F_PIO_SetOutput(AT91C_BASE_PIOA, AT91C_PIO_PA3);     //Normal work LED notification
			delay_ms(100);
			AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, AT91C_PIO_PA3);

			Func1();                             /*first function  */
			AT91F_PIO_SetOutput(AT91C_BASE_PIOA, AT91C_PIO_PA4);     //Normal work LED notification
			delay_ms(100);
			AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, AT91C_PIO_PA4);		
			Func2();                        /*second function  */
	  }
}

what is the problem ? Please help me to solve the problem.
Thanks,
Regards.
 
Last edited:

You should not use delays inside interrupt service routine. Are you reloading the timer value and clearing the interrupt flag on every interrupt? Set a flag inside ISR when there ia an interrupt. Use this flag in while(1) loop to execute the code you want when there is an interrupt. Tou can do this by checking if falg is set in an if() condition and if true (set) execute LED code once or as many times you want and then clear the flag.
 

You should not use delays inside interrupt service routine. Are you reloading the timer value and clearing the interrupt flag on every interrupt? Set a flag inside ISR when there ia an interrupt. Use this flag in while(1) loop to execute the code you want when there is an interrupt. Tou can do this by checking if falg is set in an if() condition and if true (set) execute LED code once or as many times you want and then clear the flag.

Thanks, I changed the code as below but the problem not solved yet. the LED blinks once and don't repeat blinking in 1ms period. I clear the TC_SR with reading it and clear the interrupt with acknowledging it and other codes but really don't know that this codes are true for interrupt handling function or not.

Code:
void timer1_c_irq_handler (void)
{
	volatile unsigned int dummy;
	
	dummy = AT91C_BASE_TC1->TC_SR;
	dummy = dummy;
	
	T_Counter++;
	TimerFlag = 1;
	dummy = AT91C_BASE_TC1->TC_CV;
	*AT91C_AIC_EOICR = 0; 
        AT91C_BASE_AIC->AIC_EOICR = AT91C_BASE_TC0->TC_SR;      //  Interrupt Ack
        AT91C_BASE_AIC->AIC_ICCR  = (1 << AT91C_ID_TC0);        //  Interrupt Ack
	AT91C_BASE_AIC->AIC_EOICR = AT91C_BASE_AIC->AIC_EOICR;
	AT91C_BASE_TC1->TC_CCR |= AT91C_TC_CLKEN | AT91C_TC_SWTRG;
}

Code:
int main (void) 
{
	unsigned int dummy ;
	
	AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, AT91C_PIO_PA2);      //LED 1
	AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, AT91C_PIO_PA3);      //LED 2

    AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_TC1;         // Enable peripheral clock
    AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;             // Disable TC clock
    AT91C_BASE_TC1->TC_IDR = 0xFFFFFFFF;                  // Disable interrupts
    dummy = AT91C_BASE_TC1->TC_SR;                        // Clear status register
    AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK | AT91C_TC_CPCTRG;	  // Set mode

    AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN ;             // Enable the Clock counter 
    AT91C_BASE_TC1->TC_IER = AT91C_TC_CPCS;    
    
		AT91C_BASE_AIC->AIC_IDCR = 0x1 << AT91C_ID_TC1;
		AT91C_BASE_AIC->AIC_SVR[AT91C_ID_TC1] = (unsigned int) timer1_c_irq_handler;
		AT91C_BASE_AIC->AIC_SMR[AT91C_ID_TC1] = AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL | 4 ;
		AT91C_BASE_AIC->AIC_ICCR = 0x1 << AT91C_ID_TC1;
		AT91C_BASE_AIC->AIC_IECR = 0x1 << AT91C_ID_TC1;
		
    AT91C_BASE_TC1->TC_RC = 23961; 
    AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG;
		
 while(1)
		{
                    if(TimerFlag == 1)
			 {
     			    AT91F_PIO_SetOutput(AT91C_BASE_PIOA, AT91C_PIO_PA2);     //timer int LED notification
			    delay_ms(100);
			    AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, AT91C_PIO_PA2);    
                           TimerFlag = 0;
			 }				 
	  }		
}
 

1 ms delay for blinking is too fast. It will blink 10 times in a second and you will either notice that LED is always ON or always OFF. Make delay as 500 ms or higher. Which Compiler are you using and what Clock are you using? If possible zip and post the entire project files.

**broken link removed**
 
  • Like
Reactions: rezaf

    rezaf

    Points: 2
    Helpful Answer Positive Rating
1 ms delay for blinking is too fast. It will blink 10 times in a second and you will either notice that LED is always ON or always OFF. Make delay as 500 ms or higher. Which Compiler are you using and what Clock are you using? If possible zip and post the entire project files.

**broken link removed**

yes you said true. I changed delay to 500ms but the problem remained yet and the LED blinks only for one time and go off . I use Keil 4 and the clock is 18.432MHz. I used many peripherals of chip in my project and no one has problem but this part(timer) taken many times.

Code:
void timer1_c_irq_handler (void)
{
	volatile unsigned int dummy;
	
	dummy = AT91C_BASE_TC1->TC_SR;
	dummy = dummy;
	
	T_Counter++;
	TimerFlag = 1;

	dummy = AT91C_BASE_TC1->TC_CV;
	*AT91C_AIC_EOICR = 0; 
         AT91C_BASE_AIC->AIC_EOICR = AT91C_BASE_TC0->TC_SR;      //  Interrupt Ack
         AT91C_BASE_AIC->AIC_ICCR  = (1 << AT91C_ID_TC0);        //  Interrupt Ack

	AT91C_BASE_TC1->TC_CCR |= AT91C_TC_CLKEN | AT91C_TC_SWTRG;

	AT91C_BASE_AIC->AIC_EOICR = AT91C_BASE_AIC->AIC_EOICR;	//interrupt acknowledge
}

int main (void) 
{
	unsigned int dummy ;
	
	AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, AT91C_PIO_PA2);      //LED 1
	AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, AT91C_PIO_PA3);      //LED 2

    AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_TC1;         // Enable peripheral clock
    AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;             // Disable TC clock
    AT91C_BASE_TC1->TC_IDR = 0xFFFFFFFF;                  // Disable interrupts
    dummy = AT91C_BASE_TC1->TC_SR;                        // Clear status register
    AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK | AT91C_TC_CPCTRG;	  // Set mode

    AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN ;             // Enable the Clock counter 
    AT91C_BASE_TC1->TC_IER = AT91C_TC_CPCS;    
    
		AT91C_BASE_AIC->AIC_IDCR = 0x1 << AT91C_ID_TC1;
		AT91C_BASE_AIC->AIC_SVR[AT91C_ID_TC1] = (unsigned int) timer1_c_irq_handler;
		AT91C_BASE_AIC->AIC_SMR[AT91C_ID_TC1] = AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL | 4 ;
		AT91C_BASE_AIC->AIC_ICCR = 0x1 << AT91C_ID_TC1;
		AT91C_BASE_AIC->AIC_IECR = 0x1 << AT91C_ID_TC1;
		
    AT91C_BASE_TC1->TC_RC = 93857; 
    AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG;
		
     while(1)
	{
                     if(TimerFlag==1) 
                       {
                           AT91F_PIO_SetOutput(AT91C_BASE_PIOA, AT91C_PIO_PA2);     //timer int LED notification
                           delay_ms(100);
                           AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, AT91C_PIO_PA2);    
                           TimerFlag = 0;
	               }				 
	  }
}

I think that must do a few works in the while loop except the interrupt function, to continue the interrupts and blinking the LED continuously, that doesn't done yet. is this true ? or the acknowledges and reading and clearing of registers in interrupt function isn't complete or there are mistakes in calculations?
 
Last edited:

You are still using 100 ms delay instead of 500 ms delay. What is the duration of your timer interrupt? It should be >= 500 ms because LED code will take say 520 ms to execute after first interrupt and if 2nd interrupt happens before the LED code is executed then the result can't be decided. Eg. if timer interrupt is for 100 ms then before the execution of LED code after 1st interrupt there will be another 3 or 4 timer interrupts. I don't understand why you are using both delay for LED and timer? You can just use a timer of 500 ms and then toggle LED in the ISR itself. This way LED will blink every 500 ms.
 
  • Like
Reactions: rezaf

    rezaf

    Points: 2
    Helpful Answer Positive Rating
Thanks "jayanth.devarayanadurga", the problem solved with adding an "__irq" to the end of first line of interrupt service function as below :

Code:
void TC_irq_handler(void) __irq

I will post complete routine in the next days that I completed it.
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top