Shop OBEX P1 Docs P2 Docs Learn Events
Confusing little issue — Parallax Forums

Confusing little issue

SarielSariel Posts: 182
edited 2012-08-01 10:37 in Propeller 1
Hey all!

I have isolated a bug in my code, and I have stripped it down to the extreme basics. I know that it does not, but I would like to know exactly why this code sample does not work. For bare simplicity, I brought it down to toggling a pin, and it just won't fire up. Here is the top file.
CON
'' Clock settings
  _CLKMODE      = XTAL1 +PLL16X 
  _XINFREQ      = 5_000_000  
  Power         = 26            ' GPIO to use in this demonstration

OBJ     
  BLINK :       "BlinkyPins.spin" 
  
PUB Start
'' Init the system
  BLINK.Startcog(Power)         ' Start the cog up with the code from the other object
  run                           ' Go to the next method.

PUB Run
'' this loop is to toggle the pin's output status
  repeat
    BLINK.PinOn                 ' Turn the pin on
    waitcnt(clkfreq + cnt)      ' Wait for approx 1 second
    BLINK.PinOff                ' Turn the pin back off
    waitcnt(clkfreq + cnt)      ' Wait for approx 1 second

And here is the child object:
VAR
  byte cog            ' Cog ID variable 
  byte Power          ' Var for holding the pin number to run
  long stack[10]      ' STack space for the new cog.   

PUB Startcog(PowerPin) : ok
'' Start the cog up.
  ok := cog := cognew(INIT(PowerPin), @stack[0]) + 1  
PUB init(Power_)
  Power := Power_
  
  dira[Power] := 1 
    
  repeat     
    waitcnt(clkfreq + cnt)      ' Normally this area would be filled with other code.                               
    waitcnt(clkfreq + cnt)      ' I just wanted to keep the cog alive
    
PUB PinOn
'' Turn the pin on
  
    outa[Power] := 1
    
PUB PinOff
'' Turn the pin off   
  
    outa[Power] := 0    
                               

In my mind, I would expect it to still blink the pin. whatever cog does the actual processing. But the it stays idle. I have done some experimenting and found the pin number is passed correctly, but it just will not toggle. I know the hardware is good becuase when I do it with a single cog, single file, single method:
  dira[Power] := 1

  repeat
    outa[Power] := 1   
    waitcnt(clkfreq + cnt)   
    outa[Power] := 0 
    waitcnt(clkfreq + cnt)   

it does exaclty the right thing. Can anyone explain this to me?

Comments

  • Mike GMike G Posts: 2,702
    edited 2012-08-01 07:24
    One COG spins up and sits in a waitcnt forever.
    PUB Startcog(PowerPin) : ok
    '' Start the cog up.
      ok := cog := cognew(INIT(PowerPin), @stack[0]) + 1  
    PUB init(Power_)
      Power := Power_
      
      dira[Power] := 1 
        
      repeat     
        waitcnt(clkfreq + cnt)      ' Normally this area would be filled with other code.                               
        waitcnt(clkfreq + cnt)      ' I just wanted to keep the cog alive
    

    The main cog has no concept of the "byte Power" member of BlinkyPins as the IO is ORed together..
    UB Run
    '' this loop is to toggle the pin's output status
      repeat
        BLINK.PinOn                 ' Turn the pin on
        waitcnt(clkfreq + cnt)      ' Wait for approx 1 second
        BLINK.PinOff                ' Turn the pin back off
        waitcnt(clkfreq + cnt)      ' Wait for approx 1 second
    

    Generally, you'll have a COG running is a loop looking for a command to execute - Producer/Consumer model.

    See the Propeller Education kit. It has a great tutorial covering this topic.
  • SarielSariel Posts: 182
    edited 2012-08-01 07:31
    Ahh I suspected something like that, but was not positive. So to make sure I am clear, it is trying to run "PinOn" and "PinOff" in the initial cog (theoretical cog0), not the one that is started up with cognew. Correct? And this would in no way be corrected by removing the endless loop of waitcnt's. From what I have read, I am under the impression that would stop the cog altogether and let it go back to being idle.

    Thanks Mike.
  • Mike GMike G Posts: 2,702
    edited 2012-08-01 07:37
    And this would in no way be corrected by removing the endless loop of waitcnt's. From what I ahve read, I am under the impression that would stop the cog altogether and let it go back to being idle.
    Right. what ya do is replace the repeat loop with logic that is looking for a command in HUB RAM.

    0 = no command
    1 = light LED
    2 = turn off


    I did not test this code - and it is not the greatest - but it should provide an example.
    VAR
      byte cog            ' Cog ID variable 
      byte Power          ' Var for holding the pin number to run
      long  command 
      long stack[10]      ' STack space for the new cog.
         
    
    PUB Startcog(PowerPin, cmd) : ok
    '' Start the cog up.
      command := cmd
      ok := cog := cognew(INIT(PowerPin), @stack[0]) + 1  
    PUB init(Power_) | cmd
      Power := Power_
      
      dira[Power] := 1 
        
      repeat     
        cmd := byte[command]
        if(cmd == 1)
          PinOn
        if(cmd == 2)
          PinOff
        
    PUB PinOn
    '' Turn the pin on
      
        outa[Power] := 1
        
    PUB PinOff
    '' Turn the pin off   
      
        outa[Power] := 0
    
  • SarielSariel Posts: 182
    edited 2012-08-01 08:13
    Oh that's slick. I think I will use something similar to that in my full blown application. My child object is mostly a command interpreter that is talking to another prop... effectively becoming an "Invisible serial terminal". I can add that function into the string compares and just handle all the data the same way, weather it is coming from another prop, or another cog.
  • AribaAriba Posts: 2,690
    edited 2012-08-01 10:11
    Sariel wrote: »
    Hey all!

    I have isolated a bug in my code, and I have stripped it down to the extreme basics. I know that it does not, but I would like to know exactly why this code sample does not work. For bare simplicity, I brought it down to toggling a pin, and it just won't fire up. Here is the top file.
    CON
    '' Clock settings
      _CLKMODE      = XTAL1 +PLL16X 
      _XINFREQ      = 5_000_000  
      Power         = 26            ' GPIO to use in this demonstration
    
    OBJ     
      BLINK :       "BlinkyPins.spin" 
      
    PUB Start
    '' Init the system
      BLINK.Startcog(Power)         ' Start the cog up with the code from the other object
      run                           ' Go to the next method.
    
    PUB Run
    '' this loop is to toggle the pin's output status
      repeat
        BLINK.PinOn                 ' Turn the pin on
        waitcnt(clkfreq + cnt)      ' Wait for approx 1 second
        BLINK.PinOff                ' Turn the pin back off
        waitcnt(clkfreq + cnt)      ' Wait for approx 1 second
    

    And here is the child object:
    VAR
      byte cog            ' Cog ID variable 
      byte Power          ' Var for holding the pin number to run
      long stack[10]      ' STack space for the new cog.   
    
    PUB Startcog(PowerPin) : ok
    '' Start the cog up.
      ok := cog := cognew(INIT(PowerPin), @stack[0]) + 1  
    PUB init(Power_)
      Power := Power_
      
      dira[Power] := 1 
        
      repeat     
        waitcnt(clkfreq + cnt)      ' Normally this area would be filled with other code.                               
        waitcnt(clkfreq + cnt)      ' I just wanted to keep the cog alive
        
    PUB PinOn
    '' Turn the pin on
      
        outa[Power] := 1
        
    PUB PinOff
    '' Turn the pin off   
      
        outa[Power] := 0    
                                   
    

    In my mind, I would expect it to still blink the pin. whatever cog does the actual processing. But the it stays idle. I have done some experimenting and found the pin number is passed correctly, but it just will not toggle. I know the hardware is good becuase when I do it with a single cog, single file, single method:
      dira[Power] := 1
    
      repeat
        outa[Power] := 1   
        waitcnt(clkfreq + cnt)   
        outa[Power] := 0 
        waitcnt(clkfreq + cnt)   
    

    it does exaclty the right thing. Can anyone explain this to me?

    You set DIRA in the second cog, while you execute the BLINK.PinOn/PinOff with the first cog. So just set dira at begin of the RUN methode instead of the INIT methode.

    Andy
  • Mark_TMark_T Posts: 1,981
    edited 2012-08-01 10:26
    Each cog has its own DIRA and OUTA registers and the DIRA guards the OUTA _per cog_ - if a cog has a zero for a pin in DIRA it cannot touch that pin's value at all, only read it - and this applies to code, counters or video generator of that cog.

    If more than one cog has a 1 for the same pin in DIRA, then the pin's output is the logical OR of the OUTA registers in those cogs with a 1 in the DIRA.
  • SarielSariel Posts: 182
    edited 2012-08-01 10:29
    You set DIRA in the second cog, while you execute the BLINK.PinOn/PinOff with the first cog. So just set dira at begin of the RUN methode instead of the INIT methode.

    Well I'll be.... it is working. but is it taking the pin information from the variable in the child, or the constant in the parent file? I know it does not matter, but curiosity on this is bugging me.:smile:
  • SarielSariel Posts: 182
    edited 2012-08-01 10:37
    cog has a zero for a pin in DIRA it cannot touch that pin's value at all,

    And by default, they are set to 0. Hrmmm...
    and to answear my own question, I got rid of the constant (and passing from parent to child) and just init'd the variable in the child object to be 26 and it gave up the ghost again. I guess that proves that even though it is pulling the method from the child, it is running in the first, and hence has access to the constants and variables of the first cog.

    Boy.. I am learning a boatload today. thanks guys. I know it is just a stupid little program here, but it has taught me a LOT about the inner workings of this beast.
Sign In or Register to comment.