[time-nuts] 50/60 Hz clocks
Kasper Pedersen
time-nuts at kasperkp.dk
Wed Mar 23 21:58:22 UTC 2011
On 03/10/2011 11:41 PM, Robert LaJeunesse wrote:
> Poor man's solution: Use an Arduino to read the Thunderbolt 1PPS and lock a 50Hz
> (or 60Hz) square wave to the 1PPS. Any resulting jitter can likely be kept in
Here is an even poorer man's solution (and plug):
A DDS using both compare outputs of an 8 pin part to get
a phase-centered PWM with half the usual ripple.
With PPS input as a bonus so the zero crossing occurs where
you want it to.
http://n1.taur.dk/gen60a.jpg
Output 5Vpp at 60Hz +1.1mVpp at 39kHz. Very pretty sinewave.
//
TinyAWG.c
// 60Hz generator - 2011 Kasper Pedersen - Beerware license
//
// This is an arbirtrary waveform generator set up to produce 60Hz sine
// Compile with GCC -Os
//
//
// 2-5V -------+-----------------------------+
// | |
// | ______________ |
// | __|* |__ |
// | | |__| VCC |__|---+--||--+
// 3k| | | | 1u |
// | __| |_ _|_
// 10MHz ---||--+----|__| CLK LOCK|__| GND
// 1n | | |
// | | __| |__ ___ ___
// 3k| | |__| PPS PWM1|__|---___--+---___-------+
// | | | 2k2 | 3k3 |
// | __| |__ ___ | |
// GND -------+----|__| GND PWM0|__|---___--+--||--+--||--+---------
// | |______________| 2k2 100n | 100n
// | ATTINY13V | 60Hz out
// | |
// +-----------------------------------------+----------------
//
//
// Rising edge on PPS input (optional) will steer the output
// so that, after 128 edges, the positive zero crossing
// of the output will coincide with PPS.
// When this happens, LOCK will go high.
//
// PWM frequency is 39kHz
// first filter stage attenuates 27x
// second filter stage attenuates 81x and pulls phase 1 deg.
#include<avr/io.h>
#include<avr/interrupt.h>
#include<avr/pgmspace.h>
#define DCBIAS 127
PROGMEM unsigned char table[256]={
127,130,133,136,139,142,145,149,152,155,158,161,164,167,169,172,
175,178,181,184,186,189,192,194,197,200,202,205,207,209,212,214,
216,218,220,222,224,226,228,230,232,233,235,237,238,240,241,242,
243,245,246,247,248,248,249,250,251,251,252,252,252,253,253,253,
253,253,253,253,252,252,252,251,251,250,249,248,248,247,246,245,
243,242,241,240,238,237,235,233,232,230,228,226,224,222,220,218,
216,214,212,209,207,205,202,200,197,194,192,189,186,184,181,178,
175,172,169,167,164,161,158,155,152,149,145,142,139,136,133,130,
127,124,121,118,115,112,109,105,102,99,96,93,90,87,85,82,
79,76,73,70,68,65,62,60,57,54,52,49,47,45,42,40,
38,36,34,32,30,28,26,24,22,21,19,17,16,14,13,12,
11,9,8,7,6,6,5,4,3,3,2,2,2,1,1,1,
1,1,1,1,2,2,2,3,3,4,5,6,6,7,8,9,
11,12,13,14,16,17,19,21,22,24,26,28,30,32,34,36,
38,40,42,45,47,49,52,54,57,60,62,65,68,70,73,76,
79,82,85,87,90,93,96,99,102,105,109,112,115,118,121,124};
unsigned char phase;
signed acc;
unsigned char lastp=1;
ISR(SIG_OVERFLOW0)
{
signed s;
unsigned char v;
//60Hz*256=15360Hz increment rate.
//irq rate is 10MHz/256=39062.5Hz.
//we need to increment at: 60*256*256 / 10M
//split into primes and eliminate common factors:
//10MHz = 2^7 * 5* 5^6
//60*256 *256 = 2^7 *2 * 5 *2*2*3 * 2^8
//scaler = 2*2*2*3*256 / 5*5*5*5*5*5
// = 6144 / 15625
v=__LPM(&table[phase]); //generate output
OCR0A=v;
OCR0B=(2*DCBIAS)-v;
s=acc; //generate phase
s-=6144;
if (s<0) {
acc= s+15625;
++phase;
} else {
acc= s;
}
if (PINB&16) { //on rising edge: adjust phase so this conincides with the positive zero crossing.
if (!lastp) { //we need 128 pulses to become adjusted
lastp=1;
if (!phase) {
//phase is 0. At 15kHz we are within 65us
PORTB|=4;
} else
if (phase&0x80) {
++phase; // 65us adjustments
PORTB&=~4;
} else {
--phase;
PORTB&=~4;
}
}
} else {
lastp=0;
}
}
void main(void)
{
TCCR0A=0xB3; //A is clear on match, positive output when bigger
TCCR0B=0x01;
TIMSK0=0x02;
DDRB|=1; //output
DDRB|=2;
DDRB|=4; //"locked" output
PORTB|=16; //~50uA pullup on PPS pin.
sei();
for (;;);
}
More information about the time-nuts
mailing list