How can I stop a timer?

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

How can I stop a timer?

3,230 Views
J_R
Contributor I
I have made a small radio sw, using SMAC for the MC1321 chip (HCS08). The whole system consists of one send unit and one receiver unit.
 
I'm using a timer to time out if messages stops comming in on the receiver side.
So when I receive a message I have to stop the timer and then restart it, but I cannot make it work. Once the timer is initiated and started it allways calls the ISR, even if i try to stop it before!
 
Can anyone see the error??
 
-------------------------------
 
void TimerInit(void)
{
  TPM1C0SC = 0x07 |  // prescale divisor = 128
             0x10;   // fixed system clock
       
  TPM1SC = 0x07 |  // prescale divisor = 128
           0x10;   // fixed system clock 
}
 
void TimerStart(unsigned char modH, unsigned char modL)
{
  TPM1MODH = modH;
  TPM1MODL = modL;
  TPM1C0SC |= 0x40;   // interrupt enable
}

void TimerClear(void)
{
  if(TPM1C0SC & 0x80)
    TPM1C0SC &= ~0x80;
}

void TimerStop(void)
{
  TPM1SC = 0x00;
}
 
interrupt void TimerISR(void)
{
  // We have a timeout!
  TimerClear();
  TimerStop();
  // Do stuff  
}
 
// MCPSDataIndication is called when data is received on the radio
void MCPSDataIndication(tRxPacket *gsRxPacket)
{
    TimerClear();
    TimerStop();
           
    if (gsRxPacket->u8Status == SUCCESS)
    {
 
       TimerStart(); // Restart the timer
 
 
Labels (1)
0 Kudos
Reply
8 Replies

1,055 Views
J_R
Contributor I
Hello!
Yes the problem is that I haven't understood what the "TPM channel"-stuff is.
For instance, if I use the TPM alone:
* How can I TPM interrupts without using the channels? I can se no place for the
isr in the vector table (only for "TPM channel"-isr's).
* The bit 5 in TPM1SC lets me chose from 2 different channel operating modes. But I
cannot se that I can chose to not use the cannels at all.

If I use the TPM with channels:
* I still have to set TPM1SC = 0x17 won't I? (I never get the TPM channel interrupt
if I don't). This solution works for me, but maybe I'm doing something wrong
anyway...

-------------------------------
My current code:
void TimerInit(void)
{
  TPM1C0SC = 0x10; // Use output compare
       
  TPM1SC = 0x07 |  // prescale divisor = 128
           0x10;   // fixed system clock 
}

void TimerStart(unsigned char high, unsigned char low)
{
  TPM1C0VH = high;
  TPM1C0VL = low;
  TPM1C0SC |= 0x40; // interrupt enable
}

void ClearTimerRegisters(void)
{
 TPM1SC   = 0x00;
 TPM1C0SC = 0x00;
 TPM1CNTH = 0x00;
 TPM1CNTL = 0x00;
 TPM1C0VH = 0x00;
 TPM1C0VL = 0x00;
 TPM1MODH = 0x00;
 TPM1MODL = 0x00;
}

interrupt void TimerISR(void)
{
  TPM1C0SC  &= ~0x80; //clear overflow flag
  TPM1C0SC  &= ~0x40; //clear enable
  // Do stuff
  ...
}

void MCPSDataIndication(tRxPacket *gsRxPacket)
{
    /*
     * Place your code here to handle a mac layer data indication.
     * RX packet is in the global structure
     * gsRxPacket.dataLength and gsRxPacket.data
  */
    ClearTimerRegisters(); // Stops the timer
   
    if (gsRxPacket->u8Status == SUCCESS)
    {
       // Do stuff
       ...
       // Start the timer that is used to check if messages stops comming
       TimerInit();
       TimerStart(0x22, 0x22);
       ...
 
-------------------------
 
Again, thanks for your replies!
 
/_JR_
0 Kudos
Reply

1,055 Views
bigmac
Specialist III
Hello JR,
 
I will briefly attempt to describe the basic operation ot the TPM module, hopefully to clear up some of the confusion.
 
The module consists of a 16-bit counter that runs continuously during normal operation.  Whenever the count value reaches the value contained within TPM1MOD, an overflow event occurs, and the counter will begin counting from zero at the next (prescaled) timer clock.  The overflow will generate an interrupt if the TOIE bit within the TPM1SC register is set.  The TOF flag within the same register will be set, whether or not the interrupt is enabled.
 
Even if you are not specifically using the TPM overflow facility, the TPM1SC register also controls the pre-scaler setting and the clock source selection, so will usually need to be initialized.  Many applications may leave the TPM1MOD setting at the reset default setting, for a full 16-bit count.
 
Associated with the TPM are a number of "channels" that operate quite independently of the timer overflow, but their operation will be affected by the TPM1MOD setting.  Each channel may be configured for one of the operating modes,
1)  Input capture, or
2)  Output compare with hardware output, or
3)  Output compare, interrupt only, or
4)  PWM operation, either edge aligned or centre aligned.
 
If the meaning of any of these operations is unclear, perhaps you should re-read the relevant paragraphs in the data sheet.  For channel 0, the mode of operation is controlled by the TPM1C0SC register.  If none of these operating modes are needed, the register can remain at the default setting.
 
An interrupt vector is provided for each channel, and a separate vector for overflow interrupts.
 
To provide a timeout delay as you require, the method used will depend on the length of the delay, and the accuracy required for the delay.  The output compare method can be very accurate, especially for a hardware output, but becomes more complex if the required delay exceeds the overflow period.
 
If the required delay is quite long, and is many times the overflow period, a very simple method is to count the number of overflows.  If the timer runs continuously, and is not reset, the timing uncertainty will be one overflow period.
 
I suspect that, for your specific application, high accuracy is not a requirement, and since you have a prescale division of 128, the second method may suffice if you were to reduce the prescale setting to 1.
 
word Tcount = 0;  /* Global variable */
 
void TPM_Init(void)
{
  TPM1SC = 0x50; /* prescale = 1, fixed system clock,
                    Overflow interrupt enabled */
}

 

void SetTimeout( word val)
{
  Tcount = val;  /* Multiple of TPM overflow period */
}

 
interrupt void TPM_Overflow_ISR(void)
{
  TPM1SC_TOF = 0;  /* Clear overflow flag */
  if (Tcount) {
    Tcount--;
    if (Tcount == 0) {
 
    /* Do timeout stuff */
 
    }
  }
}
 
If the action required on timeout is complex and lengty, it is probably not a good idea to execute within the ISR code.  The alternative is, within main() or an associated function, to periodically poll the value of Tcount.  When it reaches zero, the value will remain at zero to indicate that timeout has occurred.
 
Regards,
Mac



Message Edited by bigmac on 2008-02-07 11:55 PM
0 Kudos
Reply

1,055 Views
Ake
Contributor II
Hi again,
I looked at your original message and saw that you used "SMAC for the MC1321 chip".
I looked up the MC1321, and found that this is somekind or a transmitter/reciever  connected to a 9S08 made by Freescale.
But I could not find what kind of 9S08 is used.
My question is, where did you get the source code?
Did you write it yourself or is it from an application note?
 
I really must apologize, I am supposed to "know" the HC908/9S08 MCUs but I have not heard about the MC1321 chips before.
 
Regards,
Ake
0 Kudos
Reply

1,055 Views
J_R
Contributor I
Thanks for the fast reply!
I've got it working though, before I saw your reply.
I think that I'd better have a look into what you have written though.
 
This is how I've solved it:
--------------------------------------------
 
void TimerInit(void)
{
  TPM1C0SC = 0x07 |  // prescale divisor = 128
             0x10;   // fixed system clock
       
  TPM1SC = 0x07 |  // prescale divisor = 128
           0x10;   // fixed system clock 
}

void TimerStart(unsigned char modH, unsigned char modL)
{
  TPM1MODH = modH;
  TPM1MODL = modL;
  TPM1C0SC |= 0x40;   // interrupt enable
}
 
void ClearTimerRegisters(void)
{
 TPM1SC   = 0x00;
 TPM1C0SC = 0x00;
 TPM1CNTH = 0x00;
 TPM1CNTL = 0x00;
 TPM1C0VH = 0x00;
 TPM1C0VL = 0x00;
 TPM1MODH = 0x00;
 TPM1MODL = 0x00;
}
 
interrupt void TimerISR(void)
{
  TPM1C0SC  &= ~0x80; //clear overflow flag
  TPM1C0SC  &= ~0x40; //clear enable
  LED4 = ~LED4; //TEMP
 
  receivedCommand = NO_COMMAND;
}
 
void MCPSDataIndication(tRxPacket *gsRxPacket)
{
    ClearTimerRegisters(); // Stops the timer
 
    if (gsRxPacket->u8Status == SUCCESS)
    {
       TimerInit();
       TimerStart(); // Restart the timer
....
 
 
--------------------------------------------
 
By the way, I use the Freescale refecence board MC1321x.
0 Kudos
Reply

1,055 Views
Ake
Contributor II
Hi,
I understand that it is an 9S08 MCU in your dev tool.
 
But I must say that the TimerInit() routine is quite strange
 
void TimerInit(void)
{
  TPM1C0SC = 0x07 |  // prescale divisor = 128
             0x10;   // fixed system clock
 
This line write 0x17 to  TPM1C0SC. So it sets the MS0B and the ELS0A bit. It also tries to set bit 0 and 1 which are always 0.
The clock has not stopped. No interrupts are enabled. 
       
  TPM1SC = 0x07 |  // prescale divisor = 128
           0x10;   // fixed system clock 
 
This line writes 0x17 to TPM1SC. So it sets the CLKSB and the CLKSA and the PS2 bit.
This means that the external source is for the timer clock and it is divided by 16 before using it.
 
Where did you get this code from?
Is it from Freescale? Then it must be a new version of 9S08 that I have never heard of.
 
Regards,
Ake

}
0 Kudos
Reply

1,055 Views
bigmac
Specialist III
Hello,
 
It appears that there may be some confusion between the registers TPM1SC and TPM1C0SC, as suggested by the comments within the code.  The actual method used to generate the time interval seems muddled.  I suspect that the intent is to use overflow of the TPM module (the actual interrupt that the ISR refers seems unclear).  This is suggested by the change of the TPM1MOD value.  If this is the case, it is unnecessary to write anything to TPM1C0SC register, since TPM channels are not used in the process.  The TPM1C0SC value could remain at the reset default.
 
An alternative timing method would be to use a TPM channel in output compare, interrupt only mode.  Typically, this method would operate with the TPM module in free running mode.  There would be no need to stop the TPM, nor alter the modulo value.  This would be the preferred method because it does not affect usage of other TPM channels.
 
A minor point, when setting the TPM1MOD value, you can directly write a 16-bit value, rather than two 8-bit values.  This should simplify the code a little bit.
 
Regards,
Mac
 
0 Kudos
Reply

1,055 Views
Ake
Contributor II
Hi,
It seems that you have mixed the TPM and the TIM module.
If you look at the first routine, the TimerInit(), your registers start with TPM, but for eg the first line
  TPM1C0SC = 0x07 |  // prescale divisor = 128
             0x10;   // fixed system clock
....does not make any sense at all.
It should either be
  TPM1SC = 0x07 |  // prescale divisor = 128
             0x0;   // to stop the clock
or....
  TSC = 0x07 |  // prescale divisor = 128
             0x10;   // to stop the clock
What kind of MCU are you using?
 
Regards,
Ake

 

 

TPM1CSC
 
 assume that you are using the HC908 TIM module. With the 9S08 TPM module, the bits are a bit different,
 
First the routine...
 
void TimerInit(void)
{
  TPM1C0SC = 0x07 |  // prescale divisor = 128
             0x10;   // fixed system clock
       
  TPM1SC = 0x07 |  // prescale divisor = 128
           0x10;   // fixed system clock 
}
....is wrong. It should be
void TimerInit(void)
{
  TPM1CSC = 0x07 |  // prescale divisor = 128
             0x10;   // fixed system clock
  TPM 
      
  TPM1SC = 0x07 |  // prescale divisor = 128
           0x10;   // fixed system clock 
}
0 Kudos
Reply

1,055 Views
Ake
Contributor II
Hi,
Oops, I forgot to remove some of my earlier corrections. This is how my message should look like:
 
It seems that you have mixed the TPM and the TIM module.
If you look at the first routine, the TimerInit(), your registers start with TPM, but for eg the first line
  TPM1C0SC = 0x07 |  // prescale divisor = 128
             0x10;   // fixed system clock
....does not make any sense at all.
It should either be
  TPM1SC = 0x07 |  // prescale divisor = 128
             0x0;   // to stop the clock
or....
  TSC = 0x07 |  // prescale divisor = 128
             0x10;   // to stop the clock
What kind of MCU are you using?
 
Regards,
Ake

 

0 Kudos
Reply