ZEZJ zero error zero jitter period generation

Thread Starter

THE_RB

Joined Feb 11, 2008
5,438
Hi, I've just updated my "zero error 1 second timer routines" page, there is a new section at the bottom that now supports zero-jitter period generation.

Like the other code on the page it will generate any period (or frequency) from any xtal using just one simple constant to set the period. But this new system generates the period with zero jitter (which many people have requested). It is now useful for xtal-locked signal generation etc like to generate exactly 50Hz output or a 1 second clock signal etc.

The algortihm and code may not be immediately obvious so I will explain the basics;

ZEZJ algorithm;
(first, #define PERIOD in TMR0 ticks)
1. generate X interrupts of 100 ticks length
2. generate 1 interrupt of "remainder" length 100-199
3. done! make the event (toggle PIC pin etc)

It is "zero-error" as the interrupt always subtracts the 100 tick period (or remainder period) from TMR0, so that any immediate latency will be corrected on the next interrupt.

It is "zero jitter" because the remainder period syncs to the #defined PERIOD so the event (toggle PIC pin) always happens at exactly PERIOD.

The clever part is the "X*100 + remainder 100-199" because it means that the end of PERIOD can can never conflict with the TMR0 interrupt! This is because subtracting 100-199 will always result in a legal TMR0 count that will be corrected on the next int. So the result is that you can just #define PERIOD and it will automatically generate an exact jitter free period with no messy timing conflicts.

# Note! If you wanted to use the code below to generate other xtal-locked frequencies, you just need to change the PERIOD value (and maybe the xtal);
# toggle PERIOD = (xtal / 4 / freq / 2)
# 1 second; 4MHz xtal, PERIOD = 500000
# 50 Hz; 8MHz xtal; PERIOD = 20000
# 60 Hz; 6MHz xtal, PERIOD = 12500
# 60 Hz; 12MHz xtal, PERIOD = 25000
# 1 second; 8.867238MHz cheap TV xtal, PERIOD = (8867238 / 4 / 2)

Here is the code to generate 50Hz with a PIC 12F675 4MHz xtal.
Code:
/******************************************************************************
  ZeroJitter.c   Generates zero-error and zero jitter interrupt period.
  Open-source  -  21 Nov 2009  -  www.RomanBlack.com/one_sec.htm

  PIC 12F675, 4MHz xtal.
  This is like my zero-error 1 second timing system, that uses a convenient
  constant to set ANY period (with 1 timer tick resolution).
  However this system has zero jitter!
  Can be used to generate 1 second period, or 50Hz freq output etc.
******************************************************************************/

// PERIOD sets the pin toggle freq; toggle PERIOD = (xtal / 4 / freq / 2) 
#define PERIOD 10000   // (xtal 4Mhz) TMR0 1MHz, 10000 = 100Hz toggle (50Hz output)

#define PER_COUNTS ((PERIOD / 100) - 1)  // don't edit this!
#define PER_REMAINDER (PERIOD - (PER_COUNTS * 100))  // don't edit this!

unsigned int pcount;    // used in interrupt to count PER_COUNTS 
//-----------------------------------------------------------------------------


//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void interrupt()
{
  //-----------------------------------------------------
  // this is the TMR0 overflow interrupt.
  // Note! TMR0 has a 3 tick write latency, writes must be -3
  //-----------------------------------------------------
  // check if time to toggle the output pin
  if(!pcount)
  {
    asm {
      movlw 0x01      ; // mask for pin 0
      xorwf GPIO,f    ; // toggle PIC pin GPIO.0
    }
    pcount = (PER_COUNTS+1);    // how many delays to make total
    TMR0 -= (PER_REMAINDER-3);  // first delay will be ==remainder
  }
  // else make a normal delay
  else
  {
    TMR0 -= (100-3);       // make another 100 tick delay
  }
  pcount--;
  //-----------------------------------------------------
  // clear the TMR0 overflow flag and exit
  INTCON.T0IF = 0;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++


//=============================================================================
//   MAIN
//=============================================================================
void main ()
{
  //-----------------------------------------------------
  // PIC 12F675  setup ports
  ANSEL = 0;            // ADC off
  CMCON = 0x07;         // comparators off
  GPIO =   0b00000000;  // clear GPIO
  TRISIO = 0b00000000;  // All outputs
  WPU =    0b00000000;  // pin pullups; 1 = pullup on (for button)

  //-----------------------------------------------------
  // timer setup etc
  OPTION_REG = 0b00001000;    // TMR0 on, 1:1 prescale
  pcount = 0;
  INTCON = 0b10100000;  // GIE on, T0IE on (turn interrupt on) 

  //-----------------------------------------------------
  // main run loop here
  while(1)
  {
    continue;   // loop and do nothing, just let the interrupt happen
  }
}
//-----------------------------------------------------------------------------
This can be used on even the smallest cheapest PICs, I deliberately chose TMR0 for this reason. ROM needed is about 54, RAM needed is 2.

Code was programmed and tested out perfectly, all values of PERIOD >=100.

There is more info here;
http://www.romanblack.com/one_sec.htm
 
Top