Shop OBEX P1 Docs P2 Docs Learn Events
Using counters to mirror 1PPS — Parallax Forums

Using counters to mirror 1PPS

pgbpsupgbpsu Posts: 460
edited 2011-03-26 12:57 in Propeller 1
I'd like to use a counter to produce a "1PPS" in a set-it-and-forget-it mode and I'm having trouble.

My first attempt was to use a counter in duty mode so that my fake PPS signal would match (in width) the real one I have (100uS). I wasn't able to get that working. I couldn't tell if that was because I needed to do additional monitoring of the signal in Duty mode or simply because I got it wrong. But I couldn't even tell which of those scenarios I was in (probably the latter).

So I moved to an NCO/PWM mode which would have .5 second width which I'm not crazy about but I can live with. I have 2 questions
1) is Duty mode with a 100uS high pulse really out if I can't dedicate an entire cog to it?
2) how can I sync my fake PPS (code below) to the real PPS?

PRI FAKE_PPS(frequency) | buffer, counter ' Configure the status LED.
  ' taken from Kye's SD card routines.
  ' Frequency must be between 0 and (clkfreq / 2). Otherwise output is always 1.

  buffer := ((0 < frequency) and (frequency =< (clkfreq >> 1)))

  outa[OUTPUT_PIN] := 0
  ctra := (constant((%00100 << 26) + OUTPUT_PIN))
  dira[OUTPUT_PIN] := true

  counter := 1
  repeat 32 ' Preform (((frequency << 32) / clkfreq) + 1)

    frequency <<= 1
    counter <-= 1
    if(frequency => clkfreq)
      frequency -= clkfreq
      counter += 1

 frqa := (counter) ' Output is always 0 if frequency is 0.
 ' next 3 lines were added to try to sync to PPS but clearly that doesn't work
 waitpeq(0, constant(|<PPS_pin), 0)    ' wait for pin to go low
 waitpne(0, constant(|<PPS_pin), 0)    ' wait for pin to go high
 phsa := 0


I've looked over the App note and that's what got me thinking that Duty needs some babysitting. The code from Kye's routines does produce a 1hz square wave, but I'm at a loss when it comes to syncing it to the actual PPS.

Thanks,
Peter

Comments

  • kuronekokuroneko Posts: 3,623
    edited 2011-03-25 18:41
    pgbpsu wrote: »
    1) is Duty mode with a 100uS high pulse really out if I can't dedicate an entire cog to it?
    A DUTY pulse lasts 1 system clock cycle. So unless you want to run your prop at 10kHz you'll need a s/w (assisted) solution.
     ' next 3 lines were added to try to sync to PPS but clearly that doesn't work
     waitpeq(0, constant(|<PPS_pin), 0)    ' wait for pin to go low
     waitpne(0, constant(|<PPS_pin), 0)    ' wait for pin to go high
     phsa := 0
    
    Doesn't work as in ...? You clearly detect the rising edge here. But then you reset the counter to 0 which means the faked pulse only starts half a second later (it has to count up to >= $80000000). So for starters you might want to preset phsa to NEGX. That still leaves the time which is spent by SPIN from edge detection to actually setting the counter. Meaning ideally you want seomthing like NEGX + offset which you'll have to figure out by trial and error or whatever way you prefer.
  • Tracy AllenTracy Allen Posts: 6,666
    edited 2011-03-25 22:06
    A 100 us pulse at 1 second intervals is possible with code like the following, using overlap of both ctra and ctrb in NCO mode. The overlap is 100 us, but the pulse is low-going, not high-going. You could use another free cog counter to invert it, or else use an external inverter.
    CON
      _CLKMODE = XTAL1 + PLL16X
      _XINFREQ = 5_000_000
    PUB HZpps(pin) | Hz1  ' generates 1Hz with pulses 100 us wide.  (low going)
      Hz1 := 54  ' 53.6870912 is the exact divisor
      dira[pin]~~               ' pin for output
      phsa := negx
      phsb := negx-8000-400   ' 100us offset (12.5ns * 8000 cycles) plus 5 us to execute  frqx := variable.
      ctra := constant(%00100 << 26) + pin
      ctrb := constant(%00100 << 26) + pin
      frqb := Hz1
      frqa := Hz1
    
    Even so, the output will not be exactly one Hz. The dominant period with be 0.9942 second (1.005828 Hz) when the frqa=frqb=54. To achieve nominally 1Hz you would need a 4.131584 or 8.263168 MHz crystal.

    I don't think you can sync or phase lock a prop oscillator tightly to the external pps source without using a cog. However, you might be able to sync long term in spin, depending on the goal, because it would take about 170 seconds for the 0.9942 Hz free running counters to drift by 1 Hz in relation to the pps reference (gps?).
  • pgbpsupgbpsu Posts: 460
    edited 2011-03-26 07:27
    kuroneko-

    Thanks for responding and for clarifying the need for maintenance when running in Duty mode. Before being able to get back to the internet I found, in my pdf of the Education Kit labs, that set-it-and-forget-it does not apply to this mode. Running my prop at 10Khz isn't really an option, but that would do what I want.

    You figured out what I mean by doesn't work. My waitxxx commands do respond to the PPS which I have. But setting phsa:=0 on the rising edge of the of the real 1PPS does not align my fake pps with the real one. That's what I meant by doesn't work. Sorry for not being clearer. But your suggestions address that issue. I have a scope and can experiment until the two line up as closely as possible.

    Terry-
    The solution you presented is genius! I'll give it a try as soon as I get back to the hardware setup which has a PPS. My external oscillator is actually 5.12Mhz so my system clock is 81.92Mhz. I'll rework the math in your example and see where that gets me. However your explanation about the time required to drift off by one second leaves me wondering if I'm trying to solve my real problem the wrong way.

    I have a datalogger which has GPS (and 1PPS). The value of the system counter is captured every 1PPS and recorded so data can be time stamped. Problem is the GPS is a power hog so I want to sleep it to save power. My plan is to have the GPS on at boot up, use the 1PPS from the GPS to stamp data for while, then put it to sleep, turn it on later and record it again. The data would have to be adjusted for drift later in processing, but we'd just draw a straight line between the times when the 1PPS was present.

    From a coding standpoint, I thought all my time stamping could be just the same regardless of which PPS my code was watching for. I would set a flag in the data to let the post-processing software know if the time stamp is from a real 1PPS or my fake PPS. However your description of drift makes me think I'd be better of with waitcnt based timer.

    Do I understand the drift inherent in my fake 1PPS correctly? Sleep times for the GPS will exceed 170 seconds (I'd like to sleep it for 10 minutes at a time).

    Thanks,
    Peter
  • Graham StablerGraham Stabler Posts: 2,510
    edited 2011-03-26 07:36
    It might be better to add a low power real time clock of some sort.

    Graham
  • pgbpsupgbpsu Posts: 460
    edited 2011-03-26 08:01
    Hi Graham-

    That would certainly work, but we're trying to make something out of hardware we already have. I'm afraid mods are out at this point. It needs to be a software solution. There's no way to avoid correcting the timing of samples that are acquired when the PPS is not present. And I doubt that an RTC would be accurate enough to prevent this. Over 20 minutes I expect our 5.12Mhz oscillators to be decent (at least as good as an external RTC). There are more than a couple ways to solve this in software. I was hoping to use the counters since they could be setup and left alone without costing me any cogs or any (significant) code space. Maybe I was being too optimistic.
    p
  • Tracy AllenTracy Allen Posts: 6,666
    edited 2011-03-26 11:38
    If your clkfreq is 81.92 MHz, then each clock period is 12.207031 ns. To find the value to use for frqa and frqb, you compute, 2^32 / clkfreq = 2^32 / 81920000 = 52.4288. What that means is that 52.4288 added to an accumulator 81920000 times in one second would add up to 2^32. One trip through the phase accumulator. However, the number that goes into frqa and frqb has to be an integer. You have to choose either 52 or 53. If you choose 52, then it takes a little bit longer to add up to 2^32. In fact, it takes
    INT(2^32 / 52) * 12.207031 nanoseconds = 1.00824614258 second.
    That is a frequency of 0.9918213 Hz
    The drift comes from the 0.008246 second per second remainder, and that amounts to 1/0.008246 = 121 seconds for it to be off by 1 second. Pretty dismal for your intents.

    If you want that 1Hz precisely, you'll need a binary power crystal, or go to plan B.
  • pgbpsupgbpsu Posts: 460
    edited 2011-03-26 11:48
    Hi Tracy-

    Thanks again for your input. It seems like this is a case of "no free lunch". It looks like my best bet is to use waitcnt rather than a cog. I don't have the specs for our oscillator on hand, but it has to give a time base better than 1 in 120. The reason I was avoiding this is because my time keeping code will look one way when I have a PPS and another way when I don't. Oh well. The other reason was I didn't want to tie up a cog in a waitcnt. Although after thinking about it I realize I can probably do other quick non-time critical stuff as long as I know it will take less than a second. I can return from that in time to finish waiting for 1 second to have expired via waitcnt. So at the cost of a bit of code, I think the waitcnt operator is where my solution lies.

    Thanks again for all the input and the clever use of counters to get a 100uS pulse without resorting to DUTY mode.

    Regards,
    Peter
  • groggorygroggory Posts: 205
    edited 2011-03-26 12:57
    Also, I have experimentally verified that waitcnt in spin has a bit of jitter. To be truly precise you'll want this is PASM. What kind of precision do you need?

    (Oops.. Just realized I exactly agree with what Tracy Allen said a couple posts above)
Sign In or Register to comment.