If you want to make a jammed slate, you need a good  timecode specification generator with timing accuracy at least ten times better than the desired specification. This will enable accurate drift testing

This means a really accurate frequency source, like a rubidium “Atomic” frequency standard, such as the FE5680 now available on ebay. These are accurate to within a few microseconds a day, and generally give out two signals

  • 10MHz
  • 1 Pulse Per Second

With these two signals, you can make a really superb frequency counter/timer

I used a handful of 74series logic CMOS gates and a wonderful 32 bit 74lv8154  counter IC to make a precision counter timer box using the FE5680 as the time reference. The 8154 really saves on wiring time. The whole thing was controlled by a ATmega48.

The TC gen is the most basic, no preset time, no user bits or parity compensation, and just runs at 25 fps, no dropframe. The main feature is that it toggles a pin on the micro every time 00 frames is sent, generating a square wave 0f 0.5Hz  this is used by the frequency counter as the gate, feeding the FE5680 10Mhz clock into the 74lv8154.

If the TC gen is accurate the 74lv8154 will count to exactly 20,000,000 +-1 . This is means that the timecode accuracy is better than 4 milliseconds a day. If I changed the TC gen code to toggle the micro pin every other 00 frame I would probably get a reading better than 2 milliseconds a day.

The TC gen is basically just an ATmega 48 and a 3.3v regulator, with a high speed comparator to turn the 10MHz FE5680 sine wave into a digital level signal that will be the master  clock for the micro.

That looks OK.
Here’s the circuit

Here’s the code for the generator, it’s a bit rough but it works.

Was compiled with Atmel Studio 4 and Winavr tools

/*Copyright [2012] [john griffith]

Licensed under the Apache License, Version 2.0 (the “License”);

you may not use this file except in compliance with the License.

You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software

distributed under the License is distributed on an “AS IS” BASIS,

WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

See the License for the specific language governing permissions and

limitations under the License.*/

#define F_CPU 10000000UL

#define sim 0

#define BAUD 9600

#define MYUBRR F_CPU/16/BAUD-1

#define debug 0

#include <avr/io.h>

#include <avr/interrupt.h>

#include <util/delay.h>

void SPI_MasterTransmit(char);

void SPI_MasterInit(void);

//——————————-

void pwm_init(void);

void pwm_duty_cycle(unsigned char);

void notplus1(void);

void plusone(void);

//——————————–

void USART_Transmit( unsigned char);

void USART_Init( unsigned int);

void start_TCCR1B(void);

//——————————–

volatile unsigned char time[8]={4,2,9,5,9,5,3,2};

volatile unsigned char Time_out,stored[8];

volatile char bitcount=255;//not 0, as interrupt occurs in startup

volatile unsigned int bored, sync_wd=0b1011111111111100;

volatile long counter0, counter1,bigword;

char PPS_arm;

//——— temp comp———

volatile signed char T1_offset=-1,my_printf;

volatile int T1_cal, count, tweak_count,T1_trim;

volatile signed int cycle_count,UD_count;

//————————————————–

ISR(TIMER1_COMPA_vect)

{// takes 2.89uSec from tcnt1=comp1a to get here

if(PPS_arm)

{

PORTD^=8;

PPS_arm=0;

}

cycle_count++;

tweak_count++;

Time_out=1;

if((bitcount&1)==0)//even ==clock

{

PORTC^=1; //biphase

PORTD|=4;

PORTD|=4;

PORTD&=~4;

}

if((bitcount&1))////odd ==data

{ if (bored)

{

PORTC^=1;//biphase

PORTD|=4;

PORTD|=4;

PORTD&=~4;

}

}

bitcount++;

}

//—————————————–

void SPI_MasterTransmit(char cData)

{

/* Start transmission */

SPDR = cData;

/* Wait for transmission complete */

while(!(SPSR & (1<<SPIF)));

}

void SPI_MasterInit(void)

{

SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);// Fosc/4, (1<<SPR0)/16

}

//—————————————–

void pwm_init(void)

{

TCCR0A = _BV(WGM00) | _BV(COM0A1) | _BV(COM0B1);

TCCR0B |= 1;// _BV(CS00);

DDRD|=(1<<DDD6); //pwm port pin 12

OCR0A = 32;

}

void pwm_duty_cycle(unsigned char w)

{

OCR0A=w;

}

//—————————————-

void USART_Init( unsigned int ubrr)

{

/*Set baud rate */

UBRR0H = (unsigned char)(ubrr>>8);

UBRR0L = (unsigned char)ubrr;

UCSR0B |= (1<<TXEN0);

UCSR0C |= (3<<UCSZ00);//(1<<USBS0) 2stop bit if set

}

void USART_Transmit( unsigned char data )

{volatile char temp;

temp=data;

while ( !( UCSR0A & (1<<UDRE0)) );

UDR0 = data;

}

//———————

void start_TCCR1B(void)

{

TCCR1B |= (1 << WGM12)|(1 << CS10);// div1 CTC mode

}

//———————————

//

void plusone(void)// ride/slate6c

{volatile char carry=0,FRunit=5, FRten=2,x=0;

char dfbit10;

stored[0]=(time[0]&0x0f)+1;// mask off top nibble

if (stored[0]==10)

{

carry=1;

stored[0]=0;

}

stored[1]=(time[1]&0x03)+ carry; //

carry=0;

if( (stored[1]>=FRten) & (stored[0]>=FRunit) )

{PPS_arm=1;

carry=1;

stored[0]=0;

stored[1]=0;

}

if (time[1]&4)//refresh for next frame

{

dfbit10=1;

}

else

{

dfbit10=0;

}

stored[2]=(time[2]&0x0f) + carry;

carry=0;

if( stored[2]>=10)

{

carry=1;

stored[2]=0;

}

//—————— 10 seconds—————-

stored[3]=(time[3]&0x07)+carry;

carry=0;

if(stored[3]>=6)

{

stored[3]=0;

carry=1;

}

//…………….minutes……….

stored[4]=(time[4]&0x0f)+ carry;

carry=0;

if(stored[4]>=10)

{

x=0;

stored[4]=0;

carry=1;

}

//…………….10 minutes………….

stored[5]=(time[5]&0x07)+ carry;

// stored[5]=x;

carry=0;

if(stored[5]>=6)

{

carry=1;

stored[5]=0;

}

//……………hours…………..

stored[6]=(time[6]&0x0f)+carry;

carry=0;

if(stored[6]>=10)

{

carry=1;

stored[6]=0;

}

//…………..10 hours………….

stored[7]=(time[7]&0x03)+carry;

carry=0;

if( (stored[6]==4)&(stored[7]==2) )//x?

{

stored[6]=0;

stored[7]=0;

}

}

//——————————–

void startup(void)

{

bored=1;// waits for bit timer interrupt OCR1A

T1_cal=0x09c4;//250us with 10MHz fe5680 ext osc

OCR1A=0x09c4;// prevent intcompA_timer one for a short time

TIMSK1=(1 <<OCIE1A);

TCCR1B |= (1 << WGM12)|(1 << CS10);// 8

DDRB |= 2; //B0=xtal_out fuse, B1 swd,

PORTB |=56; //B8 UD_count- pullup

//B16 UDcount+

//B32 offset/trim select

DDRC=7|16; //C1 biphase C32 =offset sel. sw

DDRD|=4|8; // 1pps out

SPI_MasterInit();

pwm_init();

USART_Init(MYUBRR);

Time_out=0;

}

//……………………………..

int main (void)

{

volatile unsigned char i=0,j=0,parity;

startup();

Time_out=0;

bored=0xffff;

sei();

plusone();

while(1)

{

//…………time.data.loop.goes.here………

for (i = 0; i <8; i++)

{

for (j = 0; j <8; j++)//was (j = 0; j <64; j++ for no data)

{//was bored=0; for no data

bored=(time[i]& (1 << j));//bit mask

while(Time_out==0)

{//two “Time_out” as there are two interrupts

//per thingy, one for clock and one for data

PORTB=2;

}

Time_out=0;

while(Time_out==0)

{

PORTB&=~2;

}

Time_out=0;

}

}

plusone();

notplus1();

//—————swd————-

for (j = 0; j <16; j++)

{

bored=(sync_wd& (1 << j));

if(j==1)//scope

{

PORTC|=16;

}

if(j==15)//scope

{ PORTC&=~16;

}

while(Time_out==0)

{

PORTB=2;

}

Time_out=0;

while(Time_out==0)

{

PORTB&=~2;

}

Time_out=0;

OCR1A=T1_cal+T1_offset;

} //end syncword

bitcount=0;

}//while(1)

}//main

//———————-

void notplus1(void)

{char q;

for (q = 0; q <8; q++)

{

time[q]=stored[q];

}

}

Advertisements