MC68HC908GP32CP Changing output on TIM interrupt

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

MC68HC908GP32CP Changing output on TIM interrupt

3,639 Views
pmouse
Contributor I
Hey all,
I have a HC908GP32 chip that I want to use to generate two PWM signal
to drive two motors, and also generate a pulse signal for a LED. The
two PWM signal can be generated by TIM output compare, but since there
is only 2 output pins for the TIM1 on the CP package, TIM2 cannot be
config directly to generate the pulse for LED.

Therefore I have config TIM2CH0 to "software compare", and in the
interrupt generated, I toggle a selected output pin (say PTA_PTA3) by
the code:
PTA_PTA3 =~ PTA_PTA3;

However, when I measure the output on PTA3, there is nothing.

The chip is driven by an external 9.8304MHZ crystal. The PLL is disabled.

So to test my concept is really working, I have enabled TIM1CH0 and TIM1CH1's channel interrupt, and in the ISR I have the same code as above on different pins, i.e.,
PTE_PTE0 =~ PTE_PTE0;

I then go and measured the output. I have discovered that TIM1CH0's interrupt toggles PTE_PTE0 every 11.8us (but the channel overflow period is 1.3ms, channel compare is 50% of the channel mod). Further more, TIM1CH1's interrupt seems to be not working, there is nothing measured on PTE_PTE1, and nothing on PTA_PTA3 either.

This leads me to believe the timer is acting funny, so I measured the actual channel output pin on PTD_PTD5/6, their period is 1.3ms exactly. So the timer is differently generating PWM signal fine, it's just that the interrupts are weird.

So I'm really confused by the result. Can someone explain to me why this is happening. How the TIM module interrupt work, and what is the interrupt frequency? Can I generate 2 actively monitored PWM signals and one fixed frequency/duty cycle pulse signal on this particular MCU?

Regards,

PQ
Labels (1)
0 Kudos
10 Replies

802 Views
pmouse
Contributor I

Hello All,

  Here's the code that generates the pulse on PTE, the output measured on PTE_PTE0 is a square wave with a period of 11us, and the output measured on PTE_PTE1 is 0 at all time.

Regards,

PQ

 

/*
** ###################################################################
**     This code is generated by the Device Initialization Tool.
**     It is overwritten during code generation.
**     USER MODIFICATION ARE PRESERVED ONLY INSIDE INTERRUPT SERVICE ROUTINES
**
**     Project   : PeterQian
**     Processor : MC68HC908GP32CP
**     Version   : Bean 01.110, Driver 01.00, CPU db: 2.89.061
**     Datasheet : MC68HC908GP32 Rev. 7 03/2006
**     Date/Time : 29/10/2007, 11:30 AM
**     Abstract  :
**         This bean "MC68HC908GP32_40" provides initialization of the
**         CPU core and shared peripherals.
**     Settings  :
**         Clock setting
**             External clock      : 9.8304 MHz
**             CPU mode selection  : 1
**             Initialization interrupt priority : 1
**             Stop instruction enabled : no
**             LVI module          : yes
**
**             Source clock        : Main clock frequency / 1
**             Internal bus clock  : 2.4576 MHz
**     Contents  :
**         Function "MCU_init" initializes selected peripherals
**
**     (c) Copyright UNIS, spol. s r.o. 1997-2006
**     UNIS, spol s r.o.
**     Jundrovska 33
**     624 00 Brno
**     Czech Republic
**     http      :
www.processorexpert.com
**     mail      : info@processorexpert.com
** ###################################################################
*/

#include <MC68HC908GP32.h>             /* I/O map for MC68HC908GP32CP */


#define CGM_DELAY  0x27FFUL

/*
** ===================================================================
**     Method      :  MCU_init (bean MC68HC908GP32_40)
**
**     Description :
**         Device initialization code for selected peripherals.
** ===================================================================
*/
void MCU_init(void)
{

/*** ### MC68HC908GP32_40 "Cpu" init code ... ***/
/*** PE initialization code after reset ***/
/* System clock initialization */

  /* Common initialization of the write once registers */
  /* CONFIG1: COPRS=0,LVISTOP=0,LVIRSTD=0,LVIPWRD=0,LVI5OR3=0,SSREC=0,STOP=0,COPD=1 */
  CONFIG1 = 0x01;                                     
  /* CONFIG2: OSCSTOPENB=0,SCIBDsrc=0 */
  CONFIG2 = 0x00;                                     
  /* Common initialization of the CPU registers */
  /* PTDPUE: PTDPUE5=0,PTDPUE4=0 */
  PTDPUE &= (unsigned char)~0x30;                    
  /* ### Init_GPIO init code */
  /* PTE: PTE1=0,PTE0=0 */
  PTE &= (unsigned char)~0x03;                    
  /* DDRE: DDRE1=1,DDRE0=1 */
  DDRE |= (unsigned char)0x03;                              
  /* ### Init_TIM init code */
  /* T1SC: TOF=0,TOIE=0,TSTOP=1,TRST=1,PS2=0,PS1=0,PS0=0 */
  T1SC = 0x30;                         /* Stop and reset counter */
  T1CH0 = 0x0190;                      /* Compare 0 value setting */
  (void)(T1SC0 == 0);                  /* Channel 0 int. flag clearing (First part) */
  /* T1SC0: CH0F=0,CH0IE=1,MS0B=0,MS0A=1,ELS0B=1,ELS0A=1,TOV0=1,CH0MAX=0 */
  T1SC0 = 0x5E;                        /* Int. flag clearing (2nd part) and  channel contr. register setting */
  T1CH1 = 0xFA;                        /* Compare 1 value setting */
  (void)(T1SC1 == 0);                  /* Channel 1 int. flag clearing (First part) */
  /* T1SC1: CH1F=0,CH1IE=1,MS1A=1,ELS1B=0,ELS1A=1,TOV1=1,CH1MAX=0 */
  T1SC1 = 0x56;                        /* Int. flag clearing (2nd part) and  channel contr. register setting */
  T1MOD = 0x0320;                      /* Period value setting */
  (void)(T1SC == 0);                   /* Overflow int. flag clearing (first part) */
  /* T1SC: TOF=0,TOIE=1,TSTOP=0,TRST=0,PS2=0,PS1=1,PS0=0 */
  T1SC = 0x42;                         /* Int. flag clearing (2nd part) and timer contr. register setting */
  /* ### */
  asm CLI;                             /* Enable interrupts */
} /*MCU_init*/


/*
** ===================================================================
**     Interrupt handler : isrINT_TIM1Ovr
**
**     Description :
**         User interrupt service routine.
**     Parameters  : None
**     Returns     : Nothing
** ===================================================================
*/
__interrupt void isrINT_TIM1Ovr(void)
{
  /* Write your interrupt code here ... */
 
  // PTA_PTA3 = ~PTA_PTA3

}
/* end of isrINT_TIM1Ovr */


/*
** ===================================================================
**     Interrupt handler : isrINT_TIM1CH1
**
**     Description :
**         User interrupt service routine.
**     Parameters  : None
**     Returns     : Nothing
** ===================================================================
*/
__interrupt void isrINT_TIM1CH1(void)
{
  /* Write your interrupt code here ... */
  PTE_PTE1 =~PTE_PTE1;

}
/* end of isrINT_TIM1CH1 */


/*
** ===================================================================
**     Interrupt handler : isrINT_TIM1CH0
**
**     Description :
**         User interrupt service routine.
**     Parameters  : None
**     Returns     : Nothing
** ===================================================================
*/
__interrupt void isrINT_TIM1CH0(void)
{
  /* Write your interrupt code here ... */ 
  PTE_PTE0 =~PTE_PTE0;

}
/* end of isrINT_TIM1CH0 */

 

/* Initialization of the CPU registers in FLASH */

 

#define UNASSIGNED_ISR 0xFFFF          /* Unassigned interrupt service routine */

extern void _Startup(void);            /* reset interrupt service routine */

void (* const _vect[])() @0xFFDC = {   // Interrupt vector table
        UNASSIGNED_ISR,                /* Int.no.  0 INT_TBM (at FFDC)               Unassigned */
        UNASSIGNED_ISR,                /* Int.no.  1 INT_ADC (at FFDE)               Unassigned */
        UNASSIGNED_ISR,                /* Int.no.  2 INT_KBD (at FFE0)               Unassigned */
        UNASSIGNED_ISR,                /* Int.no.  3 INT_SCITransmit (at FFE2)       Unassigned */
        UNASSIGNED_ISR,                /* Int.no.  4 INT_SCIReceive (at FFE4)        Unassigned */
        UNASSIGNED_ISR,                /* Int.no.  5 INT_SCIError (at FFE6)          Unassigned */
        UNASSIGNED_ISR,                /* Int.no.  6 INT_SPITransmit (at FFE8)       Unassigned */
        UNASSIGNED_ISR,                /* Int.no.  7 INT_SPIReceive (at FFEA)        Unassigned */
        UNASSIGNED_ISR,                /* Int.no.  8 INT_TIM2Ovr (at FFEC)           Unassigned */
        UNASSIGNED_ISR,                /* Int.no.  9 INT_TIM2CH1 (at FFEE)           Unassigned */
        UNASSIGNED_ISR,                /* Int.no. 10 INT_TIM2CH0 (at FFF0)           Unassigned */
        isrINT_TIM1Ovr,                /* Int.no. 11 INT_TIM1Ovr (at FFF2)           Used */
        isrINT_TIM1CH1,                /* Int.no. 12 INT_TIM1CH1 (at FFF4)           Used */
        isrINT_TIM1CH0,                /* Int.no. 13 INT_TIM1CH0 (at FFF6)           Used */
        UNASSIGNED_ISR,                /* Int.no. 14 INT_PLL (at FFF8)               Unassigned */
        UNASSIGNED_ISR,                /* Int.no. 15 INT_IRQ (at FFFA)               Unassigned */
        UNASSIGNED_ISR,                /* Int.no. 16 INT_SWI (at FFFC)               Unassigned */
        _Startup                       /* Int.no. 17 INT_RESET (at FFFE)             Reset vector */
};


/* END */

/*
** ###################################################################
**
**     This file was created by UNIS Processor Expert 3.00 [03.89]
**     for the Freescale HC08 series of microcontrollers.
**
** ###################################################################
*/

0 Kudos

802 Views
peg
Senior Contributor IV
Hi Peter,
 
Without going into whether you are doing this the best way (others have already made suggestions here), the reason your interrupts are not working properly is that you are not resetting the flags that generate them.
You need to read the register that contains the flag and then write a zero to the bit to clear it and allow it to trip again next time.
For the overflow you read T1SC then clear bit 7 and,
for the compare you read T1SC1 then clear bit 7
This would normally be done within each corresponding ISR.
You can see where PE has done this in the initialisation routine.
Add the appropriate read then clear to each ISR and see how you go then.
 
0 Kudos

802 Views
pmouse
Contributor I
Thank you all for your replies! I knew the interrupt has to be cleared somehow, but just don't know how. I have read some application notes and in their source code they never cleared the interrupt flag. Hence I assumed that it doesn't need to be done. I'll try the suggestion tomorrow.

Regards,

PQ

Message Edited by pmouse on 2007-10-30 09:57 PM
0 Kudos

802 Views
pmouse
Contributor I
Hey guys,
The timers are now working. Thanks a lot!
However, I'm now having trouble handling the interrupt from the ADC. I believe it is the same problem, ie., you need to clear a flag somewhere.
How do you find out which flag to clear? the product documentation does not mention this clearly.

Regards,

PQ
0 Kudos

802 Views
peg
Senior Contributor IV
Hi,
 
Here is the relevant location in the manual that tells you this:
 

AIEN — ADC Interrupt Enable Bit

When this bit is set, an interrupt is generated at the end of an ADC conversion. The interrupt signal is cleared when the data register is read or the status/control register is written. Reset clears the AIEN bit.

1 = ADC interrupt enabled

0 = ADC interrupt disabled

 

This should be fairly automatic in most cases as you would probably read from these anyway. However a trap for you if you don't.

 

0 Kudos

802 Views
PeterHouse
Contributor I
Usually it is as simple as reading the data register of the generating source.  Sometime it is more complicated.  It is clear in the manual once you learn where and what to look for as you are doing now.

Good Luck,

Peter House
0 Kudos

802 Views
Ake
Contributor II
Hi,
I have not studied your messag closely but I would try to use the PWM mode instead of the Output Compare, that is I would use the T1MOD register to set the pulse width, instead of calculating where the next interrupt should be.
 
If you just wanted to flash a LED, wouldn't the TBM work fine instead?
 
Regards,
Ake
0 Kudos

802 Views
PeterHouse
Contributor I
A simple method I have used in the past is to use code in the output compare interrupt to turn the LED on and code in the Timer Overflow Interrupt to turn it off.  Your main code will then only need to set the Output compare register to adjust the duty factor. 

If you set the Timer Modulus to a binary factor of 256, you can use a value of 0-255 to control the PWM and merely shift it left to calculate the Output Compare register value.  Choose your dividers for the slowest count where the LED does not flicker to minimize EMI.

Good Luck,

Peter House
0 Kudos

802 Views
pmouse
Contributor I
Hey all,
Thanks for the replies. I have tried all the above methods before, but none really worked. The main concern of me right now is that either the timer interrupt don't fire, or it fires too fast. I've configuated TIM1 to have a overflow period of 1.3ms, but the overflow interrupt never occurs, and the TIM1CH0 interrupt happens every 11 microseconds. Despite this the channel output on PTD_PTD5 has a period of exactly 1.3ms, so the timer is definitely working.
I'll post the mcu_config and the ISR code here later.
I'm also wondering, to toggle a pin, is there any harm to do:
PTA_PTA0=~PTA_PTA0
versus
PTA ^= 0x1

Regards

PQ
0 Kudos

802 Views
bigmac
Specialist III
Hello PQ,
 
Welcome to the forum.
It is difficult to visualize your problem without seeing the code you are using.
 
I assume you would setup for unbuffered PWM output from each of the TIM1 channels, where the PWM frequency for both channels is determined by the TMOD register setting.  Whenever the pulse width setting is to be altered, this would need to be accomplished within the ISR for the associated channel (because of unbuffered PWM mode).
 
Since it appears that your intended timer overflow period is 1.3ms, I would assume that your LED flash rate would need to be a multiple of this period.  So you would need to count each timer overflow to determine when the LED state should be toggled.  LED control could be accomplished from either one of the channel ISRs, but you also might handle separately within the TIM1 overflow ISR - this would probably be my personal preference.
 
The ISR, whichever one you are using, might contain the following LED control code:
 
tcount--;
if (tcount == 0) {
   tcount = 154;  /* 200ms LED flash period */
   PTA ^= 0x08;   /* Toggle PTA3 output */
}
 
where tcount is defined as a global value, 8 or 16 bits depending on the LED flash period that you require..
 
Of course, PTA3 pin would need to be initialised as an output.
 
Regards,
Mac


Message Edited by bigmac on 2007-10-30 04:03 PM
0 Kudos