problem with general purpose timer

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

problem with general purpose timer

4,072 Views
VeronicaFNX
Contributor I
Hello, I have a problem with the GPT (general Purpose to timer).
I want to put a timer each 1 mseg and I do this,
 
void GPTimers_inicializa(void)
{
     MCF_GPT_GPTIOS = 0x01;   //Habilita los 4 GPT como output compare
    MCF_GPT_GPTSCR1 = MCF_GPT_GPTSCR1_GPTEN; //habilita cualquier
    MCF_GPT_GPTIE = MCF_GPT_GPTIE_CI(0x01);  //habilita la interrupcion del GPT0
    MCF_GPT_GPTSCR2 =MCF_GPT_GPTSCR2_PR(0x00); //Prescaler, 30MHz
    MCF_GPT_GPTFLG1 = 0x00; //limpia los chanel flags
    MCF_GPT_GPTFLG2 = 0x00; //limpiar flags
    
   MCF_GPT_GPTC0 = MCF_GPT_GPTC0_CCNT(0x7530);
   MCF_GPT_GPTC1 = 0;
   MCF_GPT_GPTC2 = 0;
   MCF_GPT_GPTC3 = 0;
    
    
   MCF_INTC0_ICR44 = MCF_INTC_ICR_IL(0x7) | MCF_INTC_ICR_IP(0x7); //GPT0
  MCF_INTC0_IMRH &= ~MCF_INTC_IMRH_MASK44;
}

int main()
{
  Leds_Init();
 GPTimers_inicializa();
 
 while(1); // Idle
 
 return 0;
}
 
and also initialize the interrupt vectors. That I am making bad? or, that I need to do? Thanks
Labels (1)
0 Kudos
3 Replies

283 Views
VeronicaFNX
Contributor I
Thanks for the aid but already to be used PIT. The problem is that I need to use a GPT and not that I am forming bad.
 
I want to timer each 1mseg to a frequency of 60MHz M52233demo
 
Thanks 
0 Kudos

283 Views
mccPaul
Contributor I
Hi
 
OK, so I have modified the code above to use GPT0 as it it was a PIT, see below. You will have you chaneg the references from MCF5282_GPTA to the equivalent MCF_GPT #defines because I have written this for the 5282 which has 2 GPTs (GPTA and GPTB) so the registers are slightly different.
 
I have just tested this and it works on my 5282. I noticed one error in your code - when you want to clear the flags, you must write a 1, not a 0. These lines are wrong:
 
 MCF_GPT_GPTFLG1 = 0x00; //limpia los chanel flags
 MCF_GPT_GPTFLG2 = 0x00; //limpiar flags
 
See section 23.6.12 in the reference guide. I also noticed a problem in the refernce guide with the pre-scaler. In table 23-14 it shows divisors from 1 to 64, in section 23.7.1 it says you can use 1 or 16. I don't know which is correct for 5223x. For 5282 all divisors are shown in both places in the refernce guide.
 
Maybe you will have to use prescaler divisor of 16 with count of 0x753 to get 1ms at 60MHz CPU clock.
 
Configure GPT:
 
Code:
/* FUNCTION: GPTA_Timer_Init() * * Initialise and enable General Purpose Timer A0 to work like * a PIT. * * PARAM2: Prescaler value - sets the tick frequency to *     (system clock/2) divided by 2^PCSR * * PARAM3: Modulo counter - sets the mumber of ticks per interrupt * * PARAM4: Interrupt handler * * RETURNS: none */voidGPTA_Timer_Init(uint8 PCSR, uint16 PMR, void (*handler)(void)){ // At 64MHz: // PCSR = 5 gives a tick per uS // PMR = 1000 gives an interrupt every 1ms uint8 ipl = MCF5282_INTC_ICR_IL(2)    | MCF5282_INTC_ICR_IP(0); // Disable timer A MCF5282_GPTA_GPTSCR1 = 0; // Set up interrupt handler mcf5282_interrupt_init(44, ipl, handler); // Set modulo count // (= number of ticks per interrupt) MCF5282_GPTA_GPTC0 = PMR; // Tick frequency = (system clock/2) divided by 2^PCSR MCF5282_GPTA_GPTSCR2  = (uint16)(MCF5282_GPT_GPTSCR2_PR(PCSR)); MCF5282_GPTA_GPTIOS = MCF5282_GPT_GPTIOS_IOS0; MCF5282_GPTA_GPTIE = MCF5282_GPT_GPTIE_C0I; MCF5282_GPTA_GPTFLG1 = MCF5282_GPT_GPTFLG1_C0F; MCF5282_GPTA_GPTFLG2 = MCF5282_GPT_GPTFLG2_TOF | MCF5282_GPT_GPTFLG2_C0F; // Enable timer A MCF5282_GPTA_GPTSCR1 = MCF5282_GPT_GPTSCR1_GPTEN;}

 
ISR:
 
Code:
/******************************************************************** * FUNCTION: gpt_timer_isr() * * GPTA0 interrupt handler, set to be called at 1ms intervals * * PARAMS: none * * RETURNS: none */__attribute__((interrupt_handler))voidgpt_timer_isr(void){ // Clear interrupt MCF5282_GPTA_GPTFLG1 = MCF5282_GPT_GPTFLG1_C0F;}

 
Configure it like this:
 
Code:
GPTA_Timer_Init(5, 10000, gpt_timer_isr);

 
Cheers,
 
Paul.
 
 
0 Kudos

283 Views
mccPaul
Contributor I
Hi
 
I am not sure if the GPT is better for your application than a Programmable Interrupt Timer - it seems like you just want to generate an interrupt every 1ms so a PIT would be easier. Of course, you may be using a part with no PIT.
 
I haven't used GPT, but I have included below code that will set up PITs and ISRs for them. If you need to use a GPT, then it shouldn't be too difficult to adapt this. My code is for mcf5282, but I know it also works on mcf52235.
 
When I looked at you code, I noticed that your set the interrupt level and priority to 7 - this level is non-maskable. Unless your ISR happens to need an NMI, a lower level may be better.
 
I also noticed that you haven't set a vector for the ISR, is this hardcoded in your vectors? If not, you must set the correct vector. I have included source for a C function that will both set the vector and the interrupt mask. (all code samples belowe are aimed at GCC, but should be portable to CW).
 
First, timer initialisation, adapt this for GPT:
 
Code:
/* FUNCTION: PIT_Timer_Init() * * Initialise and enable a Programmable Interval Timer * * PARAM1: PIT - can be 0, 1, 2 or 3 * * PARAM2: Prescaler value - sets the tick frequency to *     (system clock/2) divided by 2^PCSR * * PARAM3: Modulo counter - sets the mumber of ticks per interrupt * * PARAM4: Interrupt handler * * RETURNS: none */voidPIT_Timer_Init(uint8 timer, uint8 PCSR, uint16 PMR, void (*handler)(void)){ // At 64MHz: // PCSR = 5 gives a tick per uS // PMR = 10000 gives an interrupt every 10ms if (timer < 4) {  uint8 ipl = MCF5282_INTC_ICR_IL(TIMER_NETWORK_LEVEL)     | MCF5282_INTC_ICR_IP(timer);  MCF5282_PIT_PCSR(timer) = 0;  // Set up interrupt handler  mcf5282_interrupt_init(timer + 55, ipl, handler);  // Set modulo count  // (= number of ticks per interrupt)  MCF5282_PIT_PMR(timer) = PMR;  // Tick frequency = (system clock/2) divided by 2^PCSR  MCF5282_PIT_PCSR(timer)  = (uint16)(MCF5282_PIT_PCSR_PRE(PCSR));  // Create and enable 'set and forget' timer  MCF5282_PIT_PCSR(timer) |= MCF5282_PIT_PCSR_OVW         | MCF5282_PIT_PCSR_PIE         | MCF5282_PIT_PCSR_PIF         | MCF5282_PIT_PCSR_RLD         | MCF5282_PIT_PCSR_EN; }}/* FUNCTION: PIT_Timer_Stop() * * Disable timer interrupts for the specified PIT * * PARAM1: PIT - can be 0, 1, 2 or 3 * * RETURNS: none */voidPIT_Timer_Stop(uint8 timer){ if (timer < 4)  MCF5282_PIT_PCSR(timer) &= ~( MCF5282_PIT_PCSR_PIE | MCF5282_PIT_PCSR_EN );}

 
Second, set up the interrupt vector and enable the interrupt in the interrupt controller:
 
Code:
/* FUNCTION: mcf5282_interrupt_init() * * Initialise an interrupt handler for an interrupt source * for INTC0. If the handler is a NULL pointer, then mask * this interrupt. * * PARAM1: Interrupt source (1..62) * * PARAM2: Interrupt level and priority * * PARAM3: Interrupt handler * * RETURNS: none */voidmcf5282_interrupt_init(uint8 source, uint8 ipl, void (*handler)(void)){ // Only for user defined vectors in INTC0 if ((source > 0) && (source < 63)) {  // Interrupts should be disabled to avoid vector problems  // and to ensure that a spurious interrupt exception can't  // be generated.  uint8 sysint = asm_set_ipl(7);  if (handler)  {   // Set interrupt priority level   MCF5282_INTC0_ICR(source) = (ipl & 0x3F);   // Set vector   mcf5xxx_set_handler(source+64, (ADDRESS)handler);   // Clear mask for this handler   if (source < 32)    MCF5282_INTC0_IMRL &= ~(MCF5282_INTC_IMRL_INT(source)          | MCF5282_INTC_IMRL_MASKALL);   else   {    MCF5282_INTC0_IMRL &= ~(MCF5282_INTC_IMRL_MASKALL);    MCF5282_INTC0_IMRH &= ~(MCF5282_INTC_IMRH_INT(source));   }  }  else  {   // Set vector   mcf5xxx_set_handler(source+64, (ADDRESS)handler);   // Set mask for this handler   if (source < 32)   {    MCF5282_INTC0_IMRL |= MCF5282_INTC_IMRL_INT(source);   }   else   {    MCF5282_INTC0_IMRH |= MCF5282_INTC_IMRH_INT(source);   }  }  // As you were...  asm_set_ipl(sysint); }}/********************************************************************/

 
In case you need it, this is the assembler for the function that masks interrupts in the SR, used while the interrupt vectors and masks are being modified:
 
Code:
/********************************************************************//* * This routines changes the IPL to the value passed into the routine. * It also returns the old IPL value back. * Calling convention from C: *   old_ipl = asm_set_ipl(new_ipl); * For the Diab Data C compiler, it passes return value thru D0. * Note that only the least significant three bits of the passed * value are used. */asm_set_ipl:_asm_set_ipl:    link    A6,#-8    movem.l D6-D7,(SP)    move.w  SR,D7       /* current sr    */    move.l  D7,D0       /* prepare return value  */    andi.l  #0x0700,D0  /* mask out IPL  */    lsr.l   #8,D0       /* IPL   */    move.l  8(A6),D6    /* get argument  */    andi.l  #0x07,D6        /* least significant three bits  */    lsl.l   #8,D6       /* move over to make mask    */    andi.l  #0x0000F8FF,D7  /* zero out current IPL  */    or.l    D6,D7           /* place new IPL in sr   */    move.w  D7,SR    movem.l (SP),D6-D7    lea     8(SP),SP    unlk    A6    rts

 
And the interrupt handler (note that __attribute__((interrupt_handler)) is GCC specific, you need to change for CW):
 
Code:
/******************************************************************** * FUNCTION: hz_timer_isr() * * PIT2 interrupt handler, set to be called at 1 second intervals * * PARAMS: none * * RETURNS: none * * Used for updating rate counters for bit rates, etc. */__attribute__((interrupt_handler))voidhz_timer_isr(void){ // Do something...  // Clear interrupt at CSR MCF5282_PIT_PCSR(HZ_TIMER) |= MCF5282_PIT_PCSR_PIF;}

 And finally, put this call somewhere to set up a timer (this is to create a timer that is called at 1 second intervals on a mcf5282 running at 64MHz, change the values to get a 1ms timer):
 
Code:
 // We are assuming that sys_clk is 64MHz // so PCSR = 11 gives 15625 ticks per second. PIT_Timer_Init(HZ_TIMER, 11, 15625, hz_timer_isr);

 
 
Cheers,
 
Paul.
0 Kudos