10MHz to 1pps divider - Page 1
Forum section: electronics / projects

author: sahko123
author_rank: Frequent Contributor
timestamp: March 29, 2021, 12:48:25 am
content: Simply put i want to know if there is a single ic solution to get a 1pps output from a 10MHz input for a frequency counter im building. The 10Mhz reference is a Rigol DG800 and the counter i need will only count up to at most a few KHz (for audio tuning purposes).

author: Algoma
author_rank: Frequent Contributor
timestamp: March 29, 2021, 12:56:23 am
content: simple low cost 6-8 pin Microcontroller.. you could even make it adjustable.

author: sahko123
author_rank: Frequent Contributor
timestamp: March 29, 2021, 12:59:52 am
content: would a small micro even be able to count at 10MHz? or do you mean just generate the 1pps with a micro

author: TERRA Operative
author_rank: Super Contributor
timestamp: March 29, 2021, 01:01:48 am
content: Apologies for linking to my youtube, but I did exactly this a little while back:Also:https://www.eevblog.com/forum/projects/easiest-way-to-divide-10mhz-to-1mhz/

author: sahko123
author_rank: Frequent Contributor
timestamp: March 29, 2021, 01:05:07 am
content: you see i was trying to avoid using a divide-by-N 5 or so times strategy and hoped that there was some ic that does a 10MHz to 1pps division in one package and then just do the final conversion to get 0.1pps or 0.01pps to be able to measure in the mHz.

author: sahko123
author_rank: Frequent Contributor
timestamp: March 29, 2021, 01:10:22 am
content: i have also just discovered reciprocal frequency counting which may be up my alley to get high res low frequency measurements

author: 5065AGuru
author_rank: Frequent Contributor
timestamp: March 29, 2021, 02:22:18 am
content: Hi,The simplest implementation is the PicDIV.Seehttp://www.leapsecond.com/pic/picdiv.htmIt uses 12F675 PICs and if you can program your own the code is downloadable and free.Cheers,Corby

author: magic
author_rank: Super Contributor
timestamp: March 29, 2021, 06:12:36 am
content: Quote from: sahko123 on March 29, 2021, 01:10:22 amFor audio frequency that's the way to go. Get any PIC/AVR/ARM/whatever, feed it the 10MHz reference clock and learn to use its input capture function.

author: mvs
author_rank: Frequent Contributor
timestamp: March 29, 2021, 08:15:31 am
content: Quote from: magic on March 29, 2021, 06:12:36 amIt is a bad idea to sync reference clock to MCU clock... Much better is just to use reference clock as MCU clock directly, like in PicDIV.

author: MIS42N
author_rank: Frequent Contributor
timestamp: March 29, 2021, 10:50:06 am
content: Quote from: mvs on March 29, 2021, 08:15:31 amI believe some PICs, Timer 1 can be externally clocked at 10MHz (rather than use the instruction clock of Fosc/4) and can be gated by T1G. Arrange to count on gate high and interrupt when gate goes low. At every interrupt accumulate timer 1 count and add 1 to a count of interrupts, reset timer 1 before the gate goes high again. When accumulated timer 1 count is over 5 million at a gate interrupt (assuming the input signal is symmetrical) a second (and a bit more) has passed. Use period = accumulated timer 1 count/count of interrupts. Frequency = 1/(2*period) (because we only counted for half the time). For frequency less than around 75Hz, counter 1 will overflow so need another interrupt to add 65536 to accumulated timer when this happens. If counter overflow interrupts exceed a certain amount (say 100) then the frequency is very low or DC so stop anyway. Will need a bit of synchronising to ensure the start is clean (don't start counting half way through a high input). I haven't worked out how many instructions are required in the interrupt routines, that will limit the maximum frequency. I would expect > 20kHz if ISR in assembler.This is independent of the uP clock. However, the slower the uP clock, the longer the ISR needs to run and that determines the minimum measurement period and therefor maximum frequency.

author: sahko123
author_rank: Frequent Contributor
timestamp: March 29, 2021, 12:30:41 pm
content: so what i can potentially do is use a 10Mhz reference AS the clock input and ensure that an output gives one pulse every 10,000,000 clock cycles that should give a very accurate clock i cant think of a way that can go wrong timing wise. As much as i would love to avoid using micro's seeing as how my only way to program the would be using something i got from my college and may have to give back eventually.

author: Gyro
author_rank: Super Contributor
timestamp: March 29, 2021, 01:02:10 pm
content: You can buy picDIVs ready programmed from LeapSecond (the main cost is postage) but I'm sure there must be a fellow member in Ireland who would be willing to burn the Hex code into a PIC12F675 for you.

author: sahko123
author_rank: Frequent Contributor
timestamp: March 29, 2021, 01:32:53 pm
content: someone in my town is selling a pickit3.5 programmer would that work?

author: Gyro
author_rank: Super Contributor
timestamp: March 29, 2021, 04:37:31 pm
content: I've just plugged my Pickit 3.5 programmer in and run the standalone Pickit 3 S/W. Yes, the PIC12F675 is included in the supported device list. You'll just need to make up a little matrix board adaptor with a DIP socket for the Pic and 6 way header for the programmer.Note that the Pickit 3.5 is a clone of the official Microchip Pickit 3, so don't pay more than ebay prices.

author: magic
author_rank: Super Contributor
timestamp: March 29, 2021, 06:14:06 pm
content: Quote from: mvs on March 29, 2021, 08:15:31 amI never said to do thatAlthough I may say that for some applications it wouldn't matter.Quote from: sahko123 on March 29, 2021, 12:30:41 pmDunno what your options and resources are, but I would say two things:- building a frequency counter without MCUs is likely more PITA than dealing with an MCU- with an MCU it's easy to do reciprocal counting which doesn't require precision 1pps, just a reference clock- if you don't mind AVR, some Arduino thingy may be self-programmed by USB

author: bingo600
author_rank: Super Contributor
timestamp: March 29, 2021, 06:30:55 pm
content: Ulrich B made a version for an AVR too - An usbasp programmer is cheapTiny84 vershttps://www.eevblog.com/forum/projects/divide-by-10000000/msg2815024/#msg2815024Mega16 & Mega8 vershttp://www.ulrich-bangert.de/html/downloads.html(Bottom)/Bingo

author: ve7xen
author_rank: Super Contributor
timestamp: March 30, 2021, 12:19:18 am
content: Quote from: sahko123 on March 29, 2021, 12:30:41 pmMany microcontrollers these days include bootloaders from the factory, some even over USB, so you may not need special hardware at all (either a USB-TTL UART or just a USB cable). You will pay some extra for this, but it's not expensive. For example the controller on the $3 'Black Pill' STM32F401 dev board can be programmed over its USB port. You can also get generic programmers from China for the same price (e.g. STLink or USBasp).All you need to accomplish your original goal of deriving 1PPS from 10MHz is the timer peripheral of any modern microcontroller, clocked by your external clock source (either via an external clock pin, or via the processor's clock tree), and set up to toggle a compare output every 5M cycles. You can do this with virtually any microcontroller, but the exact mechanics of doing it will depend on the timer peripheral. Setting this up should be just a couple lines of code, after which the controller can go to sleep and let the timer do the work. It feels dumb, but I've done it several times when replicating vintage hardware that used 'unique' crystal frequencies, it's much cheaper/simpler/smaller than the alternatives.Doing reciprocal counting with the peripheral instead would be nearly as simple, same clock setup (though you may need to handle overflow and avoid prescaling, especially if you don't have 32b timers), and use the input capture peripheral. It would be more work once you figure you have to get the data off the controller somehow.

author: David Hess
author_rank: Super Contributor
timestamp: March 30, 2021, 03:19:48 am
content: Quote from: sahko123 on March 29, 2021, 12:59:52 amIf the counter/timer unit is not fast enough or not available, then the clock input for the microcontroller can be driven with the 10 MHz input. After that, it is just instruction cycle counting.

author: sahko123
author_rank: Frequent Contributor
timestamp: March 31, 2021, 12:54:50 am
content: i will most likely have to go with a reciprocal counting method and find a different way to utilise the VFDs i was planning on using (soviet iv6 vfd displays). Reciprocal would have a faster update rate for use down in the tens or hundreds of mHz which would take 0.01PPS to do with conventional counting which i wanted to do with basic counters and display latches so i could tile it a long.

author: jmelson
author_rank: Super Contributor
timestamp: March 31, 2021, 01:16:29 am
content: Quote from: sahko123 on March 29, 2021, 01:05:07 amWell, you could probably do this in a CPLD. You need to divide by 10 million, or a bit less than 2 ^ 24. So, some device with at least 24 FFs and enough logic to compare the count against 10 million would do. If you want a square wave, divide by 5 million, and then go through one final divide by 2.The Xilinx 9636XL might be able to handle this, or a 9572XL surely could.Jon

author: Melt-O-Tronic
author_rank: Frequent Contributor
timestamp: March 31, 2021, 05:51:30 am
content: I've been tinkering with PicDivs for a couple of months. I've fallen in love. Now I'm running Allen variance analyses on everything. I'm currently trying to figure out how to divide the dog by 10^6 so I can measure her stability too.

author: rfclown
author_rank: Frequent Contributor
timestamp: March 31, 2021, 06:02:47 am
content: I followed the links of those that suggested the picDiv. That seems to me the easiest choice since you can buy it programmed. I saw the links of similar AVR solutions. I usually program AVRs in C, but thought I'd try assembler with a attiny85 since I had one already in a breadboard from a long ago abandoned project Put a 10 MHz ocxo on the board. Sine wave out, so I used series R and shunt diode to bring it above ground. Didn't square it up, just ran it in AVR clock input. Fumbled and Googled to see how to do command line avr assembly. I usually do command line gcc C compilation and program with avrdude. I'm using gcc and avrdude as installed by Arduino. Got 10 Hz output. Didn't take it farther since I don't have an application for this. From reading about the picDiv, I just wanted to try the technique. It's just accounting for instruction steps. Output is solid with input (see pic with persistance). With 10 MHz and 1pps out of a GPSDO the 1pps jumps around the 10 MHz (see pic with persistance).The code is b.asm. I just made a couple nested loops and added nops even up the numbers. batch files to assemble (j.bat) program (prog.bat) and write fuses (wf.bat). I use a USBisp. I've had good luck with that. You can use it in the Arduino environment by selecting Sketch>Upload Using Programmer so you don't have to use a bootloader. Changed .bat files to .txtChecked the cost of a attiny25 on Digikey. It's $0.54 for one, but if you buy a reel of 2000 they'll let you have them for only $1.02301 each. What a deal!https://www.digikey.com/en/products/detail/microchip-technology/ATTINY25-20SHR/3441453

author: MIS42N
author_rank: Frequent Contributor
timestamp: March 31, 2021, 10:42:30 am
content: I am a fan of using the hardware timers for the sort of counting you are doing. E.g. you could set up timer 0 with a prescale of 8 and count to 124 (or is it 125, I would need to read the specs again), then auto reset and interrupt. You would get an interrupt every 100us, then in the interrupt routine (ISR) use SBIW to subtract 1 from a register pair (effectively a 16 bit counter) preloaded with what ever count you want - e.g. for 10Hz out you would start with 500. On software count = 0 invert output and reload software count. It requires a bit of setting up, but the logic is much clearer than nested loops with delays. And much easier to modify - you could add a second output in the ISR just by adding another load/test/invert bit of code, no change to the 100us loop, no working out nop delays. After setting up the counter and enabling interrupts the mainline just spins on a RJMP *-1 (jump to itself). I didn't set up a program to test this, but I'd take a bet there's less instructions needed.Just putting this as an alternate. Does require more knowledge of the processor. If you master the ATMEL timers, PIC timers are easy.It's a while since I did any ATMEL programs, so this is rough and may be wrongSETUPset Waveform Generation Mode = CTCset OCRA = 124set Clock Select = prescale 8set Timer/Counter0 Output Compare Match A Interrupt EnableLDI R16,low(500)LDI R17,high(500)enable interruptsspinISR - since there is only one enabled interrupt, could code this at address 0x0003Code:SBIW R16,1BRNE gobakLDI R16,low(500)LDI R17,high(500)SBI pingobak: RETI

author: rfclown
author_rank: Frequent Contributor
timestamp: March 31, 2021, 02:00:01 pm
content: Something I learned trying AVR assembly:before Googling and finding the right answer, I just looked for the assembler in the Arduino tool chain, and found avr-as. So to assemble a file named b.asm, I did:*** DON'T DO THIS *** IT DOESN"T WORK ***avr-as --warn b.asm -mmcu=attiny85 -o b.oavr-objcopy -O ihex b.o b.hexit produced a hex file, but it turns out the reference labels weren't resolved. I thought that the "--warn" would warn me of things like this... NOT. Turns out you need to use gcc, but say it's assembler, so it can link and resolve references like this:DO THISavr-gcc -c -mmcu=attiny85 -x assembler b.asm -o b.oavr-gcc -mmcu=attiny85 b.o -o b.elf -nostartfilesavr-objcopy -O ihex b.elf b.hexThis is on a Windows machine using the stuff installed with Arduino IDE. This will work on the command line as long as the path is set:PATH=C:\Program Files (x86)\Arduino\hardware\tools\avr\bin;%PATH%when I boil things down to the simple essentials like this, I find that I can go back years later and remember how to do it again. I started on this path because when I saw the picDiv, I found myself looking at PicKits on eBay (I started with PICs in the 90's). But when I thought about the bank switching stuff, I decided to fight the urge to buy and just grabbed what I had lying around.

author: bingo600
author_rank: Super Contributor
timestamp: March 31, 2021, 06:50:39 pm
content: Quote from: MIS42N on March 31, 2021, 10:42:30 amYour solution would never pass a real time-nut.The AVR ISR is not deterministic , and would produce "unacceptable 1-PPS jitter".Have a look at TVB or Ulrichs programs , and notice no interrupts are used , all is done w. pure instruction timing.If you have Glitch free 32bit timers like on the larger ARM's you might get away with a CTC , but NO using of the PLL ... Jitter/Bingo

author: jimmc
author_rank: Frequent Contributor
timestamp: March 31, 2021, 09:30:31 pm
content: Quote from: bingo600 on March 31, 2021, 06:50:39 pmIn general I would agree, however in the particular case where the timer clock is derived from the sytem clock and the MCU does nothing but sleep waiting for an interrupt, then surely the latency is fixed and jitter is not a problem.Jim

author: Picuino
author_rank: Super Contributor
timestamp: March 31, 2021, 10:11:01 pm
content: I have once used a 14 pinPIC16F15324for that job.This microcontroller has a CLC module with programmed logic that, combined in software with the timer, allows obtaining several outputs with a frequency lower than the clock input andjitter free. One of them is a 1PPS output.The output pins are programmable because this microcontroller has the Peripheral Pin Select function.Pins of input and output signals:Input frequency: Pin 2 (RA5 / CLKIN)Output frequency 5MHz: Pin 10 (RC0)Output frequency 10kHz: Pin 9 (RC1)Output frequency 1PPS: Pin 8 (RC2)Pins of power supply and programming:Pin 1: VddPin 4: Vpp/MCLRPin 12: ICSPCLKPin 13: ICSPDATPin 14: GndC source code for XC8:Code: (c)/** PIC16F15324 Divisor from 10MHZ to 1PPS** File: main.c**/// Define main source file#include <xc.h>#include "config.h"unsigned int counter;/** Peripheral pin select (Cap. 15)*/void pps_init(void) {// Unlock PPSPPSLOCK = 0x55;PPSLOCK = 0xAA;PPSLOCKbits.PPSLOCKED = 0; // Unlock// CLC1 5MHzRC0PPS = 1; // 1 = CLC1_OUTTRISCbits.TRISC0 = 0;// TIMER0 10kHzT0CKIPPS = 0x05; // 5 = RA5RC1PPS = 0x19; // 0x19 = TMR0TRISCbits.TRISC1 = 0;// CLC2 1PPSRC2PPS = 2; // 2 = CLC2_OUTTRISCbits.TRISC2 = 0;// Lock PPSPPSLOCK = 0x55;PPSLOCK = 0xAA;PPSLOCKbits.PPSLOCKED = 1; // Lock}/** Configurable Logic Cell Init*/void clc1_5mhz(void) {// CLC1 setup// JK biestable divisorCLC1CON = (1 << 7) // Enable| (0b110); // 110=J/K flip-flopCLC1POL = 0b00001010; // PolarityCLC1SEL0 = 4; // Data select FOSCCLC1SEL1 = 0; // Data selectCLC1SEL2 = 0; // Data selectCLC1SEL3 = 0; // Data selectCLC1GLS0 = 0b00000010; // GATE 1 (CLK) = FOSCCLC1GLS1 = 0b00000000; // GATE 2 (J) = 1CLC1GLS2 = 0b00000000; // GATE 3 (RST) = 0CLC1GLS3 = 0b00000000; // GATE 4 (K) = 1}void clc2_divisor(void) {// CLC1 setup// JK biestable divisorCLC2CON = (1 << 7) // Enable| (0b110); // 110=J/K flip-flopCLC2POL = 0b00001010; // PolarityCLC2SEL0 = 12; // Data select TMR0_OVERFLOWCLC2SEL1 = 0; // Data selectCLC2SEL2 = 0; // Data selectCLC2SEL3 = 0; // Data selectCLC2GLS0 = 0b00000000; // GATE 1 (CLK) = TMR0CLC2GLS1 = 0b00000000; // GATE 2 (J) = 1CLC2GLS2 = 0b00000000; // GATE 3 (RST) = 0CLC2GLS3 = 0b00000000; // GATE 4 (K) = 1}void cpu_init(void) {INTCON = 0;// OscillatorWDTCON0bits.SWDTEN = 0; // Watchdog disabled// Init portsANSELA = 0;ANSELC = 0;LATA = 0x00;LATC = 0x00;TRISA = 0xFF;TRISC = 0xFF;// Weak pull up resistorsWPUA = 0;WPUC = 0;// Setup interruptsINTCONbits.PEIE = 0;INTCONbits.GIE = 0;}/** Timer0 initialization (divide 10MHZ input by 1000 = 10kHz)*/void timer0_init(void) {T0CON1bits.T0CS = 2; // 2 = FOSC/4T0CON1bits.T0ASYNC = 0; // 1 = counter not syncronized with system clocksTMR0L = 0;TMR0H = 124;T0CON0bits.T016BIT = 0;T0CON0bits.T0EN = 1;T0CON1bits.T0CKPS = 0; // 0 = 1:1 prescalerT0CON0bits.T0OUTPS = 0; // Postscaler// Timer0 Reset and enable interruptsPIR0bits.TMR0IF = 0;PIE0bits.TMR0IE = 1;}/** Interrupt service routine*/void __interrupt() isr(void) {if (PIR0bits.TMR0IF == 1) {PIR0bits.TMR0IF = 0;counter++;if (counter== 10000) {counter= 0;CLC2GLS0 = 0b00000010;} else {CLC2GLS0 = 0b00000000;}}}/** Main function*/void main(void) {// Init modulescpu_init();pps_init();clc1_5mhz();clc2_divisor();timer0_init();counter= 0;INTCONbits.PEIE = 1;INTCONbits.GIE = 1;while (1) {};SLEEP();}Header (config.h):Code: (c)// 'C' source line config statements#define _FOSC 10000000#define _XTAL_FREQ _FOSC#define PROJECT_1// PIC16F15324 Configuration Bit Settings// CONFIG1#pragma config FEXTOSC = ECH // External Oscillator mode selection bits (Oscillator not enabled)#pragma config RSTOSC = EXT1X // Power-up default value for COSC bits (HFINTOSC = 32MHz)#pragma config CLKOUTEN = OFF // Clock Out Enable bit (CLKOUT function is disabled; i/o or oscillator function on OSC2)#pragma config CSWEN = ON // Clock Switch Enable bit (Writing to NOSC and NDIV is allowed)#pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable bit (FSCM timer enabled)// CONFIG2#pragma config MCLRE = OFF // Master Clear Enable bit (MCLR pin is Master Clear function)#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)#pragma config LPBOREN = OFF // Low-Power BOR enable bit (ULPBOR disabled)#pragma config BOREN = ON // Brown-out reset enable bits (Brown-out Reset Enabled, SBOREN bit is ignored)#pragma config BORV = LO // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (VBOR) set to 1.9V on LF, and 2.45V on F Devices)#pragma config ZCD = OFF // Zero-cross detect disable (Zero-cross detect circuit is disabled at POR.)#pragma config PPS1WAY = OFF // Peripheral Pin Select one-way control (The PPSLOCK bit can be cleared and set only once in software)#pragma config STVREN = ON // Stack Overflow/Underflow Reset Enable bit (Stack Overflow or Underflow will cause a reset)// CONFIG3#pragma config WDTCPS = WDTCPS_31// WDT Period Select bits (Divider ratio 1:65536; software control of WDTPS)#pragma config WDTE = OFF // WDT operating mode (WDT enabled regardless of sleep; SWDTEN ignored)#pragma config WDTCWS = WDTCWS_7// WDT Window Select bits (window always open (100%); software control; keyed access not required)#pragma config WDTCCS = SC // WDT input clock selector (Software Control)// CONFIG4#pragma config BBSIZE = BB512 // Boot Block Size Selection bits (512 words boot block size)#pragma config BBEN = OFF // Boot Block Enable bit (Boot Block disabled)#pragma config SAFEN = OFF // SAF Enable bit (SAF disabled)#pragma config WRTAPP = OFF // Application Block Write Protection bit (Application Block not write protected)#pragma config WRTB = OFF // Boot Block Write Protection bit (Boot Block not write protected)#pragma config WRTC = OFF // Configuration Register Write Protection bit (Configuration Register not write protected)#pragma config WRTSAF = OFF // Storage Area Flash Write Protection bit (SAF not write protected)#pragma config LVP = OFF // Low Voltage Programming Enable bit (Low Voltage programming enabled. MCLR/Vpp pin function is MCLR.)// CONFIG5#pragma config CP = OFF // UserNVM Program memory code protection bit (UserNVM code protection disabled)EDIT:The outputs with subfrequencies are easily expandable to more signals thanks to the 4 CLCs that the microcontroller has, of which only 2 are currently used.

author: MIS42N
author_rank: Frequent Contributor
timestamp: March 31, 2021, 10:12:21 pm
content: Quote from: jimmc on March 31, 2021, 09:30:31 pmI had considered the deterministic problem. In this case the only instruction to be interrupted is a 2 cycle instruction, and the interrupts occur at a multiple of 2 cycles so the first interrupt will sort it. In another program I had to deal with the jitter problem so put in a delay in the ISR to synch with the timer. I avoided 4 cycle instructions (they can be emulated).Code:in R24,TCNT0 ; jitter reduction.sbrc R24,1 ; Timer normally xxxxxx00rjmp PC+3 ; if xxxxxx10 delay 4 cycles [in(1), sbrc(not taken: 1), rjmp(2)]sbrs R24,0 ; if xxxxxx01 delay 5 cycles [in(1), sbrc(taken: 2), sbrs(taken: 2)]rjmp PC+1 ; xxxxxx00 delay 6 cycles [in(1), sbrc(taken: 2), sbrs(not taken: 1), rjmp(2)]

author: Picuino
author_rank: Super Contributor
timestamp: April 01, 2021, 10:39:18 am
content: Quote from: Picuino on March 31, 2021, 10:11:01 pmAnother advantage of PIC16F15324 is their low cost, for free if you ask for samples at microchip, or less than 1€ if you buy one.https://www.microchipdirect.com/product/search/all/PIC16F15324This microcontroller is so flexible and powerful at the same time as it is small (14 pin) that it serves me for a multitude of small projects as a standard microcontroller to solve all kinds of problems. That is why I have several in my component box and it is the one that I have used.But the program can be easily adapted to another microcontroller of the same family with 8 pins and even cheaper (PIC16F15313).