View previous topic :: View next topic |
Author |
Message |
maria100
Joined: 01 Feb 2012 Posts: 63
|
Internal Prescaler EX_FREQ.C |
Posted: Sat Feb 04, 2012 1:57 pm |
|
|
Hello, I`m trying to implement a frequency meter based on EX_FREQC.C ( the example source included in CCS package) ..but i encountered two problems:
-If i change the EXternal 20 Mhz crystal with the 8 Mhz internal OSC built in 16f88 , what other adjustments i need to make to the code to work with the new MCU frequency right? how do i do to make it read at 100 ms , not at 1000 ms as now..?
-could i use the Code: | setup_timer_1(T1_EXTERNAL|T1_DIV_BY_1); | as prescaler to have the capability to read even bigger freq? Thank you |
|
|
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Sat Feb 04, 2012 2:46 pm |
|
|
Read bigger frequency YES - but with WORSE resolution......
A prescalar is NOT your friend if you want "single count" resolution, in your design.
For instance - if you have a prescalar of /8 - you can not resolve BETTER than 64 HZ at the input rate. In simplest terms - at say 1024 hz input
you can't tell the difference between 1024 hz and 1087 hz - they will both count as 160 in your timer registers, since you CAN'T READ the PRESCALAR count at all. |
|
|
maria100
Joined: 01 Feb 2012 Posts: 63
|
|
Posted: Sat Feb 04, 2012 2:49 pm |
|
|
i dont know for real if i need a prescaler or not...i need only up to 7 Mhz measurements...but dont know if the code in that sample will go that high with a 8 Mhz OSC tune...any ideea? |
|
|
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Sat Feb 04, 2012 3:07 pm |
|
|
What you have now is a MATH problem
not a programming issue IMHO. |
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
7MHz frequency counter |
Posted: Sun Feb 05, 2012 9:11 am |
|
|
We are now all assuming that you really want to count to 7MHz NOT 7mHz.
You need to stand back from the problem and work out what you are trying to do.
SherpaDoug has already told you that the hardware can handle your 8MHz input frequency.
asmboy has outlined the problem in using T1's prescaler.
You want to use a 100ms gate period and achieve 100Hz accuracy.
Think about your problem BEFORE you start coding, you may have to do some crude maths, and play at being a computer.
(1) Timing from the internal RC oscillator will make ACCURACY 1% at best. At 8MHz that's +/- 80kHz!
(2) Do you want accuracy or resolution?
(3) Using interrupts could lead to timing and contention issues.
(4) Feeding 8MHz straight into T1 will cause T1 to overflow every 8.192ms.
(5) With your 100ms gate, T1 overflows ~12 times with no prescale.
(6) The CCS example uses overflow to make T1 effectively a 17 bit counter.
(7) You could externally gate your input signal to the external inputs of both T0 and T1.
(8) Get the PIC to control the external gate.
(9) Use the divide by 8 prescale for T1.
(10) Use divide by 1 prescale for T0.
(11) The three LSB's of T0 hold T1's prescale value.
(12) You may now get 20 bit resolution!
Mike
Last edited by Mike Walne on Sun Feb 05, 2012 3:34 pm; edited 1 time in total |
|
|
maria100
Joined: 01 Feb 2012 Posts: 63
|
|
Posted: Sun Feb 05, 2012 9:32 am |
|
|
Thank you Mike and ASMBOY, I will test your ideas and post after. |
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
More thoughts on gating. |
Posted: Tue Feb 07, 2012 5:29 pm |
|
|
I can forsee a possible problem with the simple external gate suggestion. There's a remote possibility that the first (and/or the last) pulse into your PIC is not quite wide enough to operate both counters T0 & T1 correctly. The effect would be that one or other of the counters could receive two more pulses than the other. The worst case would be the situation where T1 prescaler either misses or generates an extra overflow and leads to an eight count error. One solution would be gate hardware which preconditions the input pulses so that all pulses reaching the PIC have a guaranteed period. Or you could say that the possiblity is so remote that it can be ignored.
There are several ways you might avoid using an external gate to your frequency counter, and rely on software gating.
(1) Use T1 only without prescaler. When T1 overflows generate an interrupt. The T1 interrupt routine increments an overflow counter. During this T1 interrupt, the main() timer stops, you will then have to correct for this. The real problem occurs if the overflow happens towards the end of the gate period. Correcting for this situation could be more difficult, but may be possible.
(2) Use T1 as in (1) but use T2 as a timer to create an interrupt driven software gate. This avoids having to correct for the main() software timer stopping on T1 interrupt, but still leaves the issue of both counters overflowing close together at the end of the gate period.
(3) Use T0 and T1 as outlined previously. The problem is that the two counters can't be started and stopped sychronously (hence the external gate suggestion). However the starting and stopping delays are well defined, it should be possible to correct for the effects of the delays. Bear in mind that T0 5 MSB's should agree with T1 5 LSB's. Any discrepancy will need to be dealt with.
Mike |
|
|
maria100
Joined: 01 Feb 2012 Posts: 63
|
|
Posted: Fri Feb 10, 2012 9:40 am |
|
|
Ok, so i have problems with this freq counter (the EX_FREQ.C SAMPLE). I get garbage data in the terminal...not the " Hz " that is set in the code. I changed the include line to 18f25k22 and it compiles fine. I set the oscillator as HSH in the config. The delay 20000000. What could be the problem ? I'm running on 20 MHz. Why is this happening ?
Also I was trying PCM PROGRAMMER'S other freq meter code:
Code: |
#include <18F452.h>
#fuses H4,NOWDT,PUT,BROWNOUT,NOLVP
#use delay(clock=40M)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
int16 isr_ccp_delta;
#int_ccp1
void ccp1_isr(void)
{
int16 current_ccp;
static int16 old_ccp = 0;
current_ccp = CCP_1;
isr_ccp_delta = current_ccp - old_ccp;
old_ccp = current_ccp;
}
//=======================
void main()
{
int16 current_ccp_delta;
int32 frequency;
set_timer1(0);
setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);
setup_ccp1(CCP_CAPTURE_DIV_16);
clear_interrupt(INT_CCP1);
enable_interrupts(INT_CCP1);
enable_interrupts(GLOBAL);
while(1)
{
disable_interrupts(GLOBAL);
current_ccp_delta = isr_ccp_delta;
enable_interrupts(GLOBAL);
frequency = (int32)(160000000L / current_ccp_delta);
printf("%lu Hz\n\r", frequency);
delay_ms(500);
}
}
|
I have replaced his original 40 mhz delay with 20 , so i will got half the frequency it is right? but it doesent..I have tried to measure a known 4.155.000 freq but i get about 2.400.000 hz...not the half as should be...~2.077.000...why is this happening?.. trying for one whole week to make a frequency counter work right... ..ermm |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Feb 10, 2012 2:28 pm |
|
|
The CCP interrupt method shown in that code is not suitable for higher
frequencies. That's because it takes about 50 instruction cycles just for
the overhead to process the interrupt. The #int_ccp user code takes 13
more cycles. That's 63. At 40MHz, the PIC does 10 instructions per usec.
So it takes about 6.3 usec to handle the CCP interrupt.
But your input frequency is 4.155 MHz. Divide that by the CCP Div_16
prescaler to get about 260 KHz for the CCP input. The period is about
3.9 usec. So your input period for the CCP is shorter than the interrupt
overhead. That's a problem.
There might be some clever way to handle single captures (with two
sequential CCP positive edges), by clearing the CCP interrupt at the
beginning of the #int_ccp routine. Then use a mini-state machine to do
only two captures, and then disable interrupts. But you want it to work
up to 7 MHz. It's possible that a much shorter interrupt routine could be
done with #int_global. The problem is that you're a newbie and you're
not going to do it. You want a pre-made solution instead of theory. |
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
Latest Version |
Posted: Fri Feb 10, 2012 6:28 pm |
|
|
I'm confused. You post code then say "Oh by the way I've change this, that and the other".
So; are you using a 40MHz or a 20MHz clock? An 18F452 or an 18F25K22?
Why set up so that the displayed frequency differs from the real one by a factor of two?
It would help me if you explained how you expect your current version to work.
Into which port are you feeding your external signal? How are you deriving your gating period?
PCM programmer can see what you're doing, but I don't care to have to work it out for myself, I design power electronics, I'm not a software expert.
I have compiled your code. I get no results because I don't have enough information. I don't propose wasting any more time without input from you.
Like I said before, you need to work out CLEARLY what you're doing BEFORE coding. Think at the block diagram (pseudo-code) level.
Your code has no helpful comments.
What are you trying to achieve? 100Hz resolution? 100ms update rate? What?
Mike |
|
|
maria100
Joined: 01 Feb 2012 Posts: 63
|
|
Posted: Fri Feb 10, 2012 7:32 pm |
|
|
Sorry Mike for my lack of proper explication. Last thing i want is to waste people time for nothing. I will try to be very obiective from now one:
1. My post was about two frequency meters designs. (one the EX_FREQ.C that CCS PROVIDES,and the other one is the one posted by PCM PROGRAMMER - the one that i posted the code ).
2. All the designs I'm running is in a 18f25k22 development board, but i have posted the original designs ( that has other pic), but when i compile i change the apropriate include file with my 18f25k22.
3. PROBLEMS with the meters: The EX_Freq.c isn't working at all. I get only garbage data to the hyperterminal. The other one (pcm programmer) works, but very strange. When I turn power on it is saying that i have allready a random relative small frequency (~ 3000-6000 hz) every time (even if is nothing on the input pin), and when i apply the clk is doesn't show the value right. My guess is that my frequency that I`m trying to measure ( 4155000 HZ) ~4.1 MHZ, is too big.
4. MY final Goal: to complete a freq meter that could read up to 6 MHz, and update the frequency every 100 ms.
5. As oscillator I use a external 20 Mhz, with the apropriate HSH fuse set.
I thank all the people who answered my threads for their patience. |
|
|
maria100
Joined: 01 Feb 2012 Posts: 63
|
|
Posted: Sat Feb 11, 2012 10:56 am |
|
|
I finally done it, using the FREQ.C source file, however i have a little problem, I cannot run with external oscillator ( 20 M). It doesn't show anything in the terminal. Pure blank. Is only running with the 16 MHZ internal one. Here is the code and fuses for the external one:
Code: |
#include <18F25K22.h>
#FUSES NOWDT //No Watch Dog Timer
#FUSES WDT128 //Watch Dog Timer uses 1:128 Postscale
#FUSES ECH //External clock with CLKOUT(PIC18), high power
#FUSES NOPLLEN //4X HW PLL disabled, 4X PLL enabled in software
#FUSES NOBROWNOUT //No brownout reset
#FUSES WDT_NOSLEEP //Watch Dog Timer, disabled during SLEEP
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOXINST //Extended set extension and Indexed Addressing mode disabled (Legacy mode)
#use delay(clock=20000000) //one instruction=0.2us
#use rs232(baud=9600, UART1)
//#bit t1_overflow=0x0C.0
#bit t1_overflow=0xF9E.0 //(PIC18, Reminder)
void main() {
setup_timer_3(T3_DISABLED|T3_DIV_BY_1);
setup_timer_4(T4_DISABLED,0,1);
setup_comparator(NC_NC_NC_NC);// This device COMP currently not supported by the PICWizard
// setup_oscillator(OSC_16MHZ|OSC_NORMAL|OSC_31250|OSC_PLL_ON);
int cycles8, cycles;
int32 freq;
long freqc_high;
long freqc_low;
while (TRUE) {
cycles8=0;
cycles=0;
freqc_high=0;
t1_overflow=0;
set_timer1(0);
setup_timer_1(T1_EXTERNAL|T1_DIV_BY_1);
/* ___ wait one second ___ */
while (cycles!=0xFF) { //true=3, false=4
cycles8=0; //1 cycle
//start inner loop
while (cycles8!=0xFF) { //true=3, false=4
if (t1_overflow)//true=2,false=3 //----|
{t1_overflow=0;freqc_high++;}//6 cycles // |
else // |-- 8 cycles
{delay_cycles(5);} //----|
delay_cycles(62); //x
cycles8++; //1
///2 cycles to jump to top
//math: end inner loop
//math: total inner loop=((3+8+x+1+2)*255 + 4)*255
//math: if x=62.87781 then inner loops takes 5mil instructions
//math: if x=62 then inner loop takes 4942920, have to fill 57080 cycles
}
delay_cycles(216); //y
cycles++; ///1 cycle
///2 cylces to jump to top
//math: outer=(3+1+y+1+2)*255+4=57080
//math: y=(57080-4)/255)-(3+1+0+0+1+2)
//math: if y=216.827450980392156862745098039216 then outer loop cylces is 57080
//math: if y=216 then outer loop cycles is off by 211 cycles. z=211
}
delay_cycles(211); //z
/* ___ end waiting 1 second ___ */
setup_timer_1(T1_DISABLED); //turn of counter to prevent corruption while grabbing value
if (t1_overflow) //check one last time for overflow
freqc_high++;
freqc_low=get_timer1(); //get timer1 value as the least sign. 16bits of freq counter
freq=make32(freqc_high,freqc_low); //use new make32 function to join lsb and msb
printf("%LU Hz\r\n",freq); //and print frequency
}
}
|
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19503
|
|
Posted: Sat Feb 11, 2012 11:13 am |
|
|
Are you trying to run an external _oscillator_ (complete module that develops the clock), or an external _crystal_. Big difference. The ECH fuse is for an external hardware oscillator module, not a crystal.
Best Wishes |
|
|
maria100
Joined: 01 Feb 2012 Posts: 63
|
|
Posted: Sat Feb 11, 2012 8:01 pm |
|
|
Still doesn't work. Here is my config:
Code: |
#include<18f25k22.h>
#device adc=16
#FUSES NOWDT //No Watch Dog Timer
#FUSES WDT128 //Watch Dog Timer uses 1:128 Postscale
#FUSES HSH //High speed Osc, high power 16MHz-25MHz
#FUSES NOPLLEN //4X HW PLL disabled, 4X PLL enabled in software
#FUSES NOFCMEN //Fail-safe clock monitor disabled
#FUSES NOIESO //Internal External Switch Over mode disabled
#FUSES NOBROWNOUT //No brownout reset
#FUSES WDT_NOSLEEP //Watch Dog Timer, disabled during SLEEP
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOXINST //Extended set extension and Indexed Addressing mode disabled (Legacy mode)
#use delay(clock=64000000)
#use rs232(baud=9600, UART1)
|
I even changed the crystal with a other one ( 64 Mhz). I keep getting garbage data in the terminal. The baud rate is set up as it should. Using 18pf capacitors for the crystal. What could be the problem? No error on pcb. Checked twice. The internal one works just fine, but have a little bad precision. |
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
|
Posted: Sun Feb 12, 2012 4:38 am |
|
|
Quote: |
I even changed the crystal with a other one ( 64 Mhz). I keep getting garbage data in the terminal. The baud rate is set up as it should. Using 18pf capacitors for the crystal. What could be the problem? No error on pcb. Checked twice.
|
Have you checked with an oscilloscope that the 64MHz clock is running correctly?
Have you checked with a simple LED flasher program that the system is running at the correct rate?
Quote: |
The internal one works just fine, but have a little bad precision.
|
What do you mean?
(1) Are your readings drifting by a fractions of percent?
(2) Have you allowed for the your gate period being based on a 20MHz clock but your actual clock is ~3.2 times faster?
Mike |
|
|
|