Non-deterministic PASM loops ?
Paul Rowntree
Posts: 49
Hmmmm. I read Hippy's posting on waitcnt, and I was wondering if this is the same issue that I am up against. The symptoms seem different though.
I have a PASM code that counts edges on a pin, and after a set period of time it reports that number to hub memory and moves on to the next time bin. The hub memory is a array of sequential time bins. Commercial units are called Multichannel Scalers, and cost upwards of $7K (albeit capable of 5 nS bin times). I want to use it to measure the flight time of atoms across a vacuum chamber.
I have coded a version for the Protoboard, but when I look at the clock pulses that mark the boundaries between these bins, I find that there is considerable 'jitter', despite what seems to be a simple waitcnt controlled loop. In most cases it looks like every other bin is longer then shorter, such that the second bin clock signal is exactly on cue. This goes against what I presumed was a 100% deterministic, repeatable timing system.
In the following code, when I request a bin time of an integer multiple of 1.0 microseconds (80n as the waitcnt interval), everything is fine. Any non-multiple of 80 ticks gives jitter in the bin timings, of ~100 nanoseconds. If I remove the hub read/writes, there is never any bin jitter, no matter what parameters I use.
I would be most appreciative if anyone could shed any light on this one.
Cheers !
Paul Rowntree / Guelph Ontario
Post Edited (Paul Rowntree) : 4/11/2008 2:46:06 AM GMT
I have a PASM code that counts edges on a pin, and after a set period of time it reports that number to hub memory and moves on to the next time bin. The hub memory is a array of sequential time bins. Commercial units are called Multichannel Scalers, and cost upwards of $7K (albeit capable of 5 nS bin times). I want to use it to measure the flight time of atoms across a vacuum chamber.
I have coded a version for the Protoboard, but when I look at the clock pulses that mark the boundaries between these bins, I find that there is considerable 'jitter', despite what seems to be a simple waitcnt controlled loop. In most cases it looks like every other bin is longer then shorter, such that the second bin clock signal is exactly on cue. This goes against what I presumed was a 100% deterministic, repeatable timing system.
In the following code, when I request a bin time of an integer multiple of 1.0 microseconds (80n as the waitcnt interval), everything is fine. Any non-multiple of 80 ticks gives jitter in the bin timings, of ~100 nanoseconds. If I remove the hub read/writes, there is never any bin jitter, no matter what parameters I use.
I would be most appreciative if anyone could shed any light on this one.
Cheers !
Paul Rowntree / Guelph Ontario
DAT ' Prop ASM code to operate as a multichannel scaler ' MCS_A ' - internally generated cycle start signal, output on Pin 2 ' - internally generated channel advance timing, output on Pin 1 ' - data accumulated to hub memory ' - good to microsecond channel widths on a Prop1 (chanCnt=80) ' ' this code can drive a series of LEDs to report status of system. For symplicity they are ' all assumed to be connected to pins 0-3 ' ' Pin 0 : When high the MCS is armed; checked at start of every cycle ' Pin 1 : Goes high for 25 nS at the beginning of each channel ' Pin 2 : Is high when the MCS is actively accumulating information. Goes off during deadtime delays ' Pin 3 : Is high during the accumulation of the specified cycles. ' org mcs_A mov cycle, ncycles mov dira, #%00001110 mov ctra, ctra_ ' establish mode and start counter mov frqa, #1 ' increment for each edge seen :newCycle mov thisChan, par add thisChan, #4 ' point to buffer for the start of data. Buffer[noparse][[/noparse]0] holds the cycles counter mov chan, nChans ' load the index that will count how many Channels are acquired waitpne null_, #%1 ' wait here until pin 0 is HIGH indicating system is Armed mov cnt_, cnt ' get the current clock mov old, phsa ' get the pulse count before the bin countdown starts add cnt_, chanCnt ' Program does not accumulate for many seconds if this line is removed ! ' :newChan or outa, #%1110 ' turn on bits 1,2,3 xor outa, #%0010 ' turn off bit 1 waitcnt cnt_, chanCnt ' wait for next Channel time to expire mov new, phsa ' record new count mov temp, new ' make second copy sub new, old ' get difference between this reading and last one rdlong hubcount, thisChan ' this command is exactly 2 in front of wrlong to optimize hub access mov old, temp ' set next delta's base add hubcount, new ' add these new counts to those of previous cycles wrlong hubcount, thisChan ' store the new total back into the hub add thisChan, #4 ' point to the next long in hub memory djnz chan, #:newChan ' if this was not the last bin, jump up to the top of the bin loop xor outa, #%0100 ' toggle bit 2 off during deadtime rdlong chan, par ' use chan for local math just because it is available. Update cycle counter in hub add chan, #1 sub cnt_, chanCnt ' cnt_ was incremented anticipating a channel delay wrlong chan, par add cnt_, deadcnt waitcnt cnt_, chanCnt ' let time slip by while we wait for next cycle to start djnz cycle, #:newCycle ' if this was not the last cycle, then jump back up to the start of the cycle loop xor outa, #%1000 ' turn bit 3 off :die waitcnt cnt_, 0 jmp #:die ' ' The following estimates assume a net clock frequecy of 80 MHz ' ' a note on timing. the accumulation time per cycle = nbins x bincnt (in clock ticks) or nbins x bincnt/80_000_000 (in seconds) ' calculate the deadtime (in seconds) by subtracting the accumulation time (in seconds) from the desired cycle time (in seconds) ' calculate the deadcnt by multiplying the deadtime (in seconds) by 80_000_000 ' ctra_ long %01010 << 26 + 7 'mode + APIN (pin 7) null_ long 0 ' conditional to arm MCS ' ' the following variables can be assigned in Spin PRIOR to the cognew call that launches the MCS ' chanCnt long 120 ' ticks to let pass before advancing to next channel. 80 is 0.001 milliseconds nCycles long 100000 ' how many cycles to accumulate nChans long 5 ' number of channels to accumulate per cycle deadCnt long 160000 ' ticks to let pass from the end of the accumulation to the start of next cycle, 159_920 is 1.999 msec cnt_ res 1 new res 1 old res 1 temp res 1 cycle res 1 chan res 1 thisChan res 1 hubcount res 1 ' this is the number of counts in this Channel accumulated thus far.
Post Edited (Paul Rowntree) : 4/11/2008 2:46:06 AM GMT
spin
11K
Comments
Unfortunately, the memory range will be limited to cog ram with this method. Good luck.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
jazzed·... about·living in·http://en.wikipedia.org/wiki/Silicon_Valley
Traffic is slow at times, but Parallax orders·always get here fast 8)
Can you explain why the hub access causes the jitter? I thought that the hub/cog configuration was intrinsically deterministic (past the first iteration perhaps when the synch has to be established). Perhaps I have missed or over-interpreted something ... Is there a documented way to add another waitcnt inside the loop to restore order and ensure timing regularity?
Cheers!
Your cog will get 1 hub access per every 16 clock cycles. It is totally deterministic.
BUT, if your waicnt is a multiple of something other than 16 clocks, then when you get to
RdLong and WrLong you'll need to wait for your next access slot. Which will be anything
from 0 to 14 clock cycles of waiting - in addition to the instruction processing. The average of
which is 8 cycles (x 12.5ns = 100ns of jitter, but anything from 0 to 187.5ns of jitter will be seen).
What you need to do is store the data for the bin in cog memory at your lock-step time period,
and then copy that snapshot of the value to the hub when you get the chance.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
the likelyhood of jitter in that sequence is low. However, just one miss will cause jitter. Most
loops will have too many instructions somewhere at begin or end that will break the window.
Seeing the results on a real oscilloscope is quite convincing.
I haven't tested multiple of 16 waitcnt, but it makes sense. Mirror's advice sounds reasonable.
Now if you could ping-pong the cogs like in double-buffering maybe, you might have enough time
to save data to hub using rd*/wr* while the other is collecting it with SMC, vs-a-vs. Of course
a cog would need to poll for it's turn to save and it is very likely the active collector will finish
before the active saver. It is unlikely the two cogs would be able to sample exactly back to back.
Good luck.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
jazzed·... about·living in·http://en.wikipedia.org/wiki/Silicon_Valley
Traffic is slow at times, but Parallax orders·always get here fast 8)
Now the only jitter is in the first bin width, even if it is a multiple of 0.2 microseconds. At least I know where the issue is now.
Thank you!