Shop OBEX P1 Docs P2 Docs Learn Events
Pretty basic question about constant CNT — Parallax Forums

Pretty basic question about constant CNT

turbosupraturbosupra Posts: 1,088
edited 2010-08-12 21:55 in Propeller 1
From my reading and understanding, correct me if I am wrong please ...

CNT will go 2^32 or 4294967296 and roll over every 53.6870912 seconds at 80mhz

I can correlate time to any divisor of 80mhz then, for example 1/6.67 or .15 seconds equals 12_000_000 cycles?

Is the CNT constant signed? If it is, would I have to write || CNT or write || variable := CNT ?


Part of this is that I should have a better understanding of this constant and also is that I'm trying to deal with roll over and if I convert it to milliseconds, I can go from 53.68 seconds to 49.71 days with a 2^32 register.
I'm a little confused as to why Parallax didn't make only the system CNT at 64 bit register? If my math was right, we'd go from 53 seconds to 7300 years?



Thanks for reading!

Comments

  • Mike GreenMike Green Posts: 23,101
    edited 2010-07-30 17:43
    The Propeller is a 32-bit processor with 32-bit registers and cog memory. It's natural to make the CNT register a 32-bit register. Since at 80MHz, that will hold a count representing about 50 seconds, that's a very reasonable register size for a processor as fast as the Propeller. To make a real time clock, you only have to devote one cog to using CNT to make a 1 second or 10 second time tick, then computing the date and time from that. You can also add an external real time clock with a backup battery which would allow you to either power down the Propeller or have it shift to its (inaccurate) RCSLOW internal clock to save power.

    CNT is unsigned and you can use it for any timing up to about 50 seconds with an 80MHz system clock.

    Typically, you save the current value of CNT at the beginning of a timing interval, then compute (CNT - savedCNT) to get the elapsed time in system clocks. You use CLKFREQ as a reference for computing other time units. For example, to get the elapsed time in milliseconds, you'd compute ( (CNT - savedCNT) / (CLKFREQ / 1000) )
  • turbosupraturbosupra Posts: 1,088
    edited 2010-07-30 19:07
    Thanks Mike!

    Mike Green said...
    The Propeller is a 32-bit processor with 32-bit registers and cog memory. It's natural to make the CNT register a 32-bit register. Since at 80MHz, that will hold a count representing about 50 seconds, that's a very reasonable register size for a processor as fast as the Propeller. To make a real time clock, you only have to devote one cog to using CNT to make a 1 second or 10 second time tick, then computing the date and time from that. You can also add an external real time clock with a backup battery which would allow you to either power down the Propeller or have it shift to its (inaccurate) RCSLOW internal clock to save power.

    CNT is unsigned and you can use it for any timing up to about 50 seconds with an 80MHz system clock.

    Typically, you save the current value of CNT at the beginning of a timing interval, then compute (CNT - savedCNT) to get the elapsed time in system clocks. You use CLKFREQ as a reference for computing other time units. For example, to get the elapsed time in milliseconds, you'd compute ( (CNT - savedCNT) / (CLKFREQ / 1000) )
  • BluhairBluhair Posts: 7
    edited 2010-07-31 03:21
    I wish I had read this several days ago !!!

    I made an object for reading a tachometer and had difficult time with CNT.
    Thanks for the more in depth explanation.

    My code is still a little flakey, I will post it when it smooth.

    Charlie
  • T ChapT Chap Posts: 4,223
    edited 2010-07-31 03:34
    I am trying to understand how ( (CNT - savedCNT) / (CLKFREQ / 1000) ) handles a case where savedCNT is for example 4_294_900_000 and the CNT is 1000 on the next test. 1000 - 4_294_900_000 produces a negative number, and the result even if made absolute is still not the same value as if the rollover had not occurred.
  • Mike GreenMike Green Posts: 23,101
    edited 2010-07-31 04:12
    What you actually have is 2^32 + 1000 - 4_294_900_000. That's the way two's complement subtraction works with 32-bit arithmetic. The result is 68296. With an 80MHz clock, you have 853.7us.
  • T ChapT Chap Posts: 4,223
    edited 2010-07-31 04:29
    So you are saying that there is never a rollover issue, the math always works out regardless. That is convenient.
  • StefanL38StefanL38 Posts: 2,292
    edited 2010-07-31 06:21
    I have tested it.
    Simply calculating (CNT - savedCNT) / (CLKFREQ / 1000) leads to negative values after 26 seconds

    if the negative sign would be eliminated by the "||"-operator I would get values that DECREASE instead of INCREASE.

    SPIN treats longs as SIGNED longs. There must be a possability to get not only 26.000 milliseconds as result but 53.000 milliseconds

    So how is the math done in two's complement to get the full 53-second range that the counter offers?

    best regards

    Stefan
  • AribaAriba Posts: 2,690
    edited 2010-07-31 08:16
    (CNT - savedCNT) handles the wrap around of the CNT because the math is done with 32bit resolution and the CNT also has 32bit resolution. The resulting borrow bit is just dropped and therefore the difference is correct.
    But if the difference is higher then $7FFF_FFFF Spin sees the number as negativ that's why it works only up to 26 seconds with Spin.
    With Assembly you can also do unsigned math.

    A solution with Spin is this:
    milliseconds := (CNT - savedCNT) >> 1 / (CLKFREQ/500)

    The highest bit (the sign bit) is forced to zero by shifting all bits to the right. The resolution is halfed but that really not matters here.

    Andy
  • turbosupraturbosupra Posts: 1,088
    edited 2010-08-02 18:41
    ***Special thanks to StefanL38 for helping me get this far with this project ***


    @Stefan
    I get negative values as well, somehow the math still works on my output calculations though




    @BluHair
    What kind of car is this?
    Here is my code for others trying to do this, it includes error checking where it dumps values that have too great of a change, or are too far out of range.

    Sorry if this breaks forum etiquette as far as attaching code, for some reason I cannot upload .zip files today to the forum?


    You may need to change the math formula at the bottom, depending on how your ECU outputs to your tachometer.

    
    CON
    
    _clkmode=xtal1+pll16x
    _xinfreq=5_000_000
    
    '#########ConstantsforRPMs
    c_EngineRunningPin=1'MAKESURETHISPINISAWAYFROMINTERFERENCEORAPWMPIN(maybegroundedwithapulldownresistor)
    c_IgnitionOnPin=2
    c_StarterPin=25
    
    c_WaitingforRPM
    c_Starterturningover
    c_DetectFirstRPMPulse
    c_Default
    
    
    OBJ
    
    Debug:'FullDuplexSerial''Ifyoudon'tusethis,youshoulditmakeslifemucheasier,it'slocatedinParallax'sattachments
    
    
    
    
    VAR
    
    
    '###################VariablesforRPMs
    
    longtimeoflastpulse
    longpulsecount
    longRPMPulseonerisingedge
    longRPMPulsetworisingedge
    longRPMPulseonetrailingedge
    longRPMPulsetwotrailingtime
    longrpmtime
    longrpms
    longrpmhighlow
    longrpmcount
    longcaroff
    longstarterturningovertime
    longRPMPulseonerisingtime
    longRPMPulsetworisingtime
    longrpmpulsehigh
    longrpmpluselow
    longRPMPulseonetrailingtime
    longrpmpulselow
    longrpmcalculatedtime
    longrpm_stack[20]
    longRPMDebugupdatetime
    longrpmcalculatedtimeprevious
    longrpmcalculatedtimeerror
    
    
    
    
    PUBMain
    
    Debug.Start(31,30,0,115200)'startcogwithserialdriver
    waitcnt((clkfreq*3)+cnt)'makeslifeeasierwhenstartingtodebugwitha2secondpausetogettheserialvieweractiveandreceiving
    
    Debug.Tx(13)
    Debug.Tx(13)
    Debug.Tx(13)
    Debug.Str(string('*/\*/\*/\*/\*/\*/\*/\*START*/\*/\*/\*/\*/\*/\*/\*Abouttoentermainpub'))'fordebugpurposes
    Debug.Tx(13)
    Debug.Tx(13)
    Debug.Tx(13)
    
    
    
    '#######Defineinputsandoutputshere
    
    dira[c_EngineRunningPin]:=0'pinisaninput
    dira[c_IgnitionOnPin]:=0'pinisaninput
    ina[c_EngineRunningPin]:=1'pinlooksforahighvalue
    ina[c_IgnitionOnPin]:=1'pinlooksforahighvalue
    dira[c_StarterPin]:=1'temporarilyhavepinsettoanoutput
    
    
    
    
    '#######Callallcogshere
    
    Cognew(Measure_RPM,@RPM_stack)
    Cognew(Debug_Output(@Debug_Stack2,@Debug_Stack3,@Debug_Stack4),@Debug_Stack1)
    
    
    Debugupdatetime:=0
    
    repeat
    'loopsfromhere
    
    
    If(Debugupdatetime+clkfreq)=<cntORDebugupdatetime==0
    '#######Calldebugvalueshere
    'Debug_Output(p_Stringbeforevariable,p_variable,p_IfNewLine)
    'Debug_Output(string('='),ina[],true)
    Debug.Tx(13)
    Debug.Str(string('***********'))
    Debug_Output(string('Keyison?='),ina[c_IgnitionOnPin],false)
    Debug_Output(string('Engineison?='),ina[c_EngineRunningPin],false)
    Debug_Output(string('Starterison?='),ina[c_StarterPin],false)
    Debug_Output(string('TrunkPulseisseen='),ina[c_PulseInputPin],true)
    Debug_Output(string('RPMValueis='),rpms,false)
    Debug_Output(string('CaseRPMcountisincasenumber='),rpmcount,false)
    {Debug_Output(string('='),ina[],true)
    }
    Debug.Str(string('***********'))
    Debug.Tx(13)
    
    Debug.Tx(13)
    Debug.Str(string('Debugupdatetimeis='))
    Debug.Dec(Debugupdatetime)
    Debug.Tx(13)
    Debugupdatetime:=cnt
    
    
    
    
    PUBMeasure_RPM
    
    
    dira[c_EngineRunningPin]:=0'pinisaninput
    dira[c_IgnitionOnPin]:=0'pinisaninput
    ina[c_EngineRunningPin]:=1'pinlooksforahighvalue
    ina[c_IgnitionOnPin]:=1'pinlooksforahighvalue
    
    rpmcount:=c_WaitingforRPM
    RPMPulseonerisingedge:=false
    
    repeat'loopsfromhere
    
    
    caserpmcount'casename
    
    
    c_WaitingforRPM:'1stcase
    
    Ifina[c_IgnitionOnPin]==1
    Debug.Str(string('Ignitionison,waitingforRPMpulse'))
    Debug.Tx(13)
    WaitPeq(0,|<c_EngineRunningPin,0)'waitforrpmpinlow
    Debug.Str(string('Lowdetected'))
    Debug.Tx(13)
    WaitPeq(|<c_EngineRunningPin,|<c_EngineRunningPin,0)'waitforrpmpinhigh
    Debug.Str(string('Highdetected'))
    Debug.Tx(13)
    rpmhighlow:=cnt'setavariabletocntafterthefirsthighlow
    rpms:=0
    Debug.Str(string('High/Lowdetected'))
    Debug.Tx(13)
    rpmcount:=c_Starterturningover'gotonextcasescenario
    
    
    Else
    waitcnt((clkfreq/2)+cnt)'waitfor1/10thofasecond
    Debug.Str(string('Ignitionisoff,waitingforRPMPulse'))
    Debug.Tx(13)
    rpms:=0
    RPMPulseonerisingedge:=false'initializethisvaluetofalse
    RPMPulseonetrailingedge:=false'initializethisvaluetofalse
    rpmcount:=c_WaitingforRPM'loopbacktothiscasestatementuntiltheignitionturnson
    
    
    
    c_Starterturningover:'2ndcaseusethisifyoufeedthestartersolenoidwireintothepropasareference
    
    Ifc_StarterPin==1'ifkeyisinstartposition
    rpms:=0
    WaitPeq(|<c_StarterPin,|<c_StarterPin,0)'waitforkeynottobeinstartposition
    Debug.Str(string('Waiting2secondsafterstartersignalgenerated'))
    Debug.Tx(13)
    Waitcnt((clkfreq*2)+cnt)
    starterturningovertime:=cnt
    
    Else
    rpmcount:=c_DetectFirstRPMPulse'nostartersignal,lookforfirstrpmpulse
    
    
    
    c_DetectFirstRPMPulse:'3rdcase
    
    Ifc_IgnitionOnPin==0'ifignitionpinisoff,gobacktowaitingforrpm
    Debug.Str(string('Ignitionisoff,goingbackto*WaitingforRPM*'))
    Debug.Tx(13)
    rpmcount:=c_WaitingforRPM
    
    
    Elseifc_StarterPin==1'gobacktostartercrankingovercase,ifstarterpinishigh
    rpmcount:=c_Starterturningover
    Debug.Str(string('Goingbacktoc_Starterturningover'))
    Debug.Tx(13)
    
    
    
    Else
    
    Ifina[c_EngineRunningPin]==1
    rpmpulsehigh:=||cnt
    
    
    WaitPeq(0,|<c_EngineRunningPin,0)'waitforpinlow
    
    
    Ifina[c_EngineRunningPin]==0
    rpmpulselow:=||cnt
    
    
    
    WaitPeq(|<c_EngineRunningPin,|<c_EngineRunningPin,0)'waitforpinhigh
    RPMPulseonerisingtime:=cnt
    
    
    
    WaitPeq(0,|<c_EngineRunningPin,0)'waitforpinlow
    WaitPeq(|<c_EngineRunningPin,|<c_EngineRunningPin,0)'waitforpinhigh
    RPMPulsetworisingtime:=cnt
    
    
    
    rpmcalculatedtime:=RPMPulsetworisingtime-RPMPulseonerisingtime
    
    rpmcalculatedtimeerror:=false
    
    Ifrpmcalculatedtime=>6_015_037ORrpmcalculatedtime=<240_000
    
    rpmcalculatedtimeerror:=true
    Debug.Str(string('RPMcalculatedERRORvaluetooloworhigh,settingerror=true'))
    Debug.Tx(13)
    
    ElseIfrpmcalculatedtime=<rpmcalculatedtimeprevious-700_000ORrpmcalculatedtime=>rpmcalculatedtimeprevious+700_000
    rpmcalculatedtimeerror:=true
    Debug.Str(string('RPMcalculatedERRORdeltachangetoogreat,settingerror=true'))
    Debug.Tx(13)
    
    rpmcalculatedtimeprevious:=rpmcalculatedtime
    
    Ifrpmcalculatedtimeerror==true
    rpms:=0
    Debug.Str(string('RPMcalculatedERRORrpmcalculatedtimeerror=1,dumpingvalues'))
    Debug.Tx(13)
    
    Else
    rpms:=(((clkfreq/rpmcalculatedtime)*60)/2)'thereare2pulsesperrevolution,ifyourECUdoesthisdifferentlyyou'llhavetochangeyourmathhere
    
    
    
    
    
    
    c_Default:
    Debug.Str(string('Inthedefaultstatement,goingbacktowaitingforRPM'))
    Debug.Tx(13)
    waitcnt((clkfreq/4)+cnt)
    rpmcount:=c_WaitingforRPM
    
    
    
    
    




    StefanL38 said...
    I have tested it.
    Simply calculating (CNT - savedCNT) / (CLKFREQ / 1000) leads to negative values after 26 seconds

    if the negative sign would be eliminated by the '||'-operator I would get values that DECREASE instead of INCREASE.

    SPIN treats longs as SIGNED longs. There must be a possability to get not only 26.000 milliseconds as result but 53.000 milliseconds

    So how is the math done in two's complement to get the full 53-second range that the counter offers?

    best regards

    Stefan
  • AJMAJM Posts: 171
    edited 2010-08-02 19:20
    Maybe I'm a little late to the party but I needed to measure engine RPM last year for a project.

    Jon Williams has a nice object in the exchange that works flawlessly if you are simply measuring the output waveform from the PCM:

    obex.parallax.com/objects/479/

    Good Luck.

    Post Edited (AJM) : 8/2/2010 7:46:50 PM GMT
  • turbosupraturbosupra Posts: 1,088
    edited 2010-08-07 23:41
    This is still causing me headaches. I don't understand why count would be signed?

    I've had mixed results with using the || operator as well.

    Does anyone have a full proof way of doing this?
  • T ChapT Chap Posts: 4,223
    edited 2010-08-08 01:02
    How fast do you need to get a time update? Can you explain what you want to accomplish more specifically? CNT is unsigned, but to deal with CNT in SPIN requires that SPIN handle CNT as a signed long. If CNT is negative, then you can do some math to correct the problem after 26 seconds. For example, when the value becomes negative, then subtract the negative number from 2_147_483_647, and then work with two sets of positive values from 0 to 2_147_483_647. This takes a few instructions, but since you are in SPIN anyway who cares. If you need really precise measurements you need to do this in ASM.

    This crude but you get the idea, I just tested this and get 2 sets of 0 - 2147483647 back to back. This may need to be cleaned up on the last digits.

    VAR Long NewCnt

    PUB GetCNT
    ...If CNT < 0
    .....NewCNT := 2,147,483,647 - (||CNT + 1)
    .....Return NewCNT
    ...elseIf CNT => 0
    .....Return CNT

    If you just need a time stamp every 52 seconds, you could scan for a certain CNT value in a loop, when the loop sees a value withing the window, then do something. In a SPIN loop you may miss a specific CNT number, so if the timing requirements can handle a little tolerance per iteration (will not accumulate an error), then you can check for a small window of time in CNT to be sure not to miss it:

    If CNT > 1 AND CNT < 5000
    do something
  • SeariderSearider Posts: 290
    edited 2010-08-08 07:02
    You asked for a fool proof way of calculating. Here is what I do
    repeat
      tmp := cnt
      dosomethng
      Pre_time_Elapsed = Cnt - Tmp
      If Pre_Time_Elapsed < 0
        NEXT
      else
        Real_Time_Elapsed = Pre_Time_Elapsed
    

    As you can see in the example above, all I do is test to see if the calculated time elapsed is <0 and if so, then just skip this measurement cycle. You can optimize the way I have coded this to reduce lines. I purposely expanded it a little to make it easier to read.

    this will only work if
    1. The worst case lenght of a measurement cycle is less than 50 seconds or so (Cnt Rap time)
    2. You can afford to allow the time elapsed measure to skip an update every 50 seconds (Cnt Rap Time)
  • turbosupraturbosupra Posts: 1,088
    edited 2010-08-08 07:20
    I'm not doing anything faster than 1ms, but an example of what I'm doing is I have my prop connected to a BCD and the BCD connected to 6 different LED's.

    The prop will send a binary number to the BCD, and turn on ONE of the LED's (via the anode) for 1ms, then it will cycle to the next LED, send a different binary number to the BCD and turn that LED on for 1ms and so on ... This way I use 10 pins for my 6 LED's instead of 24.

    When spin goes negative, it hoses the whole operation. One of the lines of code I tried but couldn't use because of the signed stuff is
    repeat while ((clkfreq/c_ledoscillationvalue) + led1equals1) => cnt
    
    
  • localrogerlocalroger Posts: 3,452
    edited 2010-08-08 07:50
    turbosupra, as long as you're not timing intervals over 26 seconds the negativity shouldn't affect you. 2's complement math is circular; if you keep adding to a 2's complement number it eventually rolls over. With unsigned math it rolls from 4294967295 to zero; with signed math it rolls from 2147483647 to -2147483648. The thing that is probably confusing you is that when you do a time interval subtraction where the result is less than 2147483647, it doesn't matter whether the sources are considered signed or unsigned; the subtraction will roll past the breakpoint regardless and you will get the same result.

    For example, let's say you start timing with cnt at $FFFF_FFFE and end at $0000_0002. In signed math that's simple enough; $FFFF_FFFE is -2 so 2 - (-2) = 4. But with unsigned math it's 2 - 4294967294 or -4294967292. That's not what you want! But that's a signed number and you're using unsigned math; rolling has the effect of adding (or subtracting in the other direction) $1_0000_0000 to the result to get it within the limits, so -4294967292 + 4294967296 = 4. Same result!
  • turbosupraturbosupra Posts: 1,088
    edited 2010-08-08 08:11
    Here is what I tried for the past 1/2 hour, it still wants to count down to negative numbers


    CON
      _clkmode = xtal1 + pll16x
      _xinfreq = 5_000_000
    
    
    OBJ
      Debug : "FullDuplexSerial"
                   
    
    VAR
      long c_unsignedcnt
    
    
    
    PUB Main
    
      Debug.Start(31,30,0,115200) 'start cog with serial driver
      waitcnt((clkfreq * 3) + cnt)          ' makes life easier when starting to debug with a 3 second pause to get the serial viewer active and receiving
    
      Debug.Tx(13)
      Debug.Tx(13)     
      Debug.Tx(13)
      Debug.Str(string(" */\*/\*/\*/\*/\*/\*/\* START */\*/\*/\*/\*/\*/\*/\* About to enter main pub"))          ' for debug purposes
      Debug.Tx(13)
      Debug.Tx(13)     
      Debug.Tx(13)
      
      repeat
    
         
        if cnt > 0
          c_unsignedcnt := cnt
          Debug.Str(String("if "))
          Debug.Tx(13)
        elseif cnt < 0
          c_unsignedcnt := (2_147_483_648 + (2_147_483_648 + cnt))
          Debug.Str(String("elseif "))
          Debug.Tx(13) 
    
        Debug.Tx(13)
        Debug.Str(String("unsigned count is "))
        Debug.Dec(c_unsignedcnt)
        Debug.Tx(13)
        Debug.Dec(||cnt)
        Debug.Tx(13) 
    
    

    unsigned count is 2145448196
    2145689716
    if

    unsigned count is 2145810148
    2146048180
    if

    unsigned count is 2146161636
    2146403156
    if

    unsigned count is 2146520132
    2146758164
    if

    unsigned count is 2146878596
    2147120116
    if

    unsigned count is 2147237060
    2147471508
    elseif

    unsigned count is -2147377804
    2147113228
    elseif

    unsigned count is -2146991724
    2146723628
    elseif

    unsigned count is -2146602124
    2146337484
    elseif

    unsigned count is -2146215980
    2145951436
    elseif

    unsigned count is -2145829932
    2145561836
    elseif

    unsigned count is -2145440332
    2145175724
    elseif

    unsigned count is -2145054220
    2144793100
    elseif

    unsigned count is -2144678668
    2144410572
    elseif
  • turbosupraturbosupra Posts: 1,088
    edited 2010-08-08 08:21
    Hi localroger,

    I don't understand the asm to be perfectly honest, but I can tell you that the complement ideal does not work when I write code such as
    repeat until (snapshotofcnt + clkfreq < cnt)
    

    If half of cnts cycle is a negative number, this repeat loop will not run for ~26 seconds.


    So either there has to be a better way to calculate time, or a better way for me to write my loops, both of which I'm not sure how to do.

    localroger wrote: »
    turbosupra, as long as you're not timing intervals over 26 seconds the negativity shouldn't affect you. 2's complement math is circular; if you keep adding to a 2's complement number it eventually rolls over. With unsigned math it rolls from 4294967295 to zero; with signed math it rolls from 2147483647 to -2147483648. The thing that is probably confusing you is that when you do a time interval subtraction where the result is less than 2147483647, it doesn't matter whether the sources are considered signed or unsigned; the subtraction will roll past the breakpoint regardless and you will get the same result.

    For example, let's say you start timing with cnt at $FFFF_FFFE and end at $0000_0002. In signed math that's simple enough; $FFFF_FFFE is -2 so 2 - (-2) = 4. But with unsigned math it's 2 - 4294967294 or -4294967292. That's not what you want! But that's a signed number and you're using unsigned math; rolling has the effect of adding (or subtracting in the other direction) $1_0000_0000 to the result to get it within the limits, so -4294967292 + 4294967296 = 4. Same result!
  • T ChapT Chap Posts: 4,223
    edited 2010-08-08 08:52
    turbosupra wrote: »
    elseif cnt < 0
    c_unsignedcnt := (2_147_483_648 + (2_147_483_648 + cnt))


    This does go negative. You should first get an understanding of what these values really are before doing the math. Print out the value 2_147_483_648 alone and you will see that SPIN considers that number to be 0. So you are really saying in that formula:

    0 + (0 + CNT) which goes negative just like it always did. I posted code above that perfectly cycles from 0 to 2_147_483_647, not sure why you are changing the formula when the one posted works.

    2_147_483_647 is the maximum number allowed in signed numbers with SPIN. -2_147_483_648 is the lowest. If you write 2_147_483_648 then SPIN considers it 2_147_483_647 + 1.

    There are 16 counters on the Prop that are amazing at doing 32 bit counting locked to the system clock. You should take a look at the App note for the counters, they may make things easier for you.
  • turbosupraturbosupra Posts: 1,088
    edited 2010-08-08 09:25
    T-Chap,

    Thanks for replying, I tried your way but didn't have success, but I will try again.

    I'm getting closer with the bitwise shift operator >>, but I will try your way first.

    The fact that CNT goes - completely hoses the whole thing no matter what I seem to try.




    T Chap wrote: »
    This does go negative. You should first get an understanding of what these values really are before doing the math. Print out the value 2_147_483_648 alone and you will see that SPIN considers that number to be 0. So you are really saying in that formula:

    0 + (0 + CNT) which goes negative just like it always did. I posted code above that perfectly cycles from 0 to 2_147_483_647, not sure why you are changing the formula when the one posted works.

    2_147_483_647 is the maximum number allowed in signed numbers with SPIN. -2_147_483_648 is the lowest. If you write 2_147_483_648 then SPIN considers it 2_147_483_647 + 1.

    There are 16 counters on the Prop that are amazing at doing 32 bit counting locked to the system clock. You should take a look at the App note for the counters, they may make things easier for you.
  • turbosupraturbosupra Posts: 1,088
    edited 2010-08-08 10:11
    T Chap

    Although that may work, it still does not work within my loops

    repeat while (variable + clkfreq) => (cnt >> 1)

    If I want the code to do something for a second, and then update


    How do you write your loops to take advantage of your newcnt?
  • ErNaErNa Posts: 1,753
    edited 2010-08-08 10:57
    Without having followed the whole discussion, there is a question about wrapping around of CNT. The answer may be hidden in this thread: http://forums.parallax.com/showthread.php?t=122997&highlight=Erna
  • localrogerlocalroger Posts: 3,452
    edited 2010-08-08 11:09
    tubosupra: snapshotofcnt + clkfreq < cnt

    Yes, that's pushing past the rollover without recovering properly if cnt has rolled over. The way you do it is this:

    cnt - snapshotofcnt > clkfreq

    That will work.
  • turbosupraturbosupra Posts: 1,088
    edited 2010-08-08 11:30
    You are the man localroger, that is what I was doing wrong! Thank you

    localroger wrote: »
    tubosupra: snapshotofcnt + clkfreq < cnt

    Yes, that's pushing past the rollover without recovering properly if cnt has rolled over. The way you do it is this:

    cnt - snapshotofcnt > clkfreq

    That will work.
  • T ChapT Chap Posts: 4,223
    edited 2010-08-08 11:32
    Based on what you are describing I would use the counters. You could either put this inside another loop, or make it's own cog and use pointers to variables if needed. The counters are designed to count from the system clock, and allow you to fashion any type of count needed. The following makes a beep every clkfreq/10 but you could use clkfreq/1000 for a result every millisecond. Using the counters you never bother with signed values.

    CON
    _clkmode = xtal1 + pll16x
    _xinfreq = 5_000_000

    OBJ
    spk : "CLEAN_piezospeaker3.01"
    PUB timer
    ....ctra := %00110 << 26
    ....repeat
    ......frqa := 1 'count by 1 at clkfreq
    ......phsa := 0 'set counter to 0
    ......repeat while phsa =< clkfreq/10 'count up to some number
    ......spk.beep(19, 3000, 20) 'beep as test only
    ......'do something here
    ......phsa := 0 'reset the counter to 0
  • turbosupraturbosupra Posts: 1,088
    edited 2010-08-10 14:07
    I'll give this a shot, thanks T Chap

    T Chap wrote: »
    Based on what you are describing I would use the counters. You could either put this inside another loop, or make it's own cog and use pointers to variables if needed. The counters are designed to count from the system clock, and allow you to fashion any type of count needed. The following makes a beep every clkfreq/10 but you could use clkfreq/1000 for a result every millisecond. Using the counters you never bother with signed values.
  • AribaAriba Posts: 2,690
    edited 2010-08-10 17:19
    turbosupra

    it is still not clear to me, what you want to do.
    The negative cnt values are only a problem if you try to measure time intervals longer then 27 seconds (up to max. 54 seconds).
    But from what you describe, I think you will just do a 1ms delay.
    For that exists the waitcnt command.

    So for measuring a time interval:
    time := cnt
      ..do something
      time := cnt - time    'time in 12.5ns steps up to 27sec
    
    
      time := cnt
      ..do something
      time := (cnt - time) >> 1    'time in 25ns steps up to 54sec
    

    and for doing a 1ms delay:
    ..do something
      waitcnt(clkfreq/1000 + cnt)   '1ms delay
    
    
      time := cnt
      ..do something
      waitcnt(time + (clkfreq/1000)) '1ms inclusive time for ..do something
    

    Andy
  • turbosupraturbosupra Posts: 1,088
    edited 2010-08-12 21:55
    I'll give that a shot, thank you very much for the reply :)
Sign In or Register to comment.