Shop OBEX P1 Docs P2 Docs Learn Events
Using locks for multi-cog sensor inputs — Parallax Forums

Using locks for multi-cog sensor inputs

lyons5959lyons5959 Posts: 13
edited 2008-09-14 23:41 in Propeller 1
During one of my projects I found the need to learn about locks. I have a prop that is reading two speed signals(w/ timeout), two thermocouples(via DS2760), and two ADC(Max1202). I have the startup cog initializing everything, then working with fullduplexserial to send the data out to a separate display unit. The main cog specifies the address of 16 word variables, and passes this address on each new cog. two cogs for reading speed, a cog for reading the thermocouples, and a two cogs for reading the two ADCs. However, I keep running into problems. I have tested the code and the program works if I only start up one cog, but when I add another, it goes haywire. How should I use the locks to fix this. I was thinking one lock for each cog representing access to memory. No cog could read from or write to memory while any lock was set. However, i'm not really sure how to do this, and which commands to use. any help is appricated.

Comments

  • codemonkeycodemonkey Posts: 38
    edited 2007-06-26 00:26
    If you're using spin you could look at locknew, lockret, lockset, and lockclr on p234 (thereabouts) in the prop ref manual or 377-ish in the assembly portion of the manual. I haven't used them nor can i offer much more than the reference, but until someone else answers, it's a start.
  • Mike GreenMike Green Posts: 23,101
    edited 2007-06-26 00:52
    If you only have one cog reading a particular sensor and another cog processing the value (to send out serially), you may not need the locks (semaphores). This is a special case called the single "producer"/"consumer" case that doesn't need the semaphores.

    Basically, you need a single value that means "not ready yet". It could be zero or all one bits or some other value that will never occur with the sensor. The variable associated with the sensor is initialized with this value. The "producer" (the routine that reads the sensor) sits in a loop waiting for the variable to have this "not ready yet" value. When it does, the routine reads the sensor and stores its value in the variable. The "consumer" (the routine that processes the sensor value) sits in a loop waiting for the variable to not have the "not ready yet" value. When it does, the routine does whatever it needs to with the value, then sets the variable to "not ready yet". If the "consumer" routine is designed to handle several sensors, it just checks each variable in turn, processes the value if not "not ready yet", then goes on to the next variable (in an overall loop).
  • lyons5959lyons5959 Posts: 13
    edited 2007-06-27 00:45
    So this has the same effect as using a lock for each variable, however it doesn't use any locks at all. I think something like this...

    For writing sensor data...

    repeat until (var) == $FFFF
    (var) := (data)


    For reading sensor data...

    repeat until not (var) == $FFFF
    ...send out data
    (var) := $FFFF

    Will this work if the reading and writing occur on separate cogs?
  • Mike GreenMike Green Posts: 23,101
    edited 2007-06-27 01:07
    1) I'd change the second repeat to "repeat while (var) == $FFFF" or "repeat until (var) <> $FFFF".

    2) Yes.· It's assumed that these are in separate cogs that are executing simultaneously.· This type of inter-process communication is very common and very useful (one process generating data and another consuming it).

    ·3) These are actually special forms of locks that don't require any special hardware·or instructions to do.· The only requirement is that the assignment operation and the data fetch operation are each indivisible.· In other words, the act of storing a 32-bit long word can not be interrupted by another processor and the act of fetching a 32-bit value from the shared memory can not be interrupted by another processor, both of which are true for the Propeller.

    Post Edited (Mike Green) : 6/27/2007 1:13:06 AM GMT
  • tdeyletdeyle Posts: 85
    edited 2008-09-14 18:43
    Since this post helped me a bit, and I have questions pertaining to it, I will post here instead of making a new thread.

    I am building a controller that will activate two solenoids based on two variables: RPM and MAP. Since I have been going through the Objects lab and found an exercise that checks the status of two variables that are passed on from a parent object, I decided to tweak it and try to make it work for my application.

    The first object (parent) will start another object (child) in a different cog that will monitor the two variables (RPM, MAP)that are updated in the parent object.

    I have implemented a loop that will check the value of the variables, and if it is noticed that it changes to $FFFF, then the parent object will get the value with the Measure method in the parent object and update.

    Since the child object is in a loop until the RPM value is not equal to $FFFF, then it should carry out the case loops that follow.

    However, it doesn't. The terminal freezes at a measurement and no more measurements are made. I believe it is stuck at the 1st repeat loop in the child object. I even tried to set the two outputs before the repeat loop in the PRI NoidControl Method, in order to turn on the solenoids, but they do not turn on. I also tried beefing up the number of longs for the Method stack from 10 to 1000, no dice. Why isn't the second cog running the child method? NOTE: The post will not show the number four on the outa settings throughout the post. I am using pin four and pin nine as outputs.

    Parent Object:
    OBJ
       
      Debug:        "FullDuplexSerialPlus"
      NoidCont:     "NoidControlwcase"
      AD:           "MCP3208"
    
    VAR
      
      long MAP
      long RPM                    
               
    PUB UpdateVariables
    
      '' Update variables that get watched by NoidControlwcase object.
     
      Debug.start(31, 30, 0, 57600)                         ''Start FullDuplexSerialPlus object                        
      waitcnt(clkfreq*2 + cnt)                              ''Wait two seconds
      Debug.tx(Debug#CLS)                                   ''Clear the Terminal Screen
    
      ad.start(27, 25, 26, 0)                               ''Start RPM A/D Converter on DPIN = 27, CPIN = 25, SPIN = 26, DAC Pin Channel = 0                         
      ad.start(27, 25, 26, 1)                               ''Start MAP A/D Converter on DPIN = 27, CPIN = 25, SPIN = 26, DAC Pin Channel = 1 
      ad.start(27, 25, 26, 2)
      ad.start(27, 25, 26, 3)
    
      RPM := $FFFF                                          ''Set the RPM Variable to $FFFF
      MAP := $FFFF                                          ''Set the MAP Variable to $FFFF
        
      NoidCont.start(@MAP, @RPM)                            ''Start the NoidControlwcase method, passing on the address locations
    
      dira~~                                             ''Clear Pin 4
      dira[noparse][[/noparse]9]~~                                             ''Clear Pin 9
      
      repeat                                                ''Start of Repeat Loop to update RPM and MAP Variables                                     
         
         debug.tx(Debug#CLS)                                ''Clear the Terminal Screen
    
         debug.dec(MAP)                                     ''Display the MAP value
         debug.str(string(" @ "))
         debug.hex(@MAP,4)                                  ''Display the Address Location of the MAP Value
         debug.tx(Debug#CR)
         debug.dec(RPM)                                     ''Display the RPM Value
         debug.str(string(" @ "))                           
         debug.hex(@RPM,4)                                  ''Display the Address Location of the RPM Value
         debug.tx(Debug#CR)
         
         repeat until RPM == $FFFF                          ''Repeat until the RPM Value is equal to $FFFF
         Measure                                            ''Run the Measure Method
         waitcnt(clkfreq/100 + cnt)                         ''Wait for 1/100th of second
          
    PRI Measure | RawRPM, RawMAP
    ''Takes measurements of various sensors and stores them in variables for later manipulation
    
      rawRPM := ad.average(0, 100)                   ''Measure RPM voltage and average over 100 samples
      RPM := rawRPM * 5500 / 4096                    ''Convert BYTE measure into value of 0-5500
      rawMAP := ad.average(1, 100)                   ''Measure MAP Voltage and average over 100 samples
      MAP := rawMAP * 25 / 4096                      ''Convert BYTE measure into value of 0-25
      
    
    



    Child Object:
    VAR
    
    long stack[noparse][[/noparse]1000]
    byte cog
    
    PUB Start(MAPAddress, RPMAddress) : success
    
     stop
     success := (cog := cognew(NoidControl(MAPAddress, RPMAddress), @stack) + 1)
     
    PUB Stop
    
    
      if Cog
        cogstop(Cog~ - 1)
    
    PRI NoidControl(MAPAddress, RPMAddress) | RPM, MAP
    
    '' Method that will switch the solenoids on and off according to the MAP and RPM values.
    
    outa~
    outa[noparse][[/noparse]9]~
       
    repeat        
    
      RPM := long[noparse][[/noparse]RPMAddress]                               ''Store value at RPMAddress to RPM variable.               
      MAP := long[noparse][[/noparse]MAPAddress]                               ''Store value at MAPAddress to MAP variable.
    
      repeat until RPM <> $FFFF                             ''Wait until the RPM value changes from $FFFF.
      
        case RPM                                            ''Start of RPM CASE Loop
          0..3000 :                                         ''If RPM value is between 0 and 3000,
            case MAP                                          ''Start of MAP CASE Loop
              0..7 :                                          ''and MAP value is between 0 and 7,
                outa~                                      ''clear pin 4,
                outa[noparse][[/noparse]9]~                                      ''clear pin 9.
                                                              
              7..11 :                                         ''or MAP value is between 7..11,
                outa~~                                     ''set pin 4 high,
                outa[noparse][[/noparse]9]~                                      ''clear pin 9.
                                                              
              11..15 :                                        ''or MAP value is between 11..15,
                outa~~                                     ''set pin 4 high,               
                outa[noparse][[/noparse]9]~                                      ''clear pin 9.                  
                                                              
              15..25 :                                        ''or MAP value is between 15..25,
                outa~~                                     ''set pin 4 high,               
                outa[noparse][[/noparse]9]~                                      ''clear pin 9.                  
                                                              
              other :                                         ''otherwise,
                outa~                                      ''clear pin 4,
                outa[noparse][[/noparse]9]~                                      ''clear pin 9.
                                                              
          3000..4500:                                       ''If RPM value is between 3000 and 4500,
            case MAP                                          ''Start of MAP CASE Loop             
              0..7 :                                          ''and MAP value is between 0 and 7,  
                outa~                                      ''clear pin 4,                       
                outa[noparse][[/noparse]9]~                                      ''clear pin 9.                       
                                                                                                   
              7..11 :                                         ''or MAP value is between 7..11,     
                outa~~                                     ''set pin 4 high,                    
                outa[noparse][[/noparse]9]~                                      ''clear pin 9.                       
                                                                                                   
              11..15 :                                        ''or MAP value is between 11..15,    
                outa~                                      ''clear pin 4,                    
                outa[noparse][[/noparse]9]~~                                     ''set pin 9 high.                       
                                                                                                   
              15..25 :                                        ''or MAP value is between 15..25,    
                outa~                                      ''clear pin 4,                    
                outa[noparse][[/noparse]9]~~                                     ''set pin 9 high.                       
                                                                                                   
              other :                                         ''otherwise,                         
                outa~                                      ''clear pin 4,                       
                outa[noparse][[/noparse]9]~                                      ''clear pin 9.                       
                                                              
                                                              
                                                              
          4500..6000:                                       ''If RPM value is between 4500 and 6000,
            case MAP                                          ''Start of MAP CASE Loop             
              0..7 :                                          ''and MAP value is between 0 and 7,  
                outa~                                      ''clear pin 4,                       
                outa[noparse][[/noparse]9]~                                      ''clear pin 9.                       
                                                                                                   
              7..11 :                                         ''or MAP value is between 7..11,     
                outa~~                                     ''set pin 4 high,                    
                outa[noparse][[/noparse]9]~                                      ''clear pin 9.                       
                                                                                                   
              11..15 :                                        ''or MAP value is between 11..15,    
                outa~                                      ''clear pin 4,                    
                outa[noparse][[/noparse]9]~~                                     ''set pin 9 high.                       
                                                                                                   
              15..25 :                                        ''or MAP value is between 15..25,    
                outa~~                                     ''set pin 4 high,                    
                outa[noparse][[/noparse]9]~~                                     ''set pin 9 high.                       
                                                                                                   
              other :                                         ''otherwise,                         
                outa~                                      ''clear pin 4,                       
                outa[noparse][[/noparse]9]~                                      ''clear pin 9.                       
    
          other :                                           ''otherwise,
            outa~                                        ''clear pin 4,
            outa[noparse][[/noparse]9]~                                        ''clear pin 9.
                
                   
        RPM := $FFFF                                        ''Set RPM value to $FFFF
    
    
  • Mike GreenMike Green Posts: 23,101
    edited 2008-09-14 18:53
    Very simple mistake. You have several different variables with the names RPM and MAP and you confused them.

    In the child object, you're setting RPM to $FFFF to signal that the child wants a new measurement. Unfortunately,
    this RPM is the one declared local to the child object, not the one in the main object. You should use long[noparse][[/noparse]RPMAddress].
    You have the same naming problem in the REPEAT loop at the beginning where you use RPM.

    I'd suggest you simply use long[noparse][[/noparse]RPMAddress] and long[noparse][[/noparse]MAPAddress] throughout the child object. These don't take that
    much more space or time than using a local copy, particularly since they're only used in a few places and this will avoid
    any confusion over which copy you're using at what time.
  • tdeyletdeyle Posts: 85
    edited 2008-09-14 19:37
    Thanks for the quick response! Ok, I have done those corrections, and can see why they were not working, however, why is it that when I set both outa[noparse][[/noparse]four]
    and outa[noparse][[/noparse]9] high, that the solenoids do not switch on?

    In the child object:

    
    PRI NoidControl(MAPAddress, RPMAddress)
    
    '' Method that will switch the solenoids on and off according to the MAP and RPM values.
    
    outa[noparse][[/noparse]four]~~
    outa[noparse][[/noparse]9]~~
       
      repeat until long[noparse][[/noparse]RPMAddress] <> $FFFF                ''Wait until the RPM value changes from $FFFF.
      
    
    



    I am using LEDs in place of the solenoids. The LEDs are switched on with a high output on pins 4 and 9. What the program does is take the last measurement,
    then halts as if the child object is not running. Why does it halt?
  • SapiehaSapieha Posts: 2,964
    edited 2008-09-14 19:45
    Hi tdeyle

    You must set.

    dira~~ ''Clear Pin 4
    dira[noparse][[/noparse]9]~~ ''Clear Pin 9

    In same COG proces.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Nothing is impossible, there are only different degrees of difficulty.
    For every stuipid question there is atleast one inteligent answer
    If you dont ask you wont know

    Sapieha
  • tdeyletdeyle Posts: 85
    edited 2008-09-14 19:54
    Which Process? The child or the Parent?
  • Mike GreenMike Green Posts: 23,101
    edited 2008-09-14 19:58
    You also have to remove the DIR[noparse][[/noparse] 4 ]~~ and the DIR[noparse][[/noparse] 9 ]~~ from the parent object. The program will still work because the parent object's cog leaves its OUT[noparse][[/noparse] 4 ] and OUT[noparse][[/noparse] 9 ] bits set to their default of zero. You have to place a DIR[noparse][[/noparse] 4 ]~~ and DIR[noparse][[/noparse] 9 ]~~ in the child object.

    Each cog has its own DIR and OUT registers and, as is shown in several diagrams on the Propeller webpages and manual, they're all OR'd together. If any cog sets its DIR register bit to a one, that pin becomes an output regardless of what any other cog does. If any cog with its DIR bit set to one also sets its OUT bit to one, that I/O pin becomes an high output regardless of what any other cog does.
  • tdeyletdeyle Posts: 85
    edited 2008-09-14 20:19
    Well, it is still hanging up when the Child Object is called. I even placed a out[noparse][[/noparse] 4 ] ~~ after the Start method in the child object, commenting out the rest of the method, just to see if
    the LED would light up. It didn't. For some reason, the Parent Object is not starting up the new object in the new cog.
  • tdeyletdeyle Posts: 85
    edited 2008-09-14 20:21
    Scratch that last reply. I forgot to set the direction register to an output. It does light the LED. This means that the start method is running.
    I will test to see if the NoidControl Method starts via the cognew command.
  • tdeyletdeyle Posts: 85
    edited 2008-09-14 21:31
    Well, still can't get it going. I kind of wanted to do this function through parallel processors, however, I believe the Prop will be quick enough running this program in one cog.

    Thanks for everyone's help.
  • SapiehaSapieha Posts: 2,964
    edited 2008-09-14 21:35
    Hi tdeyle.

    Not give up.
    I wanted Yours post.
    Place You code for Child proces I have one mistake but must see you code.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Nothing is impossible, there are only different degrees of difficulty.
    For every stuipid question there is atleast one inteligent answer
    If you dont ask you wont know

    Sapieha
  • tdeyletdeyle Posts: 85
    edited 2008-09-14 21:54
    It's posted in this thread, the two objects are marked as Child and Parent, 9 posts up.
  • SapiehaSapieha Posts: 2,964
    edited 2008-09-14 21:55
    Hi tdeyle.

    Sorry.
    I mean you EDITED Child

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Nothing is impossible, there are only different degrees of difficulty.
    For every stuipid question there is atleast one inteligent answer
    If you dont ask you wont know

    Sapieha
  • tdeyletdeyle Posts: 85
    edited 2008-09-14 22:21
    Any help is appreciated:

    VAR
    
    long stack[noparse][[/noparse]100]
    byte cog
    
    PUB Start(MAPAddress, RPMAddress)' : success
    
     stop
     success := (cog := (cognew(NoidControl(MAPAddress, RPMAddress), @stack) + 1)
     cognew(Noid(MAPAddress, RPMAddress), @stack)
     
    PUB Stop
    
    
      if Cog
        cogstop(Cog~ - 1)
    
    PUB Noid(MAPAddress, RPMAddress)
    
    '' Method that will switch the solenoids on and off according to the MAP and RPM values.
    
      dira~~
      dira[noparse][[/noparse]9]~~
      
      outa~
      outa[noparse][[/noparse]9]~
    
    
      repeat until long[noparse][[/noparse]RPMAddress] <> $FFFF                ''Wait until the RPM value changes from $FFFF.
      
        case long[noparse][[/noparse]RPMAddress]                               ''Start of RPM CASE Loop
          0..3000 :                                         ''If RPM value is between 0 and 3000,
            case long[noparse][[/noparse]MAPAddress]                                          ''Start of MAP CASE Loop
              0..7 :                                          ''and MAP value is between 0 and 7,
                outa~                                      ''clear pin 4,
                outa[noparse][[/noparse]9]~                                      ''clear pin 9.
                                                              
              7..11 :                                         ''or MAP value is between 7..11,
                outa~~                                     ''set pin 4 high,
                outa[noparse][[/noparse]9]~                                      ''clear pin 9.
                                                              
              11..15 :                                        ''or MAP value is between 11..15,
                outa~~                                     ''set pin 4 high,               
                outa[noparse][[/noparse]9]~                                      ''clear pin 9.                  
                                                              
              15..25 :                                        ''or MAP value is between 15..25,
                outa~~                                     ''set pin 4 high,               
                outa[noparse][[/noparse]9]~                                      ''clear pin 9.                  
                                                              
              other :                                         ''otherwise,
                outa~                                      ''clear pin 4,
                outa[noparse][[/noparse]9]~                                      ''clear pin 9.
                                                              
          3000..4500:                                       ''If RPM value is between 3000 and 4500,
            case long[noparse][[/noparse]MAPAddress]                                          ''Start of MAP CASE Loop             
              0..7 :                                          ''and MAP value is between 0 and 7,  
                outa~                                      ''clear pin 4,                       
                outa[noparse][[/noparse]9]~                                      ''clear pin 9.                       
                                                                                                   
              7..11 :                                         ''or MAP value is between 7..11,     
                outa~~                                     ''set pin 4 high,                    
                outa[noparse][[/noparse]9]~                                      ''clear pin 9.                       
                                                                                                   
              11..15 :                                        ''or MAP value is between 11..15,    
                outa~                                      ''clear pin 4,                    
                outa[noparse][[/noparse]9]~~                                     ''set pin 9 high.                       
                                                                                                   
              15..25 :                                        ''or MAP value is between 15..25,    
                outa~                                      ''clear pin 4,                    
                outa[noparse][[/noparse]9]~~                                     ''set pin 9 high.                       
                                                                                                   
              other :                                         ''otherwise,                         
                outa~                                      ''clear pin 4,                       
                outa[noparse][[/noparse]9]~                                      ''clear pin 9.                       
                                                              
                                                              
                                                              
          4500..6000:                                       ''If RPM value is between 4500 and 6000,
            case long[noparse][[/noparse]MAPAddress]                                          ''Start of MAP CASE Loop             
              0..7 :                                          ''and MAP value is between 0 and 7,  
                outa~                                      ''clear pin 4,                       
                outa[noparse][[/noparse]9]~                                      ''clear pin 9.                       
                                                                                                   
              7..11 :                                         ''or MAP value is between 7..11,     
                outa~~                                     ''set pin 4 high,                    
                outa[noparse][[/noparse]9]~                                      ''clear pin 9.                       
                                                                                                   
              11..15 :                                        ''or MAP value is between 11..15,    
                outa~                                      ''clear pin 4,                    
                outa[noparse][[/noparse]9]~~                                     ''set pin 9 high.                       
                                                                                                   
              15..25 :                                        ''or MAP value is between 15..25,    
                outa~~                                     ''set pin 4 high,                    
                outa[noparse][[/noparse]9]~~                                     ''set pin 9 high.                       
                                                                                                   
              other :                                         ''otherwise,                         
                outa~                                      ''clear pin 4,                       
                outa[noparse][[/noparse]9]~                                      ''clear pin 9.                       
    
          other :                                           ''otherwise,
            outa~                                        ''clear pin 4,
            outa[noparse][[/noparse]9]~                                        ''clear pin 9.
                
                   
        long[noparse][[/noparse]RPMAddress] := $FFFF                           ''Set RPM value to $FFFF
    
    
  • Mike GreenMike Green Posts: 23,101
    edited 2008-09-14 23:01
    You're not providing much information. You have a lot of code there and most of it doesn't have anything to do with the interaction of two cogs. It looks basically like the interplay between the two cogs should work although you didn't give the parent object's updated code. Assuming that hasn't changed from before other than removing the DIRs, it ought to work. Do you know that the analog to digital conversions work? Do the MAP and RPM values look reasonable? If I were doing this, I'd have a TV display or VGA display running and show everything ... solenoid I/O pins, MAP and RPM values, raw ADC values in real-time on the display.
  • tdeyletdeyle Posts: 85
    edited 2008-09-14 23:41
    Yep, I did this with the prop terminal as a debug screen. I have the I/O pins functioning through LEDs, the addresses and values of MAP and RPM are reasonable since I have them being introduced as two pots in a voltage divider across 0-5V. They are moving from low to high values properly, but this is only when I run the parent object.

    When I introduce the Child Object and the repeat until <> and == $FFFF loops in their respective places in the objects, that is when the program hangs, I only get the initial measured value from the pots and then it is waiting for the child object to cycle through. This is why I think something is wrong with the child object.

    This is not a big deal since I can use one cog for this operation, it is not as time critical to warrant two cogs slaving over it.

    However, I do appreciate the assistance from you, Mike and Sapieha.
Sign In or Register to comment.