Shop OBEX P1 Docs P2 Docs Learn Events
Code Help — Parallax Forums

Code Help

Just stumped trying to figure out why my code doesn't run. I tried to write one of my first programs, and when I figured out it was not working I attempted at a little debugging. I commented out the lines one by one to try to isolate the problem, and so here is the condensed code (no comments).

The CK method appears to be what is causing the program to hang up. There is an LED on pin 11 which should turn off if the program runs to the end, and it doesn't as soon as I add the CK(10,10) method. It is the waitcnt command specifically because as soon as I remove it, it all works, and the light turns off. The LCD, however, is another matter.

What a brain-tease.

Con
_xinfreq = 5_000_000
_clkmode = xtal1 + pll1x
uS = (5)
mS = (5_000)

PUB Main

T_Del(mS,40)
DirA := %00000000_00000000_0000_1111_1111_1111
OutA := %00000000_00000000_0000_0000_0000_0000 ' Set Control and data ports as outputs

OutA[11] := %1
T_Del (mS,1)
T_Del (uS,100)
OutA[0..1] := %00
OutA[10..3] := %0011_0000

CK(10,10) ' Trigger the clock pin. check clock for required pulse width and time.

OutA[11] := %0 ' Turn off led to confirm program ran to end. !Not the case.
repeat

PUB T_Del(dt, x) 'waits until cnt register equals expression.
waitcnt(dt*x + cnt) 'dt = time step x = multiplier

PUB CK(Toff,Ton) ' Method to pulse the CK Pin on the LCD
waitcnt(Toff + cnt)

Comments

  • @NickMikhay said:
    Just stumped trying to figure out why my code doesn't run. I tried to write one of my first programs, and when I figured out it was not working I attempted at a little debugging. I commented out the lines one by one to try to isolate the problem, and so here is the condensed code (no comments).

    The CK method appears to be what is causing the program to hang up. There is an LED on pin 11 which should turn off if the program runs to the end, and it doesn't as soon as I add the CK(10,10) method. It is the waitcnt command specifically because as soon as I remove it, it all works, and the light turns off. The LCD, however, is another matter.

    What a brain-tease.

    CON
      _xinfreq = 5_000_000
      _clkmode = xtal1 + pll1x
      uS = (5)
      mS = (5_000)
    
    PUB Main
    
      T_Del(mS,40)
      DirA := %00000000_00000000_0000_1111_1111_1111
      OutA := %00000000_00000000_0000_0000_0000_0000 ' Set Control and data ports as outputs
    
      OutA[11] := %1
      T_Del (mS,1)
      T_Del (uS,100)
      OutA[0..1] := %00
      OutA[10..3] := %0011_0000
    
      CK(10,10) ' Trigger the clock pin. check clock for required pulse width and time.
    
      OutA[11] := %0 ' Turn off led to confirm program ran to end. !Not the case.
      repeat
    
    PUB T_Del(dt, x) 'waits until cnt register equals expression.
      waitcnt(dt*x + cnt) 'dt = time step x = multiplier
    
    PUB CK(Toff,Ton) ' Method to pulse the CK Pin on the LCD
      waitcnt(Toff + cnt)
    

    The problem you are having is most likely due to passing only 10 as Toff for the CK routine.
    There is a minimum amount of time that Spin takes to interpret and execute the waitcnt instruction.
    You need to ensure that you supply a target value that is large enough to keep the cnt from counting past the value you are waiting for.

    See the following comment in the simple wait routine below for clarification:

    PUB wait(Time_in_ms)                            'This routine has the program wait the specified number of milliseconds.
      waitcnt(((clkfreq / 1_000 * Time_in_ms - 3932) #> 381) + cnt)
      {{ This will delay/wait the specified number of milliseconds. This is SPIN code, and SPIN is interpreted,
         so it takes significantly longer to interpret and execute the waitcnt command than it does with PASM.
         The 3932 is to compensate for the time that it takes the interpreter to process the computation portion of the command.
         The #>381 insures that you never do a waitcnt with a value less than 381 more than the current CNT, because if you do
         that the counter will have already counted past your target value before the timing starts, and that means you will
         hang there while the counter loops through it's entire 32-bit range, somewhere around a minute (53 seconds).
         Waitcnt waits for the system counter to be exactly equal to the target value. }}
    
  • I use this timing section in my P1 programs:

    con { timing }
    
      _clkmode = xtal1 + pll16x
      _xinfreq = 5_000_000                                          ' use 5MHz crystal
    
      CLK_FREQ = (_clkmode >> 6) * _xinfreq                         ' system freq as a constant
      MS_001   = CLK_FREQ / 1_000                                   ' ticks in 1ms
      US_001   = CLK_FREQ / 1_000_000                               ' ticks in 1us
    

    This handles the details of calculating CLK_FREQ, MS_001, and US_001 based on your clock mode and input frequency.

    With those constants you can implement a cleaner delay methods:

    pub delay(ms) | t
    
      t := cnt
      repeat ms
        waitcnt(t += MS_001)
    

    You're going to have trouble with very short delays running a 5MHz system. You don't have a lot of clock cycles to deal with the fixed overhead of the Spin interpreter. Is there a reason you're running the P1 so slowly?

  • I see, I suppose I can run the prop a bit faster. Interesting that I did observe the light turn off about ten minutes later. Nice operation on the constant, Jon.

    Much catch up on the PASM documentation. Thanks for the help.

    PS
    381, does that imply 381 machine cycles to interpret one command? Although it appears to be a compound statement with 3 sets of parentheses?

  • JonnyMacJonnyMac Posts: 8,926
    edited 2021-09-29 15:24

    I see, I suppose I can run the prop a bit faster. Interesting that I did observe the light turn off about ten minutes later.

    Your waitcnt finally hit its target. At 80MHz the wrap-around time of the cnt register is about 56 seconds.

    Here's a how I do speed testing of code segments.

      t := cnt
      ' code to test 
      t := cnt - t - 368
    
      term.dec(t)
      term.tx(13)
      term.dec(t/US_001)
    

    The - 368 removes the overhead for accessing the cnt register so you get the area in between the t := lines timed properly.

    In your case you might blip the CK line like this (assuming it's already an output):

      outa[CK] := 1
      outa[CK] := 0
    

    At 5MHz this takes about 243 microseconds so you can assume the high pulse is about 121 microseconds -- that's about as short as you're going to get without invoking a timer to create the pulse, or moving to PASM.

    381, does that imply 381 machine cycles to interpret one command?

    No. In that instance you must add at least 381 cycles to the current value of cnt (note that it's accessed last) for the waitcnt to be able to hit the target without wrap-around. That value was probably determined empirically for that particular line of code.

  • The nice thing about low clock speeds is that it is possible to use the 4000 series logic chips to accompany the prop, which are relatively inexpensive and don’t draw a lot of power, and you have to love all the specialty chips like the analog switches among others.

Sign In or Register to comment.