S12G128 Timer Overflow Interrupt

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

S12G128 Timer Overflow Interrupt

Jump to solution
3,032 Views
rayhall
Contributor V

I am trying to make a overflow timer interrupt to work. This is my code that just locks up when run. What am I going wrong ?

 

Ray.

 

void main(void) {

 

  DDRT = 0x30;

  PTT_PTT5 = 0x01;

 

  TSCR1 = 0x80;    // Enable Timer.with legacy prescaler

  TSCR2 = 0x80;   // Overflow Interrupt with 1 prescaler   

 

  EnableInterrupts;

 

  for(;;) {

 

  FEED_COP(); /* feeds the dog */

  } /* loop forever */

 

}

 

#pragma CODE_SEG NON_BANKED

interrupt 8 void TI1_Interrupt(void)

{

  TFLG1 = 0x01U;        // Reset interrupt request flag

  PTT_PTT5 = ~PTT_PTT5; //toggle LED on PT5 

}

 

#pragma CODE_SEG DEFAULT

Labels (1)
0 Kudos
1 Solution
2,012 Views
rayhall
Contributor V

I have solved the problem. I had two errors.

1. Interrupt vector is 16 not 8.

2. The clear interrupt flag is TFLG2 not TFLG1.

This is correct,

#pragma CODE_SEG NON_BANKED

interrupt 16 void TIM0_ISR(void)

{

  TFLG2 = 0x80;                     /* Reset interrupt request flag */ 

}

#pragma CODE_SEG DEFAULT

View solution in original post

0 Kudos
18 Replies
2,013 Views
rayhall
Contributor V

I have solved the problem. I had two errors.

1. Interrupt vector is 16 not 8.

2. The clear interrupt flag is TFLG2 not TFLG1.

This is correct,

#pragma CODE_SEG NON_BANKED

interrupt 16 void TIM0_ISR(void)

{

  TFLG2 = 0x80;                     /* Reset interrupt request flag */ 

}

#pragma CODE_SEG DEFAULT

0 Kudos
2,012 Views
RadekS
NXP Employee
NXP Employee

Hi Ray,

You are right. In attachment you can find simple example code for period time measuring.

Note: Example code was designed for S12XDP512, however timer module structure is almost the same and it should work also at S12G.

Note: Example codes for S12G are here:

S12G Examples Pack


I hope it helps you.

Have a great day,
RadekS

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos
2,012 Views
lukmankurniawan
Contributor II

Hello Radek,

I just saw your example using timer interrupt. Based on your example if I am not wrong, you are using input capture using rising edge and every time any incoming pulse trough channel 1 it will increase the overflow value, am I correct?

Actually I have an application to count the digital pulse coming using interrupt (can be rising edge or falling edge detection). Is this example suitable for that? And on your example were using "interrupt 16 void TIM0_ISR(void)" and "interrupt 8 void IC0_ISR(void)", why on my codewarrior v5.9.0 has error? and when I change only use "interrupt void TIM0_ISR(void)" and "interrupt  void IC0_ISR(void)" the error disappear?

I appreciate your answer.

Best Regards,

Lukman

0 Kudos
2,012 Views
RadekS
NXP Employee
NXP Employee

Hi Lukman,

Actually, the example use timer channel 0 for capturing TCNT value when a rising edge appears on timer channel 0 pin.

Additionally, there is timer overflow interrupt TOI_ISR which is triggered by TCNT overflow from 0xFFFF to 0x0000.

This solution is necessary when the time between rising edges may be higher than the timer overflow period. 

The above-attached example was created for an S12XD family.

The interrupt channels (like 8 or 16) may be different for your MCU derivative.

Please check Table "Interrupt Vector Locations" in the appropriate Reference Manual.

The "interrupt 16 void TIM0_ISR(void)" is one of the possible interrupt routine definitions (probably simplest one).

"16" means here interrupt vector 16 - Enhanced capture timer overflow at address 0xFFDE (0xFFFE-(2bytes*16) = 0xFFFE-0x20=0xFFDE).

If you use vector assignment in prm linker file, you don't need to use the vector number in your *.c file for ISR definition.

Which error appeared? I guess that you already use some interrupt routines and the interrupt routine from example may be in collision with some of them (two ISRs for the same interrupt vector).


I hope it helps you

Have a great day,
Radek

0 Kudos
2,012 Views
lukmankurniawan
Contributor II

Hello Radek,

The error that appeared is :

Link Error : L1100: Segments .absSeg263 (0xFF80) and .absSeg265 (0xFFDE) overlap
Link Error : Link failed.
I just solved it without include vector number.

And I have another question, actually I also want to have serial communication with PC. For right now I use DEVKIT-S12G128. On the example that I found, I just got SCI between TXD0 with RXD0 example which is local uart communication. After I check the board, the pins that connect to USBtoSerial is TXD1 & RXD1. So I try changing the PIN number on Processor Expert with the same baudrate and modified the code as well as below, but it still do not work. The hyperterminal on PC didn't receive any data. What is the problem?

void SCI_Send(char *pSendBuff)
{
int ptr = 0;

while(pSendBuff[ptr]!='\0')

   {

    SCI1DRL = pSendBuff[ptr];
     while(!SCI1SR1_TC);

    ptr++;
   }
}

unsigned char SCI_Read(void)

{

    if(SCI1SR1_RDRF)

   {
     return SCI1DRL;
   }
}

 

I appreciate your help.

Best Regards,

Lukman

0 Kudos
2,012 Views
RadekS
NXP Employee
NXP Employee

Hi Lukman,

Per linker, there is overlapping between objects at 0xFFDE (example of Timer ISR) and object at 0xFF80 (most probably vector table).

So, as you mentioned, you should delete vector number in ISR definition and update your vector table. The position of the vector will be determined by position in your vector table.

 

Note: For S12G, the TIM channel 0 vector number is 8 and TIM timer overflow vector number is 16.

 

Unfortunately, I have no idea regarding SCI connection. Please check the generated code and register values.

Best Regards

Radek

0 Kudos
2,012 Views
lukmankurniawan
Contributor II

Hi Radek,

 

I just created following code based on the example you given, then I connect PT0 (IOC0) to function generator, but as I check variables TC0 or new_capture it doesn't change/increase? what is the problem?  the code as below:

 


//===========================
// Input Capture Interrupt channel 0

//===========================

#pragma CODE_SEG NON_BANKED

interrupt void IC0_ISR(void)
{ 

TC0++;
new_capture = TC0; //save the value of input capture register

old_capture = new_capture; //save the IC for next using


TFLG1 = 0x01; //clear interrupt flag on channel 0 (channel1= 0x02, channel2=0x04, channel3=0x08) 
}
#pragma CODE_SEG DEFAULT


//==========================
// InitInputCapture for channel 0//
//==========================
void InitInputCapture_0(void)
{
PPST_PPST0 = 0; //set pull-up PPST0 (pull-up=0, pull-down=1)
PERT_PERT0 = 1; //enable pull-up on PERT0 

 

TSCR1 = 0xE0;//0xF0;//enable timer, stop timer during wait and freeze, disable fast flag clear
TIOS_IOS0 = 0; //channel 0 as an input capture (input capture=0, output compare=1)
TCTL4 = 0x01; //capture on rising edge
TIE_C0I = 1; //enable interrupt on channel 0 
TSCR2 = 0x00; //timer overflow interrupt disable, counter free runs, timer prescaler is 1
}

 

void main(void)

{


PE_low_level_init();
InitInputCapture_0(); ///Input Capture Interrupt//
EnableInterrupts; ///Enable interrupt//

}

 

I appreciate your help.

 

Best Regards,

 

Lukman

0 Kudos
2,012 Views
RadekS
NXP Employee
NXP Employee

Hi Lukman,

I cannot see any obvious issue in your code.

Are you sure, that you connected appropriate signal to PT0 pin and there isn't any other circuit connected to this pin?

How do you read the TC0 register/new_capture variable? Did you let code run and stop it, or did you enable periodical refresh?

Have a great day,
Radek

0 Kudos
2,012 Views
lukmankurniawan
Contributor II

Hi Radek,

I have modified my code, now the interrupt is happen, but only once. Would you kindly check my project?
I attached my project on attached file.

I appreciate your help.

 

Best Regards,

 

Lukman

0 Kudos
2,012 Views
RadekS
NXP Employee
NXP Employee

Hi Lukman,
1) I am not sure why you using TC0++; command in IC0_ISR. The TC0 contains a value of TCNT free running counter when an edge on input capture channel happen. Writes to this register have no meaning or effect during input capture. If you need some post-processing, I would like to recommend increment a variable instead of register.
2) If I understood correctly, you using “if(new_capture!=old_capture)” condition for edge detection. Unfortunately, this cannot work because you make it equal in ISR by command “old_capture = new_capture;”. These commands will make a sense only when you change their order. E.g.
old_capture = new_capture; //save the IC for next using
new_capture = TC0;//TFLG1_C0F; //save the value of input capture register
And even, in this case, you cannot use your condition because the old and new capture values will be always different (except init state).
Please use command like “PTP_PTP4 = ~PTP_PTP4; //toggle PTP4 pin” inside of IC0_ISR for edge detection.


I hope it helps you

Have a great day,
Radek

2,012 Views
lukmankurniawan
Contributor II

Hi Radek,

I got the idea, now I do not use TC0, just directly using increment variable.

Now is working. Many Thanks to you.

Best Regards,

Lukman   

0 Kudos
2,012 Views
RadekS
NXP Employee
NXP Employee

Hi Lukman,

You are welcome.

I am glad that it works now.

Radek

0 Kudos
2,012 Views
lukmankurniawan
Contributor II

Hello Radek,

Sorry for asking question again to you. Actually right now I just try to use timer for running ADC read function. I use TC0 to make the period happen. But TC0 seems affect PTT0. How to prevent PTT0 get affect from TC0? because I use PTT0 as GPIO pin for push button. My code is as below:

#pragma CODE_SEG NON_BANKED
interrupt 8 void TC0_ISR(void)
{

PTP_PTP4 = ~PTP_PTP4; //toggle PTP4
PORTD_PD0 = ~PORTD_PD0; //toggle PTD0
time_count++;

Read_ADC();
TC0 = TC0 + PERIOD;
TFLG1=0x01;
}
#pragma CODE_SEG DEFAULT


void Timer_Init(void)
{

//timer clk = bus clk / prescaler = 16Mhz / 16 = 1MHz
TIOS = 0x01; //channel 0 as output compare
TIE = 0x01; //interrupt enable
TSCR2= 0x03; //prescaler = 3
TC0 = PERIOD;
TSCR1_TEN =1;// 0xA0; //timer enabled

}

 

void main(void) {


ECLKCTL_NECLK = 1; 
SetPEEmodeBUSCLK(0x02, 0x80, 0x00); //24Mhz BUSCLK from 8 MHZ oscclk, PEE mode
DDRD = 0x0F; //LEDs output
DDRP = 0xF0; //LEDs output

DDRT = 0x00; //as input
Timer_Init();

EnableInterrupts;


for(;;)
{

   if (UP_1==0)

   {  PTT_PTT0=0;}
   else { PTT_PTT1=1;}

   

   if (DOWN_1==0)

   {  PTT_PTT1=0;}
   else { PTT_PTT1=1;}


}

Thanks & Regards,

Lukman

0 Kudos
2,012 Views
RadekS
NXP Employee
NXP Employee

Hi Lukman,

No problem with additional questions.

If you need to disconnect OCx channel from PTTx pin, please set the appropriate bit in OCPD register.

It will release PTTx pin and it can be used as GPIO after that.

 

Note: The cleared OMx/OLx bits combination in TCTL1/TCTL2 registers manages the same for the old S12(X) MCUs built on 250nm technology (= MCUs without OCPD register).


I hope it helps you

Have a great day,
Radek

0 Kudos
2,012 Views
lukmankurniawan
Contributor II

Hi Radek,

I have one more question to the timer. Recently I try two channels TC0 & TC1 with defined period. The problem is when I combine with Hardware interrupt, The MCU become unstable, some time hangup. But when I run separately the Hardware Interrupt & Timer working fine, anything I miss?

*Note: on *.prm file I already include the Vector Address for Hardware Interrupt: 

VECTOR ADDRESS 0xFFCE my_ISR 

the code is as below:

 

//==============================================================================
//TC01_ISR
//==============================================================================

#pragma CODE_SEG NON_BANKED
interrupt 8 void TC01_ISR(void)
{
if(TFLG1_C0F)
{
TFLG1_C0F = TFLG1_C0F_MASK; //clear the flag
PORTD_PD0 = ~PORTD_PD0; //toggle PORT D1
PTP_PTP3 = ~PTP_PTP3; //toggle PTP4
time_count[0]++;
TC0 = TC0 + PERIOD;

}

if(TFLG1_C1F)
{
TFLG1_C1F = TFLG1_C1F_MASK; //clear the flag
PORTD_PD1 = ~PORTD_PD1; //toggle PORT D1
PTP_PTP4 = ~PTP_PTP4; //toggle PTP4
time_count[1]++;
TC1 = TC1 +(2*PERIOD);

}
}
#pragma CODE_SEG DEFAULT


//==============================================================================
//Timer_Init
//==============================================================================
void Timer_Init(void)
{
TIOS = 0x03; //channel 0 & 1 as output compare
TIE = 0x03; //interrupt enable channel 0 &1
TSCR2 = 0x03; //prescaler = 16
TC0 = PERIOD;
TC1 = (2*PERIOD);
TSCR1 = 0xA0; //timer enabled
OCPD = 0x03; //disconnect GPIO pin T0 & T1 from TC0 & TC1//
}

//==============================================================================
//Hardware interrupt for ripple_count

//==============================================================================

void Init_Hardware_interrupt_4(void)
{
PPSJ = 0x1E; //set pull-up PPSJ0..4 (pull-up/falling edge=0, pull-down/rising edge=1)
PERJ = 0x1E; //enable pull-up on PERJ0..4
PIEJ = 0x1E; //interrupt enable/disable setting on PERJ0..4
}

#pragma CODE_SEG __NEAR_SEG NON_BANKED
interrupt void my_ISR(void)
{
if (PIFJ_PIFJ4==1)
{
if(runtime_direction[0]==1)
{
if(count[0]<2280)count[0]++;
}
else
{
if(count[0]>0) count[0]--;
}

PIFJ= 0x10;
}
if(PIFJ_PIFJ1==1)
{
if(runtime_direction[1]==1)
{
if(count[1]<2280) count[1]++;
}
else
{
if(count[1]>0) count[1]--;
}

PIFJ= 0x02;
}
if(PIFJ_PIFJ2==1)
{
if(runtime_direction[2]==1)
{
if(count[2]<2280) count[2]++;
}
else
{
if(count[2]>0) count[2]--;
}

PIFJ= 0x04;
}
if(PIFJ_PIFJ3==1)
{
if(runtime_direction[3]==1)
{
if(count[3]<2280) count[3]++;
}
else
{
if(count[3]>0) count[3]--;
}

PIFJ= 0x08;
}
}
#pragma CODE_SEG DEFAULT

void main(void) {

ECLKCTL_NECLK = 0; 
SetPEEmodeBUSCLK(0x02, 0x80, 0x00); 

DDRD = 0x03; //LEDs output
DDRP = 0xF8; //LEDs output
Timer_Init();

Init_Hardware_interrupt_4();
EnableInterrupts;


for(;;) {
_FEED_COP(); 

}

I appreciate your help.

Best Regards,

Lukman

0 Kudos
2,012 Views
lukmankurniawan
Contributor II

Hello Radek,

Just want to inform, I solved it already by separate the interrupt void & define the interrupt vector address as bellow:

VECTOR ADDRESS 0xFFEE TC0_ISR
VECTOR ADDRESS 0xFFEC TC1_ISR

#pragma CODE_SEG NON_BANKED
interrupt  void TC0_ISR(void)
{ 
if(TFLG1_C0F) 
{ 
TFLG1_C0F = TFLG1_C0F_MASK; //clear the flag 
PORTD_PD0 = ~PORTD_PD0; //toggle PORT D1 
PTP_PTP3 = ~PTP_PTP3; //toggle PTP4
time_count[0]++;
TC0 = TC0 + PERIOD; 

}

}
#pragma CODE_SEG DEFAULT

#pragma CODE_SEG NON_BANKED
interrupt  void TC1_ISR(void)
{ 

if(TFLG1_C1F) 
{ 
TFLG1_C1F = TFLG1_C1F_MASK; //clear the flag
PORTD_PD1 = ~PORTD_PD1; //toggle PORT D1 
PTP_PTP4 = ~PTP_PTP4; //toggle PTP4
time_count[1]++;
TC1 = TC1 +(2*PERIOD);

}

}
#pragma CODE_SEG DEFAULT

Now it's working fine.
Thanks & Best Regards,

Lukman

0 Kudos
2,012 Views
lukmankurniawan
Contributor II

Hello Radek,

Thanks for your fast reply. So in this case I just need to put OCPD_OCPD0=1; on my Timer_Init right?

Okay will try it.

Many Thanks  & Regards,

Lukman

0 Kudos
2,012 Views
lukmankurniawan
Contributor II

Hi Radek,

Thank you for your explanation.

Best Regards,

Lukman

0 Kudos