|
|
View previous topic :: View next topic |
Author |
Message |
tmeyer
Joined: 28 Jul 2021 Posts: 2
|
Timer2 above 60khz |
Posted: Wed Jul 28, 2021 8:35 pm |
|
|
Hello all
I have been playing with pics for years just as a hobby making simple devices. But I have recently been trying to understand the math behind the timers. When I use the below code and the program (with a period of 78 or above in setup_timer2(T2_DIV_BY_1,78,1)) everything works fine. The frequency of the interrupt matches the math.
However, when I put in 77 it should generate an interrupt frequency of 64,102hz. Note that I am actually measuring for 1/2 that (32,051hz) since I am using two interrupts to toggle the pin I am measuring PIN_C4.
After being "spot on math vs actual" from period values of 78 and above, the scope and counter diverge from math at 77 showing 29,450hz instead of expected 32,051hz. And the faster I make frequency of interrupts by lowering period value the worse the spread between measured and actual gets. I also moved the prescaler and periods around but still broke away from the math at around the same 30Khz point measured, 60khz actual interrupt frequency.
Anyone know why? This example is on a 18F258 with 20mhz clock. Same issue on a 16f684 with 20mhz clock but things break down 10khz later at around 40khz on scope, 80khz actual interrupt frequency. Multiple clock crystals, multiple different chips. Same results.
I've got to be missing something pretty basic. I even used the code generating wizard to make sure I wasn't doing something stupid. I am using a regulated power source so no issues there.
Thanks if anyone can tell me why. I searched everywhere for explanation but maybe don't know how to phrase the question.
Code: |
#include <main.h>
#INT_TIMER2
void TIMER2_isr(void)
{
output_toggle(PIN_C4);
}
void main()
{
setup_timer_2(T2_DIV_BY_1,78,1);
enable_interrupts(INT_TIMER2);
enable_interrupts(GLOBAL);
setup_low_volt_detect(FALSE);
while(TRUE)
{
//TODO: User Code
}
}
|
main.h
Code: |
#include <18F258.h>
#device ADC=16
#FUSES NOWDT //No Watch Dog Timer
#FUSES WDT128 //Watch Dog Timer uses 1:128 Postscale
#FUSES NOBROWNOUT //No brownout reset
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#use delay(crystal=20000000) |
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19520
|
|
Posted: Thu Jul 29, 2021 12:33 am |
|
|
Problem is entering and exiting an interrupt takes time....
At 20MHz, the chip does 5MIPS. It typically takes about 35 instructions to
detect an interrupt has happened, save the registers, then enter the
interrupt.
Your output toggle, takes another two instructions. Then clearing the
interrupt and restoring the registers another thirty instructions. By the time
the code arrives back in the 'main' about 70 instructions have passed. Remember a call, return etc., all take two instruction times, so more
than this in actual instruction times.
So at 20MHz, the maximum rate would be around perhaps 65KHz.
At this point, the code would be 100% occupied handing this interrupt.
No time to do anything else.
You are finding it runs out of time (remember it needs one instruction
time back in the 'main', to then respond to the interrupt), at 79 instruction
times between the triggers.
This is why chips have hardware to do useful things for you. So the PWM,
allows you to generate output pulse trains using no processor time. More
flexibly, the CCP can support having the hardware set a pin or clear a
pin after an interval. This is why to do anything actually useful, you need
to use the hardware.
There is a trick that can be used, which is to not physically call an interrupt:
Code: |
#include <main.h>
void main()
{
setup_timer_2(T2_DIV_BY_1,78,1);
setup_low_volt_detect(FALSE);
while(TRUE)
{
if (interrupt_active(INT_TIMER2))
{
output_toggle(PIN_C4);
clear_interrupt(INT_TIMER2);
}
}
}
|
Here, the main code 'polls' the interrupt flag. When it sets, does the toggle,
and clears the flag. Result, handling in a total of less than 10 instructions.
Suddenly toggle rates at about 500KHz potentially become possible!.... |
|
|
tmeyer
Joined: 28 Jul 2021 Posts: 2
|
|
Posted: Fri Jul 30, 2021 1:48 pm |
|
|
Thanks for taking the time to answer me! Your explanation makes perfect sense - I guess I would have though there would be some disclaimer somewhere about the maximum frequency that could be generated by processing the interrupt. There is a note in the datasheet (at least on the 16f684) about max PWM frequency. They are giving hobbyists like me way too much credit (I run a Ford Truck Dealership as my day job).
For the sample code below (which I haven't had time to try), I don't need to enable interrupts to test for their presence?
Thanks again - much appreciated.
Trey |
|
|
newguy
Joined: 24 Jun 2004 Posts: 1908
|
|
Posted: Fri Jul 30, 2021 2:37 pm |
|
|
No you don't need to enable interrupts to test to see if one has "fired". Interrupts are simply hardware-induced function calls if they're enabled. If they're not enabled, they still "fire" but the function isn't called. All you're doing by testing for the interrupt flag in a loop is essentially bypassing the (slow) formal interrupt call mechanism. |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|