Shop OBEX P1 Docs P2 Docs Learn Events
MCP3208 Single acquisition time — Parallax Forums

MCP3208 Single acquisition time

TCP71TCP71 Posts: 38
edited 2011-05-14 20:11 in Propeller 1
I'm trying to get 100 samples from a single channel of the MCP3208 using the following code:


PRI GetHP | C

C := 0
repeat
hp[C] := ADC.in(0)
C++
while C < 100

The number of samples is less important than the time over which they are acquired. I'm trying to discover how long, in time, the above code will acquire. Is there a known length of time a single "ADC.in(0)" type cycle takes?
Thanks.

Comments

  • StefanL38StefanL38 Posts: 2,292
    edited 2011-05-13 12:26
    hi TCP71,

    easy to measure empirically


    _start := cnt
    hp[C] := ADC.in(0)
    _stop := cnt

    time := _stop - _start

    compare this time with
    _start := cnt
    _stop := cnt

    time := _stop - _start

    to extract the execution time of command hp[C] := ADC.in(0)

    If the systemcounter cnt has wrapped around from max to zero between _start and _stop the result will be wrong

    To avoid this you can use
    a calculation like in the method below
    PUB elapsed_time_msec(p_TimeVar) | RightNow, ClockTicks
    'can measure up to 26843 Milliseconds
    '(2147483647 CounterTicks / 80.000.000 Hz = 26843 Milliseconds) 
    
      RightNow := cnt
    
      if RightNow < p_TimeVar                          
        ClockTicks := ||($FFFFFFFF - RightNow + p_TimeVar)  
      else
        ClockTicks := ||(RightNow - p_TimeVar)
    
      result := ClockTicks / (clkfreq / 1_000) 'calculate milliseconds
    
      '#####################################################################################
      'explanatio how it works
      ' SPIN treats longs as SIGNED longs meaning bit 32 represents the sign "+-"
      ' the systemcounter thinks of the 32bits as UNsigned meaning bit 32 is
      ' just another bit of the number and NOT a sign "+-" 
      ' if one or both values are negative it could happen
      ' that the result is negative too
      ' the command "||" calculates the absolute value of the SIGNED longs
    
      'if the systemcounter has wrapped around since snapshot of
      'systemcounter (value of parameter p_TimeVar),
      'this method calculates the timedifference in the right way
      
      'wrap-around example with easy numbers: counter maxvalue 1000
      'p_TimeVar containing value 980
      'time goes on counter wraps around from 1000 to 0
      'time goes on 
      'RightNow containing 300. This means 20 ticks until maximum 1000 and 300 ticks
      'since wrapping from 1000 to 0 in summary 320 ticks of time has gone
      'this is calculated by MaxCounter - p_TimeVar + RightNow
      'in numbers              1000     -   980     +   300     = 320
      'the real systemcounter has 32bits max value 2^32 -1 = 4294967295
      'hexadecimal $FFFFFFFF
      '#####################################################################################
     
    

    best regards

    Stefan
  • kuronekokuroneko Posts: 3,623
    edited 2011-05-13 18:41
    StefanL38 wrote: »
    If the systemcounter cnt has wrapped around from max to zero between _start and _stop the result will be wrong.
    PUB elapsed_time_msec(p_TimeVar) | RightNow, ClockTicks
    'can measure up to [COLOR="red"]26[/COLOR]843 Milli[COLOR="red"]seconds[/COLOR]
    '(2147483647 CounterTicks / 80.000.000 Hz = 26843 Milliseconds)
    
    ' @80MHz to match the ~26sec range
    
      before := cnt
      ...
      after  := cnt{before+clkfreq*26}
    
      elapsed := after - before
    
    Can you give me a single example for before/after which would justify the use of your method instead of simply subtracting one from the other (ignoring msec conversion)?
  • JonnyMacJonnyMac Posts: 9,208
    edited 2011-05-13 19:50
    Speed will depend on how the code is written; PASM will always be significantly faster than Spin.
  • TubularTubular Posts: 4,717
    edited 2011-05-13 20:21
    I think C will need to be incremented by more than 1 byte as there are (at least) 12 bits in each sample

    TCP71, what rate do you want to sample at? There are objects already for that chip that sample nice and fast. There is a MCP3208_fast_multi somewhere.
  • JonnyMacJonnyMac Posts: 9,208
    edited 2011-05-14 05:53
    I stuck this code into my MCP3208 demo (which uses a Spin driver) and came up with 72ms.
    t := -cnt
      
      analog := 0
      repeat 100
        analog += adc.read(0, adc#SE)
      analog /= 100
    
      t += cnt - 544
    
      term.str(string("Time used: "))
      term.dec(t / (clkfreq/1000) )
      term.str(string("ms"))
    
  • mynet43mynet43 Posts: 644
    edited 2011-05-14 07:25
    There are two types of MCP3208 drivers available.

    The first type runs constantly in the background, cycling thru the requested ports. It always returns the 'current' value of the adc port. If you call this repeatedly, you may end up getting duplicate adc values, because it hasn't had time to complete the next iteration between calls. These values may skew your average calculation.

    The second type of driver calculates a new value each time it is called. This is the true time needed to retrieve a value from the chip. So if you call this repeatedly, you will get a new value each time. This will give you a true average over a number of samples. I believe the time to calculate a sample is around 6000 machine cycles.

    I can give you examples of each type of driver if you're interested.

    Jim
  • StefanL38StefanL38 Posts: 2,292
    edited 2011-05-14 13:12
    @kuroneko,

    as long as you simply watch for a difference of just a second everything stays alright.

    Try the different repeat-loops in the following code and watch the resulting values for at least a minute.
    You will see that at some point the values turn negative and that they get smaller and smaller.

    I tried different versions (calling the method elapsed-time with and without caclculating milliseconds, using local and global variables
    but with all these versions if you wait long enough the values turn negative.

    If you or somebody else can explain to me why this happends only after a certain amount of seconds I appreciate it very much.
    CON
    
      _CLKMODE      = XTAL1 + PLL16X                        
      _XINFREQ      = 5_000_000
    
    VAR
      long Start
      long Stop
      long Diff
            
    OBJ
      debug    : "FullDuplexSerialPlus"
    
    PUB Main | RightNow, ClockTicks
      Debug.Start(31,30,0,115200) 'start(rxpin, txpin, mode, baudrate) :
      ''        '"rx" and "tx" viewed from Propeller-Chip.   Propeller-Chip-PIN-Tx ----> PC
    
    
      Start := cnt
    
      repeat
        Stop := cnt
        ClockTicks := Stop - Start
    
        WaitCnt(ClkFreq / 5 + cnt)
        Debug.Str(string("elapsed_time ="))
        Debug.Dec(ClockTicks)
        Debug.Tx(13)
        Debug.Tx(13)
    
    
      repeat
        Stop := cnt
        ClockTicks := (Stop - Start)
    
        WaitCnt(ClkFreq / 5 + cnt)
        Debug.Str(string("elapsed_time ="))
        Debug.Dec(ClockTicks)
        Debug.Tx(13)
        Debug.Tx(13)
    
    
      repeat
        RightNow := cnt
        ClockTicks := (RightNow - Start)
    
        WaitCnt(ClkFreq / 5 + cnt)
        Debug.Str(string("elapsed_time ="))
        Debug.Dec(ClockTicks)
        Debug.Tx(13)
        Debug.Tx(13)
    
    
      repeat
        WaitCnt(ClkFreq / 5 + cnt)
        Debug.Str(string("elapsed_time ="))
        Debug.Dec(elapsed_time_msec(Start))
        Debug.Tx(13)
        Debug.Tx(13)
        
      repeat
        Start := cnt
        WaitCnt (ClkFreq + cnt)
        Stop := cnt
        Debug.Str(string("Stop - Start ="))
        Debug.Dec(Stop)
        Debug.Str(string(" - "))
        Debug.Dec(Start)
        Debug.Str(string(" = "))
        Diff := Stop - Start
        Debug.Dec(Diff)
        Debug.Tx(13)
        Debug.Tx(13)
    
    
    
    PUB elapsed_time_msec(p_TimeVar) | RightNow, ClockTicks
    'can measure up to 26843 Milliseconds
    '(2147483647 CounterTicks / 80.000.000 Hz = 26843 Milliseconds) 
    
      RightNow := cnt
    
      ClockTicks := (RightNow - p_TimeVar)
    
      {
      if RightNow < p_TimeVar                          
        ClockTicks := ||($FFFFFFFF - RightNow + p_TimeVar)  
      else
        ClockTicks := ||(RightNow - p_TimeVar)
      }
      'result := ClockTicks / (clkfreq / 1_000) 'calculate milliseconds
      result := ClockTicks '/ (clkfreq / 1_000) 'calculate milliseconds 
    
    best regards

    Stefan
  • kuronekokuroneko Posts: 3,623
    edited 2011-05-14 20:11
    StefanL38 wrote: »
    as long as you simply watch for a difference of just a second everything stays alright.

    Try the different repeat-loops in the following code and watch the resulting values for at least a minute. You will see that at some point the values turn negative and that they get smaller and smaller.
    What I was trying to say is this: Your method has a comment saying that it can measure up to ~26sec. This is exactly the range you can cover when you are confined to signed arithmetic (effectively only 31bit available) and running at 80MHz. However, being aware of this limitation (26sec) voids the requirement for this method. I did run one of your loops (slightly modified) and as long as I stay in the 26sec window the method call gives me the same result as simply subtracting start from stop. So why would I use it?
    hex(A-B)  method    dec(A-B)
    elapsed_time = 7D539440 7D539A81  2102629440
    elapsed_time = 7E4C4D20 7E4C5361  2118929696
    elapsed_time = 7F4518E0 7F451F21  2135234784
    elapsed_time = 803DE260 7FC2175F -2143428000
    elapsed_time = 8136AB10 7EC94EAF -2127123696
    elapsed_time = 822F8EB0 7DD06B0F -2110812496
    
    After that the difference (left column) still works until we reached double/full range (~53sec) provided you can handle/ignore the sign.
Sign In or Register to comment.