Shop OBEX P1 Docs P2 Docs Learn Events
Pitfalls and crawling out... GetSec() behaves not as I expected, to slow and counting down — Parallax Forums

Pitfalls and crawling out... GetSec() behaves not as I expected, to slow and counting down

ErNaErNa Posts: 1,803
edited 2025-03-11 11:32 in PASM2/Spin2 (P2)

I use this setting for timing:

con { timing }

  CLK_FREQ = 200_000_000                                        ' system freq as a constant
  MS_001   = CLK_FREQ / 1_000                                   ' ticks in 1ms
  US_001   = CLK_FREQ / 1_000_000                               ' ticks in 1us

  _xtlfreq = 20_000_000 '25_000_000
  _clkfreq = CLK_FREQ                                           ' set system clock

repeat
    term.PutValhex ( 5, 15, "i", ":", GetCt() )
    term.PutValhex ( 5, 16, "T", ":", Getsec() )
    term.PutValhex ( 5, 17, "S", ":", GetmS() )


But GetSec() needs about 10 seconds to count. Do I have to configure something else?
The baud rate works perfect with the setting, I'm using a P2 Eval board
p.s. GetSec counts backward

Some more analysis: GetCt() works as expected, Getsec() counts when GetCt() wraps round. Getms() counts fast, but not milliseconds and GetSec and Getms start at $FFFF_FFFF and count down

Strange things happen: If I use Getsec() is a demo program, it works fine. But no longer in the application., running in a different COG. GetSec() actually counts backward at the overflow of GetCt().
I'll run more tests when time comes..

Comments

  • JonnyMacJonnyMac Posts: 9,249
    edited 2025-03-02 21:30

    It's very possible that you're creating a buffer overrun in the terminal you're using. There is no breathing room between loops in your code to let the terminal clear its buffer. If it takes more time to process/display your input than it does for the terminal to receive it, you'll eventually step on yourself.

    I ran a simple test and getsec() works as expected (incrementing count). I used PST (which has that overrun problem if you don't give it breathing room).

  • JonnyMacJonnyMac Posts: 9,249

    This seems to work, too:

  • ErNaErNa Posts: 1,803

    Thanks for help, it was just to take advantage of this new feature. The application is quite complex and doesn't work completely, I finally did it the old-fashioned way and now the display show the right ticks of seconds. The moment the screen updates all the variables (just now, it is reluctant), I'll give GetSec() another try.

  • ErNaErNa Posts: 1,803
    edited 2025-03-02 22:33

    Where to find the subtle difference between
    _clkfreq, clkfreq and clkfreq_?

  • evanhevanh Posts: 16,353
    edited 2025-03-02 23:09

    Last section, called Clock Setup, of Spin 2 Language Documentation - https://docs.google.com/document/d/16qVkmA6Co5fUNKJHF6pBfGfDupuRwDtf-wyieh_fbqw

    • _clkfreq and _clkmode are the user constants of desired startup sysclock frequency/mode to be compiled. Should never be used in methods. Only define in the CON section.
    • clkfreq_ and clkmode_ are the compiled constants of startup sysclock frequency/mode. Use these in your methods.
    • clkfreq and clkmode are system variables that contain dynamic runtime settings. These are adjusted by clkset(). If such is used then all timing methods should also use these variables in place of the above compiled constants.

    I used both in pllset() method. It adjusts the runtime variables as well as extracting board specific compile-time parameters from the constants - https://obex.parallax.com/obex/pllset/

  • ErNaErNa Posts: 1,803

    OK. I now have a first statement in the Main: clkset (clkmode_, clkfreq_) and the program show sound behavior, no symptoms of overrun. Another step. Thanks.

  • ErNaErNa Posts: 1,803

    I'm falling into another pit: as mentioned, I initated clkfreq : clkset (clkmode_, clkfreq_) A timer is running on a cog started. This timer created problems before, because I migrated software from the P1, that used clkfreq, the compiler was fine with that.
    Now I'm working to implement Cluso's LCD driver, overcome some hurdles, but so far, it's ok. What happens: In the main I create a tick reading clkfreq
    if (tick - GetCt()) < 0 Lcd_.HandsRoundclock() tick += clkfreq ' +1S
    This works as long as I do not activate the other cog creating a tick. I checked, I never write to clkfreq and I only once use clkset.
    If I change clkfreq to clkfreq_, it works fine.
    The behavior is, that clkfreq looks to be a constant, because ticks run for about the same time as they stall. I'll try to find the reason, but any idea is welcome.

  • If you only want to set speed once, do not use CLKSET, just set

    CON
    _CLKFREQ = 300_000_000 ' Or whatever you need it to be
    

    Computing the right clkmode value at runtime is tricky

  • ErNaErNa Posts: 1,803

    If I understood correctly, clkfreq and clkfreq are constants. clkfreq is a register. From Spin-documentation:
    CLKSET(NewCLKMODE, NewCLKFREQ) Safely establish new clock settings and update CLKMODE and CLKFREQ.
    As ClkFreq is located in Hub-Ram, I suspect, I accidently overwrite this location, have to investigate...

  • evanhevanh Posts: 16,353

    @ErNa said:
    clkfreq is a register.

    HubRAM variable only.

    As ClkFreq is located in Hub-Ram, I suspect, I accidently overwrite this location, have to investigate...

    That would be bad,

  • JonnyMacJonnyMac Posts: 9,249
    edited 2025-03-10 17:18

    I'm really simple. I set the program running speed from the constants section in my topmost cog.

    con { timing }
    
      CLK_FREQ = 200_000_000                                        ' system freq as a constant
      MS_001   = CLK_FREQ / 1_000                                   ' ticks in 1ms
      US_001   = CLK_FREQ / 1_000_000                               ' ticks in 1us
    
      _clkfreq = CLK_FREQ                                           ' set system clock 
    

    Since child objects don't have access to my CLK_FREQ constant, they use the system variable clkfreq to determine running speed when needed.

  • evanhevanh Posts: 16,353

    @JonnyMac said:
    Since child objects don't have access to my CLK_FREQ constant, they use the system variable clkfreq to determine running speed when needed.

    Wise move for library type code. It can then handle the user program making runtime frequency changes too.

  • ErNaErNa Posts: 1,803

    OK, it looks as if the hub ram is corrupted. I output the value, correct 200.000.000, the moment, the other program starts, it nullified. So there is a bug in another place and I have to find it. So using this register is a bug-indicator ;-)

  • ErNaErNa Posts: 1,803

    clkfreq is located $44 in hub memory. So it is unlikely I overwrite this location and the SPIN-interpreter is not corrupted? I tested $40 and $48, they are unchanged ;-(

  • ErNaErNa Posts: 1,803

    I'm coming close:

                 long[LONG[@Val011[MirrOffs]]] := ((long[LONG[@Val014[MirrOffs]]]*AnzaPoPa)<<12 / WklMeDiv)//3600  
                 long[LONG[@Val009[MirrOffs]]] :=   long[LONG[@Val014[MirrOffs]]]          <<12 / WklMeDiv
                 long[LONG[@Val007[MirrOffs]]] := (((long[LONG[@Val079[MirrOffs]]]*((ClkFreq~>8))) / long[LONG[@Val080[MirrOffs]]]~>8)*60) / IncrRevo
    

    I can see, that clkfreq ($44) is set to zero, if and only if, the last of the lines above is executed. If the line is commented out, the timer runs correctly! Maybe there is a bug only when this program is running on a P2. We'll see.

  • evanhevanh Posts: 16,353
    edited 2025-03-10 23:14

    Yep, the ~ operator changed from Spin1 to Spin2. It now erases the variable!
    From docs:

    var~ Return var, post-clear all bits in var

    EDIT: Oh, err, wow, never even knew about ~> operator. The equivalent Spin2 is: (ClkFreq SAR 8)

    PS: I wouldn't used that operator though. The frequency variable is unsigned in nature. Just use >> right-shift operator instead.

  • ErNaErNa Posts: 1,803
    edited 2025-03-11 07:55

    That's unexpected:
    Separation of ClkFreq fixes the problem!

                 fxck := ClkFreq
                 long[LONG[@Val007[MirrOffs]]] := (((long[LONG[@Val079[MirrOffs]]] * (( fxck~>8))) / long[LONG[@Val080[MirrOffs]]]~>8)*60) / IncrRevo
    

    Even if I shift ClkFreq~>2, the variable is set to $0

  • ErNaErNa Posts: 1,803

    @evanh said:
    Yep, the ~ operator changed from Spin1 to Spin2. It now erases the variable!
    From docs:

    var~ Return var, post-clear all bits in var

    PS: I wouldn't used that operator though. The frequency variable is unsigned in nature. Just use >> right-shift operator instead.

    Thanks, luckily you didn't know about this operator.
    I had changed ~> to SAR in other source files, but it slipped through here. You see other places, and I wouldn't have the starting point if not clkFreq was nulled. ;-) Lucky me.

  • ErNaErNa Posts: 1,803

    A next problem:

              x := byte[@SH00][sprev*2+1]   << 24
              x := x SAR 24
              drawLine(CX, CY, CX + byte[@SH00][sprev*2], CY + x, fgm)'bgd)   ' remove prev second hand
    '          drawLine(CX, CY, CX + byte[@SH00][s_cur*2], CY + byte[@SH00][s_cur*2+1], fgs)   ' show second hand
    

    I'm modifying Clusos LCD-demo to have a clock, I can move around. Adding byte valued hands coordinates to a long results in an error if the byte value is negative.

    Had to find SIGNX.

  • ErNaErNa Posts: 1,803

    I just run into a problem when migrating from DIRA[7..0] in P1 to the P2. I have to use Port B. For single pins it is working, but no range does what expected. Is there a simple replacement or do I really have to study the smart pins just now?
    PINLOW [39..32] works, but that is not a simple replacement. Is there a "PINTOGGLE" function?

  • JonnyMacJonnyMac Posts: 9,249

    Is there a "PINTOGGLE" function?

    Yes. Spin2 is documented here:
    -- https://docs.google.com/document/d/16qVkmA6Co5fUNKJHF6pBfGfDupuRwDtf-wyieh_fbqw/edit?tab=t.0#heading=h.1h0sz9w9bl25

    You'll find

    • pinhigh()
    • pinlow()
    • pintoggle()
    • pinwrite()
    • pinfloat()
    • pinread()

    To deal with multiple pins you need to create a pin group with addpins.

      pinlow(32 addpins 7)
    

    If you're writing to an 8-pin bus, you can do this

      pinwrite(32 addpins 7, value)
    

    To keep you code cleaner and easier to edit, you can define the bus pins group as a constant

    CON
    
      LCD_BUS = 32 addpins 7
    
  • ErNaErNa Posts: 1,803
    edited 2025-03-28 16:46

    OK, thanks for helping with the pins. And now the counters (ASM):
    I was used to wait for a counter to reach a value: waitcnt TimTrig, #0
    WaitCnt doesn't exist any longer, I have to loop for just now, but there are three counters to wait for. Just have to make the choice. If I know how.

    OK, I made a hit in the hardware manual Page 22, System counter...

  • JonnyMacJonnyMac Posts: 9,249
    edited 2025-03-28 17:53

    I'm working on a new product that needs to update pixels at a very specific rate while also checking on inputs from buttons, IR (laser-tag guns), and RF (XBee coms from control system). I came across the pollct() Spin2 instruction which returns true or false instead of blocking like waitct() does. If you don't have Chip's PNut compiler archive you might consider downloading it. Chip always includes his PASM2 code for the interpreter in that archive. From that I found that the cmpm instruction is a the heart of pollct() and I've been using it in a lot of code. Here's a simple example.

    dat
    
                            getct     pr0                           ' start of period
    
    .loop                   ' do something                        
    
                            getct     pr1                           ' get now
                            cmpm      pr1, pr0              wc      ' period done?
            if_c            jmp       #.loop
    

    In this case if the C flag is set the period has not expired.

    WaitCnt doesn't exist any longer

    That's not the case. In Spin2:

      t := getct()
      repeat
        ' do something
        waitct(t += LOOP_TIX)
    

    In PASM2:

    dat
    
                            getct     timer                         ' get now
    
                            ' do something
    
                            addct1    timer, #TRGT_TIX              ' set target
                            waitct1                                 ' wait to reach target
    

    Of course, for simple delays (with no work being done while holding) you have the waitx instruction.

  • ErNaErNa Posts: 1,803

    It will take a lot of time 'till you can just play the Propeller. Always surprising news around the corner! I have to expand an existing P1 software, have to do housekeeping, removing all the garbage, which sometimes turns out be of hidden importance, ... This is fun to do, but takes time and time, so searching for a function can take hours, you urgently need in another place. The counter-stuff also is tricky and I can make good use of this later...
    Thanks for pointing me to to sources..

  • evanhevanh Posts: 16,353

    If you're simply pausing the program for a short time then use WAITX instruction. It's simpler than the old WAITCNT. Spin2 also has the waitms() and waitus() functions.

  • ErNaErNa Posts: 1,803

    I need waitct, but it is great to have three counters, so I can have them interleaved. Have to have variable times to measure a signal, but I'm making progress.. Only sometimes I waste some hours watching a few lines of code ;-)

  • JonnyMacJonnyMac Posts: 9,249

    Have to have variable times to measure a signal,

    Smart pins can help. Have a look at this thread:
    -- https://forums.parallax.com/discussion/176164/using-a-smart-pin-to-get-frequency-of-a-pin

  • evanhevanh Posts: 16,353

    Yes, various smartpin modes have their own timers.

Sign In or Register to comment.