Hi,
I am using the S12ZVC 64LQFP micro in my project. I want to generate 1ms(Higher Priority) timer Interrupt and 10ms (Lower priority)Timer Interrupt. My External Ocillator Frequency is 16MHz and Bus Clock Frequency is 32MHz.
Is it possible to generate 1ms and 10ms timer interrupts using in this micro? Requesting to reply at the earliest. It's urgently needed.
Thanks,
Anwar
Solved! Go to Solution.
Hi Anwar,
This comes from basic architecture of multichannel timer.
There is only one free running TCNT counter (0x0000->0xFFFF, counter reset, 0x0000->0xFFFF,….) and OC channels will generate events when TCNT counter reach their TCx values.
The TCNT counter value cannot be modified in normal mode.
The presented example code is just the simplest using of the timer. The timer does not automatically calculate current TCNT value + TCx value because such behavior will block some of other cases of use (we may need to configure timer interval from another point that is current TCNT value).
The Timer Counter Reset Enable TCRE bit will allow resetting TCNT counter when TCNT reach TC7 value.
Note: This bit and the feature are available only when channel 7 exists. If channel 7 doesn’t exist, this bit is reserved. So, you may use that special feature only for TIM0 and only for one specific channel. This feature may be used when you need several OC/IC channels aligned together. The code for other OC/IC channels must be adapted for that behavior.
I hope it helps you.
Have a great day,
Radek
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Hi Anwar,
Yes, it is possible.
You have several options how to implement periodic interrupts.
Autonomous periodic interrupt (API) – The source clock for API may be bus clock or ACLK (low power 20kHz RC oscillator). The API is available in stop mode when ACLK is enabled and selected as a clock source. The disadvantage is the limited accuracy of ACLK clock source.
Real Time Interrupt (RTI) - The source clock for RTI may be oscillator clock OSCCLK or IRCCLK (internal 1MHz RC oscillator).
Timer Module (TIM) in the output compare mode – The TIM0 (8 channels) is gated from bus clock while TIM1 (4 channels) is gated from device core clock.
Attached are simple example codes which demonstrated API (include trimming), TIM (see mainly TIM-500usPeriod example).
The RTI code should be extremely simple. For example:
CPMURTI = 0x85; /* prescaler for RTI, decimal values, 10x10^3=>10ms interrupt */
CPMUINT_RTIE = 1; /* enable interrupt */
EnableInterrupts;
Interrupt routine:
interrupt 11 void RTI_ISR(void) {
CPMUIFLG_RTIF = 1; /* clear flag */
/* do something */
}
Note: CPMUCLKS_RTIOSCSEL bit selects clock source. The IRCCLK is a default value.
I hope it helps you.
Have a great day,
Radek
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Hi Radek,
Thank you for very much for your quick reply. I would like to know would there be any issues in the below scenario.
Scenario: I have to create two tasks based on the 1ms timer interrupt and 10ms timer interrupt to serve the purpose of my project
1) RTI as 1ms Timer interrupt with the highest priority and the clock source for it is as 16MHz External Oscillator Clock.
2) If I use TIM1 as10ms timer interrupt with lowest priority and the clock source for it as 64MHz Core Clock(PLL clock).
or
If I use TIM0 as10ms timer interrupt with lowest priority and the clock source for it as 32MHz Bus Clock.
I would like to know about; would there be any synchronization issues or accuracy(Timing Jitter) issues with respect to generation of these interrupts, if I use as mentioned above.
Thank you in advance.
Best Regards,
Anwar
Hi Anwar,
Currently, I cannot see any potential issue in such scenario.
The RTI and TIM are independent modules and the output period will be not synchronized any of way.
About Timing Jitter/Interrupt Latency)
In general, when an interrupt is enabled and occurs, the CPU will first finish pending interrupt routine (if any active) or current instruction. After that, it pushes CPU registers on the stack and jumps to RTI interrupt routine.
So, when no other interrupt routine is active, the maximum jitter is given by maximum instruction length.
The influence of low priority interrupts may be minimized by interrupt nesting – we will enable interrupts (clear I bit) inside low priority interrupt routine (e.g. TIM0_CH1). In such case, any interrupt with higher priority than current interrupt routine (e.g. RTI) may interrupt it.
Note: If you will use more than one timer channel, please keep in mind flag clearing mechanism. For example:
TIM0TFLG1_C1F=1; //wrong approach – it will clear all pending flags
TIM0TFLG1=0x02; or TIM0TFLG1= TIM0TFLG1_C1F_MASK; //correct approach – it will clear only one flag.
For more details, please look at AN2554 Clearing and Disabling Interrupt Flags
http://www.nxp.com/files/microcontrollers/doc/app_note/AN2554.pdf
I hope it helps you.
Have a great day,
Radek
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Hi Radek,
I need small clarification on your below piece of code from "ZVML128-TIM-500usInterval-CW105" project.
void Start_interval(unsigned int interval_us)
{
unsigned long int interval=0;
//time align according current prescaler(=8) and bus clock(6.25MHz)
//interval = (interval_us * BUS_CLOCK )/(prescaler * 1Mhz);
interval = ((unsigned long int)interval_us * 6250)/8000;
TIM0TC0 = TIM0TCNT + interval; //set interval
TIM0TIE_C0I = 1; //enable interrupt on channel 0
PTS_PTS0 = 1; //toggle PS0
}
void main(void) {
unsigned long i;
DDRS=0x01; //PS0 is output
InitOutputCompare();
EnableInterrupts;
for(;;) {
Start_interval(500); //interrutp will be triggered in 500us
for(i=1;i<1000;i++); //just delay
} /* wait forever */
}
Why do we need to update the output compare register( TIM0TC0 = TIM0TCNT + interval; //set interval) value every time? Is it not possible to configure once and start the timer, so that it shall generate the interrupt with the configured duration?
And also, why can't we load the TIM0TC0 with only counter value needed (Example: only with "interval" value)?
Thanks in advance.
With Best Regards,
Anwar
Hi Anwar,
This comes from basic architecture of multichannel timer.
There is only one free running TCNT counter (0x0000->0xFFFF, counter reset, 0x0000->0xFFFF,….) and OC channels will generate events when TCNT counter reach their TCx values.
The TCNT counter value cannot be modified in normal mode.
The presented example code is just the simplest using of the timer. The timer does not automatically calculate current TCNT value + TCx value because such behavior will block some of other cases of use (we may need to configure timer interval from another point that is current TCNT value).
The Timer Counter Reset Enable TCRE bit will allow resetting TCNT counter when TCNT reach TC7 value.
Note: This bit and the feature are available only when channel 7 exists. If channel 7 doesn’t exist, this bit is reserved. So, you may use that special feature only for TIM0 and only for one specific channel. This feature may be used when you need several OC/IC channels aligned together. The code for other OC/IC channels must be adapted for that behavior.
I hope it helps you.
Have a great day,
Radek
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Ok. Thank you. So in my case, I can update the Compare register value with required duration count value as follows from Interrupt service routine.
interrupt IC0_ISR(void)
{
/*clear the flag*/
TIM0TFLG1_C0F = TIM0TFLG1_C0F_MASK;
TIM0TC0 = TIM0TCNT+RequiredDurationCount;
EnableInterrupts;
}
Thanks a lot Radek for your quick support. It is very helpful. I agree with your point #1 and #2.
For 3rd point, I have added the Enableinterrupts because I would be calling some 10ms task functions.They may take more than 1ms of execution time.
With Best Regards,
Anwar
Hi Anwar,
You are welcome.
Thank you for clarification 3rd point. It is clear and I agree with that.
Have a great day,
Radek
Hi Radek,
I need one more clarification with respect to MCU Wakeup when I configure the Priority levels as below.
/*Interrupt Request Configuration Address Register*/
INT_CFADDR = 0x70;
INT_CFDATA3_PRIOLVL = 0x04; /*Priority level of TIM0_C0I*/
INT_CFDATA4_PRIOLVL = 0x07; /*Priority level of Real Time Interrupt*/
And, I am using the Port P interrupt i.e. PIFP_PIFP4 enabled to wake up MCU from STOP mode using the external wakeup source signals.
Observed behavior:
Without enabling the Nesting Interrupt feature, wake up works fine but If enable the this feature as mentioned above, MCU is doesn't wake up from STOP mode.
Please let me know what would be the configuration to wake up the MCU as per the above scenario.
Thanks in advance.
With Best Regards,
Anwar
Hi Anwar,
It depends on where you call asm STOP command.
This command should be executed only from the main loop and not from any interrupt routine.
In the case of interrupt nesting, the I-bit maskable interrupt requests can be interrupted by any interrupt request with a higher priority. So, I suppose that you use interrupt nesting for TIM0 interrupt and port P interrupt has lower priority (default is priority 1) than 4.
The priority decoding is based on compare interrupt request priority with the status of the current interrupt processing level (IPL) in the CPU condition code register (CCW).
Note: Priority level of port P ISR
INT_CFADDR = 0x40;
INT_CFDATA3_PRIOLVL = 0x04; /*Priority level of port P ISR*/
I hope it helps you.
Have a great day,
Radek
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Hi Radek,
Thank you for your quick reply.
Your below statement is correct. I am calling the "asm STOP" command in as part of the Real Time Interrupt ISR task.
Q1: So, can it not be called from any of the Interrupt Service Routines? Can I call this from my Background Task?
Q2: If I have understood correctly the INT_CFADDR register description details, as per your example
INT_CFADDR = 0x40;
INT_CFDATA3_PRIOLVL = 0x04; /*Priority level of port P ISR*/
I can set the priority levels for the Interrupt vector addresses (Vector base + 0x100, 104, 10C, 110, 114, 118, 11C, 120)
using INT_CFDATA0–7 register configurations.
Is the priority levels configurations applicable only for the enabled interrupts?
For example: Let us say, I want to configure the below interrupts to serve the purpose.
1, Vector base + 0x100 Autonomous periodical interrupt (API) Enabled during the sleep/stop to to know the sleep time.
2, Vector base + 0x10C Port P interrupt (To wakeup from stop)
3, Vector base + 0x154 CAN receive interrupt(Normal Mode)
4, Vector base + 0x1CC TIM0 timer channel 0 (10ms task interrupt, Normal Mode)
5, Vector base + 0x1D0 RTI timeout interrupt (1ms task interrupt, Normal Mode)
Your inputs would be highly appreciable.
Have a good day too!
With Best Regards,
Anwar
Hi Anwar,
Q1)
When CPU jumps into interrupt routine, it sets I-bit in CPU CCW register. This way it blocks other I-bit maskable interrupts. The I-bit is cleared during ISR leaving (RTI instruction). So, the calling asm STOP instruction inside ISR typically causes partially brick of MCU (wake-up only by non I-bit maskable interrupts). When you clear I-bit manually inside ISR prior calling asm STOP instruction, the MCU may be wake-up only be non I-bit maskable interrupts (like XIRQ) or by I-bit maskable interrupts with higher priority than currently executed ISR.
So, you may call asm STOP instruction anywhere in your code, but you must consider the available wake-up sources. Typically, we do not call asm STOP instruction inside any ISR, but somewhere in the main loop – that all interrupts/wake-up sources are available.
Driving wake-up capability by interrupt priority is not a practical solution. You may simply disable/enable appropriate interrupts prior asm STOP instruction. The priority settings should be used for priority configuration during run mode.
Q2)
Yes, there is up to 128 interrupt vectors. For the saving number of registers, the access to priority level is managed by paging mechanism. INT_CFADDR is a page and INT_CFDATA0–7 registers may be used for priority level configuration of 8 appropriate interrupt vectors.
You may configure INT_CFDATAx values despite on fact whether appropriate interrupt is enabled or disabled.
Note: Priority 0 effectively mean disabled interrupt.
Note: The RTI may wake-up MCU only from Pseudo Stop Mode (External oscillator (XOSCLCP) continues to run). TIMx module cannot wake-up MCU from any of stop modes.
For example:
/*Interrupt Request Configuration Address Register*/
INT_CFADDR = 0x70;
INT_CFDATA3_PRIOLVL = 0x01; /*Priority level of TIM0_C0I*/
INT_CFDATA4_PRIOLVL = 0x02; /*Priority level of Real Time Interrupt*/
INT_CFADDR = 0x50;
INT_CFDATA5_PRIOLVL = 0x04; /*Priority level of CAN receive*/
INT_CFDATA7_PRIOLVL = 0x04; /*Priority level of CAN wake-up*/
INT_CFADDR = 0x40;
INT_CFDATA3_PRIOLVL = 0x05; /*Priority level of port P ISR*/
INT_CFDATA1_PRIOLVL = 0x06; /*Priority level of LVI*/
INT_CFDATA0_PRIOLVL = 0x07; /*Priority level of API*/
Note: when you divide vector address in hex format by 4, you will get hex number where lower 3 bits [0..2] refers to selected register INT_CFDATAx and upper 4 bits [3..6] refers to page register INT_CFADDR value.
If you set for example INT_CFADDR = 0x40, you may configure priority for the Interrupt vector addresses (Vector base + 0x100, 0x104, 0x108, 0x10C, 0x110, 0x114, 0x118, 0x11C)
I hope it helps you.
Have a great day,
Radek
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Thank you Radek for the detailed information.
Merry Christmas and advanced Happy new year 2017.
Have great time.
With Best Regards,
Anwar
Hi Anwar,
Yes/No
1. If you need to generate some regular periodic output, I would like to rather recommend using previous TIM0TC0 value as the starting point for calculating next TIM0TC0 value, instead of current counter value TIM0TCNT.
For example: TIM0TC0 = TIM0TC0+RequiredDurationCount;
This will allow to you minimize influence of interrupt jitter.
2. Please use rather TIM0TFLG1 = TIM0TFLG1_C0F_MASK; instead TIM0TFLG1_C0F = TIM0TFLG1_C0F_MASK;.
3. You probably don’t need EnableInterrupts; at end of your IC0_ISR interrupt routine. It makes sense only when you make some longer calculations inside IC0_ISR.
I hope it helps you.
Have a great day,
Radek
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Thank you for your support Radek.