Too much F-IN for the CountTransitions() input?

Discussion specific to the 24-pin ZX microcontrollers, e.g. ZX-24r, ZX-24s and ZX-24t.
Post Reply
rpb
Posts: 6
Joined: 08 April 2009, 5:27 AM

Too much F-IN for the CountTransitions() input?

Post by rpb »

Crud - posted this on the ZBasic language forum by mistake, probably should have rightly been here... squuuzzzz me ! anyway, here goes...

sampling RF from 1.8-30mhz with a gimmick capacitor, conditioned, and fed into a divide by 100 chain, tied to input port on zx24p.

On all bands thru 21mhz, frequency is accurately determined. Starting at 24mhz, and particularly on 28mhz, i dont get accurate frequency determination.

same circuit worked fine on Basic Stamp controller even at 28mhz. When using zx24p 28mhz comes out at about 22mhz. BasicStamp Count() only counts one edge, zx24 counts both. So i am sampling at half the rate to get equivalent.

Question - have i hit the limits of f-in for the zx24p hardware ? Or is there something i can to with the prescaler or other ideas to resolve? PCBs are built - dont want to muck with hardware if i can help it.

Also, dont want to stay in the CountTransitions() code long because it holds up my executive loop.

Any help out there??

-bob
BTW - ZBasic/zx24p is so much better than the BasicStamp i never want to look back.
dkinzer
Site Admin
Posts: 3120
Joined: 03 September 2005, 13:53 PM
Location: Portland, OR

Re: Too much F-IN for the CountTransitions() input?

Post by dkinzer »

rpb wrote:Starting at 24mhz, and particularly on 28mhz, i dont get accurate frequency determination.
The longest path through the loop in the CountTransitions function is approximately 2.3us. This would imply a maximum frequency of about 216KHz which would correspond to about 21MHz at the input of the divide-by-100 counter. That seems to correlate reasonably well with your observed results.
rpb wrote:same circuit worked fine on Basic Stamp controller even at 28mhz.
Part of the loop has to check for the RTC timer flag and keep track of how many of those events occur during the CountTransitions period. Without that (which the Basic Stamp does not have, I'm sure) the maximum loop time would probably be on the order of 1.4us.

You might want to take a look at InputCapture() or InputCaptureEx(). The resolution of those routines is about 68ns, more than enough to accurately sample a 300KHz signal (corresponding to 30MHz).
- Don Kinzer
rpb
Posts: 6
Joined: 08 April 2009, 5:27 AM

Freq limit on CountTransitions

Post by rpb »

tnx don.

yep, you hit it right on the head, a little over 21mHz is where it initially seems to start breaking down. I dont need great accuracy, being off a couple of kHz wouldnt matter much. But above this, its off too far to be useful. The project is a high power auto-tuning T-network antenna tuner twisting vacuum variables for C and L with steppers. I bust the bands up into segments, so being off a bit is no biggie.

Unfortunately, my hardware is setup to use pin 20 for freq detect, which isnt a valid pin for the Inputcapture method from what i see in the dox.

would have to modify the hw a bit - swapping pins. Any other recourse?

-bob
dkinzer
Site Admin
Posts: 3120
Joined: 03 September 2005, 13:53 PM
Location: Portland, OR

Re: Freq limit on CountTransitions

Post by dkinzer »

rpb wrote:Any other recourse?
If you were using a native mode device (e.g. ZX-24n) you could write a specialized equivalent to CountTransitions that is optimized for your specific case.

If your counting duration were limited to about 1ms, you could omit the code that tracks RTC interrupts and get a boost in the sampling frequency. The low end of your input frequency produces an 18KHz signal, the period of which is about 56us. With a 1ms counting duration, the 1.8MHz input signal would still give you a transition count of 36. At the upper end, a 30MHz input signal would give you a transition count of 600 so you could keep the count in a 16-bit value. You could push the counting duration higher, if necessary, but when you get closer to 1.95mS you run the risk of losing RTC ticks.

If this option is of interest, I can provide some sample code to get you started. I believe that a specialized version could have a loop cycle time below 1us. This would give you coverage up to 50MHz (unscaled) input frequency.
- Don Kinzer
dkinzer
Site Admin
Posts: 3120
Joined: 03 September 2005, 13:53 PM
Location: Portland, OR

Post by dkinzer »

The code below is an (untested) implementation of the specialized version of the CountTransitions() function that I mentioned above. It is only useful on native mode devices and should be compatible with ZX devices based on the mega644P and mega328P. It could be modified fairly easily for ZX devices based on other AVR chips.

For the mega644P, the sampling loop compiles to code that requires a maximum of 12 cycles meaning that it will correctly detect transitions on an input signal with a low time or high time as small as about 81ns. For a waveform with 50% duty cycle, this corresponds to a frequency at the sampled pin of about 614KHz. With your divide-by-100 prescaler in place that would give coverage up to about 61.4MHz.

Code: Select all

' Define the duration of the counting period.  This value should be less
' than 175% or so of the period of the RTC's "fast tick" period.  For most
' ZX devices, the RTC fast tick frequency is 1024Hz.
Const FastCountTransDuration as Single = 1.5e-3

'
'' FastCountTrans
'
' This is a specialized version of the CountTransitions() function optimized
' for counting transitions on higher frequency signals for a pre-determined
' short period of time on a specified pin.
'
Function FastCountTrans(ByVal pin as Byte) as UnsignedInteger
  ' Initialize the return value.
  FastCountTrans = 0

  ' Determine the bitmask for the specified I/O pin.  If the mask
  ' is zero, the pin was invalid.
  Dim mask as Byte = PortMask(pin)
  If (mask = 0) Then
    Exit Function
  End If

  ' Check that the 16-bit timer is available.
  If (Not Semaphore(Register.Timer1Busy)) Then
    Exit Function
  End If

  ' Get the address of the PINx I/O port corresponding to
  ' the specified pin.  (It is assumed that this is successful
  ' since the pin was validated earlier.)  Also, define a Byte
  ' variable based at the I/O port address to be used in the
  ' sampling loop below.  The 'Volatile' attribute is necessary
  ' to prevent the compiler from optimizing away repetitive
  ' accesses to the I/O port.
  Dim addr as UnsignedInteger = Register.Pin(pin).DataAddress
  Dim Volatile pinVal as Byte Based addr

  Atomic
    ' Set up the timer for regulating the sampling duration.  We need to
    ' keep the sampling duration significantly less than 1.95mS in order
    ' to avoid missing more than one low level RTC interrupt which occur
    ' (typically) at 1024Hz.
    Const OCF1A_MASK as Byte = &H02
    Register.TIMSK1 = 0
    Register.TCCR1A = 0
    Register.TCCR1B = 0
    Register.TCNT1 = 0
    Register.OCR1A = CUInt(FastCountTransDuration * CSng(Register.CPUFrequency))
    Register.TIFR1 = OCF1A_MASK  ' clear the OCF1A bit
    Register.TCCR1B = &H09    ' WGM12 and 1x prescaler

    ' Read the current pin state.
    Dim lastVal as Byte
    lastVal = pinVal

    ' sample the input until the timer period expires.
    Do While (Not CBool(Register.TIFR1 And OCF1A_MASK))
      Dim curVal as Byte

      ' Read the current input value and detect a transition.
      curVal = pinVal
      If CBool((curVal Xor lastVal) And mask) Then
        FastCountTrans = FastCountTrans + 1
        lastVal = curVal
      End If
    Loop
  End Atomic

  ' Turn off the timer and release the semaphore.
  Register.TCCR1B = 0
  Register.Timer1Busy = False
End Function
- Don Kinzer
Post Reply