Shop OBEX P1 Docs P2 Docs Learn Events
Can two cogs within the same obect have access to the same global variable? — Parallax Forums

Can two cogs within the same obect have access to the same global variable?

idbruceidbruce Posts: 6,197
edited 2011-01-16 10:39 in Propeller 1
lllllllllllllllllllllll
«13

Comments

  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2011-01-15 13:19
    Yes, multiple Spin cogs within the same object share the object's global variables.

    -Phil
  • idbruceidbruce Posts: 6,197
    edited 2011-01-15 13:32
    Thanks Phil

    Well I guess I better look elsewhere for the problem then. However, I am glad for that answer.

    Thanks again Phil
    Bruce
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2011-01-15 14:15
    So at the chance of being scolded, can two cogs within the same object have access to the same global variables?

    Is this in Spin or Pasm?

    The answer is yes in spin.

    However, in pasm, you can pass a value to a cog when the cog starts up, but once that cog is running using its own internal 2k of memory, it won't necessarily have access to global variables. It depends on the code. You can code it so it can by passing the cog the location of hub ram where your variable is stored. Then you need to think 'in parallel', about how that variable might be accessed. Fine if one bit of code changes the variable and two or three cogs are reading it. But it is more complex if two or more cogs are able to change that variable. You then need flags and locks.

    FWIW it took me months to understand this stuff, and I still get confused sometimes. I find it helpful to write quick test programs and try out concepts.

    Are you programming in spin or pasm?
  • idbruceidbruce Posts: 6,197
    edited 2011-01-15 14:24
    Dr_Acula

    Okay I was referring to Spin, but that is good information anyhow. However, now you bring up another issue. It is quite possible that one cog is reading the variable while the other cog is writing to it. I may have to implement locks.

    Along similar lines my next question is:
    Can two cogs within the parent obect have access to the same object declared in the parent?

    Bruce
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2011-01-15 14:36
    idbruce wrote:
    It is quite possible that one cog is reading the variable while the other cog is writing to it. I may have to implement locks.
    This would be necessary only if a single "datum" requires more than one byte, word or long access. In the case of a single access, the hub's round-robin operation obviates any need for locks. Also, when one cog is queuing data, for example, and another is retrieving it, locks are unnecessary, since the two cogs are writing different pointers. Another example is the case of calling procedures in a PASM cog, wherein the parameters are written to the hub first, then the command. The PASM cog polls for a valid command and, when it receives one, reads the parameters. After performing the requested work, it writes any results back to the parameter array, then zeroes the command to tell the caller it's finished. No locks required.

    -Phil
  • idbruceidbruce Posts: 6,197
    edited 2011-01-15 15:07
    Phil

    Well then I just don't know. It appears as if everything should work and it does until it gets near the end where I have four cogs running.

    It starts with the main cog which is used to display input data on a LCD and update a DS1302. Upon initialization, another cog is created to monitor a keypad for inputing the DS1302 data. Once the data is set into the RTC, another cog is created to repeatedly update time and date variables. And then another cog is created to repeatedly read these variables and write them to a LCD. Meanwhile, the keyboard input cog repeatedly checks for a stop button condition. At which point the cogs would shut down the PROP would reboot.

    In case anyone wants to examine it, I have attached the source. It runs fine until the ENT button is pressed to upload the data into the DS1302, at which point the LCD display doesn't change and it should to reflect current time.

    Thanks Phil. That saved from programming useless locks.

    Bruce
  • Mike GreenMike Green Posts: 23,101
    edited 2011-01-15 15:17
    There are some special case situations where locks are not necessary. Generally these are cases where only one cog can change the variable. One example is using a ring buffer to communicate between two cogs where one pointer is used for writing into the buffer while the other pointer is used for reading from the buffer. One cog uses the write pointer for writing and only uses the read pointer to tell when the buffer is full. The other cog uses the read pointer for reading and only uses the write pointer to tell when the buffer is empty. The worst that can happen is that the cog that's filling the buffer might think that the buffer is full even though the other cog is in the process of emptying it or the cog that's emptying the buffer might think that the buffer has nothing in it even though the other cog is in the process of putting something into the buffer. In both cases, the cog will try again (to write or read).
  • idbruceidbruce Posts: 6,197
    edited 2011-01-15 15:20
    Thanks For The Input Mike

    Like I said in my last, I am just not sure. It looks like it should work, except for any locking that might be required.

    Bruce
  • Mike GreenMike Green Posts: 23,101
    edited 2011-01-15 15:33
    It seems awfully complicated for what it seems to be doing. For a start, you've got different routines for entering each part of the time (and date?) even though they're doing almost the same thing. You ought to be able to have just one routine with parameters providing the differences between uses.

    Try stripping down the program to just the time/date entry so you can get that working before you add other logic. It'll make debugging a lot easier.
  • idbruceidbruce Posts: 6,197
    edited 2011-01-15 15:57
    Mike

    It appears more complicated than it actually is.
    You ought to be able to have just one routine with parameters providing the differences between uses.

    As MagIO2 pointed out, much of the output to the LCD could be condensed, however, the conditions for the input are obviously quite different. I am sure there are better programmers than me here at the forum that could accomplish condensing the input, but for me, it was easier just to seperate them because of the various conditions.
    stripping down the program

    You told me that once before and it was good advice. As you can see, I did comment out a section that I thought was giving me trouble, but to no avail. I will rip it to shreads, and down to the bare bones. As for condensing the code, I will leave that to the true blue programming experts :) Too much thought and time for my little brain :)

    Mike thank you for your input and advice.

    Bruce
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2011-01-15 16:09
    It starts with the main cog which is used to display input data on a LCD and update a DS1302. Upon initialization, another cog is created to monitor a keypad for inputing the DS1302 data. Once the data is set into the RTC, another cog is created to repeatedly update time and date variables. And then another cog is created to repeatedly read these variables and write them to a LCD. Meanwhile, the keyboard input cog repeatedly checks for a stop button condition. At which point the cogs would shut down the PROP would reboot.

    Can I just check terminology? The above mentions "creating cogs" and I think you might mean running more functions (or PUBs) as looking at the code, and all the sub code, the entire thing appears to be in Spin, so no cogs are being created.

    So all the comments about locks etc may not be relevant at all here.

    I'll think some more about explaining the above better, because I have an idea that you are confusing spin objects with cogs.

    Which is a Good Thing, because there is still a vast amount of propeller power that you can tap into! Plus you have heaps of memory left, so no worries about having to condense code.

    Which means... the issue at hand is that something in the code is not working. Which bit is not working and what should it do and what is it actually doing?
  • idbruceidbruce Posts: 6,197
    edited 2011-01-15 16:13
    Dr_Acula

    If no cogs are being created, why would they offer the cognew function in spin?

    Bruce
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2011-01-15 16:19
    I'm not sure where the good Dr. got that idea either. Clearly your code contains several cognews to other Spin code.

    -Phil
  • idbruceidbruce Posts: 6,197
    edited 2011-01-15 16:21
    Phil

    :) He must have overlooked that. He got me wondering. LOL

    Bruce
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2011-01-15 16:27
    Ah yes, I see, you have a couple of cognews in that code.

    My experience with cognew is to use it to load pasm into a cog. Pasm is for speed and for background processes. So I like to load some pasm code to drive a vga screen in the background, another to drive a keyboard and buffer the input, and another to run the mouse, and another to run some serial ports. All these things need speed.

    But just to confuse things further, there is a thing called the spin interpreter. This is sort of hidden from the programmer in that it loads up into cog 0 and interprets the code. Normally it is just happily running in the background (unless you come along with Catalina and replace it with your own custom driver).

    Yes, you can open up more spin interpreters but it may or may not be the most efficient way to be using spin. I've never coded like that, as generally I tend to put all the fast things into cogs with pasm code, then the slow lumbering "main" part of the program can happily cycle through everything, checking first if anything is in the keyboard buffer, then if the mouse has moved, then if there is anything in the serial port. This "main" does not need to run fast, because it knows that keypresses are not going to be missed because the keyboard buffer is handling those.

    Of course, the way you are doing things is fine and someone will hopefully pitch in soon with some code suggestions. I'm also mindful of some comments on another thread, so I'm posting less here about code structure than perhaps I might. This line though does have me a little stumped about what it does and what it ought to be doing
      KeypadCheckCog:= cognew(MonitorKeypad, @KeypadCheckStack)  
    

    though that is more my lack of understanding of the propeller than anything else.
  • SapiehaSapieha Posts: 2,964
    edited 2011-01-15 16:28
    Hi Bruce.

    In Time I started with Propeller I was wondering to WHY have 2 types of COGNEW one For PASM and one to CALL Spin.
    Before I understand that IF I call it to start SPIN I really not start SPIN in that COG ONLY Second Spin interpreter that RUN this particular CODE.

    idbruce wrote: »
    Phil

    :) He must have overlooked that. He got me wondering. LOL

    Bruce
  • idbruceidbruce Posts: 6,197
    edited 2011-01-15 16:31
    Sapieha

    I apologize, but I had a very difficult time trying to understand what you typed.

    Bruce
  • SapiehaSapieha Posts: 2,964
    edited 2011-01-15 16:36
    Sorry for that.
    Reread it now (I had some typos in it).
    Maybe now it is readable.
    English are not my language.

    idbruce wrote: »
    Sapieha

    I apologize, but I had a very difficult time trying to understand what you typed.

    Bruce
  • idbruceidbruce Posts: 6,197
    edited 2011-01-15 16:39
    Sapieha

    So then you are just agreeing with Dr_Acula

    Bruce
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2011-01-15 16:55
    Sapieha's comment does make sense, but of course, he is way ahead of me in programming and I've now had to go back and reread the Propeller Manual! He is saying he has been where you are now. As have I.

    Ok, there is something about your comment here that I need to think about:
    It starts with the main cog which is used to display input data on a LCD and update a DS1302. Upon initialization, another cog is created to monitor a keypad for inputing the DS1302 data. Once the data is set into the RTC, another cog is created to repeatedly update time and date variables. And then another cog is created to repeatedly read these variables and write them to a LCD. Meanwhile, the keyboard input cog repeatedly checks for a stop button condition. At which point the cogs would shut down the PROP would reboot.

    In terms of big picture structure, I think it makes sense to run a cog to monitor a keypress. However, I don't think you necessarily have to have a dedicated cog to read a RTC or to output to an LCD.

    I think those things are not time critical and running them in spin in parallel is not going to gain much in the way of speed compared to cycling through a main loop. But I am still mindful of that other thread and discussing coding structure, so rather than dig a big hole for myself, perhaps I could digress and talk about when I first started coding the prop. I found the very first thing I missed compared with other languages was debugging. Run one program and put in debugging and it works fine. Start running several in parallel and you have to handle the debugging statements as well. eg, say you were debugging out to a serial port, and say the serial port driver was so smart that it can handle input from multiple places. Say one process sends it "debug message 1" and another sends it "debug message 2", your screen could show "ddeebbuugg mmeessaagge 12" or worse if they are out of sync.

    I find I simply can't code without the ability to put a debug message on every line. So I tend to stick to a "main" routine, with lots of debugging, sometimes on every line, and then try to use obex code that others have already debugged.

    And debugging pasm in a cog is even harder, because sometimes the memory for the cog is full, so you can't even add one line of debugging code.

    If your keypad is not doing what it is supposed to do, then it will be a lot easier if you can trace every line of code.

    Actually, I just thought of something about how I'd solve this. I'd put everything back into the "main", accept that it is going to run slower, debug it, and then move blocks of code out into other cogs as required.

    There are other debugging solutions too. My standard propeller setup has two serial ports, vga and 20x4 LCD. At one stage when we were building the CP/M emulator, I had one cog going to the LCD, one debugging to the vga, and two, each to the serial ports with two terminal programs open at once.

    So - which bit doesn't work? When you press the "ENT" button?
  • idbruceidbruce Posts: 6,197
    edited 2011-01-15 17:00
    Dr_Acula

    This is a machine interface. The date and time will not always be visible, but when it is, I want the time that is displayed to be accurate. The keyboard in it's own cog is an absolute necessity. As for displaying the date and time, no it's not necessary in that case, but that is not the point. If the code were written correctly, it should not have a problem running these cogs.

    Bruce
  • SapiehaSapieha Posts: 2,964
    edited 2011-01-15 17:03
    Hi Bruce.

    Not directly.

    COGNEW ---- Always load PASM code
    Inline else Second Interpreter in as many COG's You need.
    Dr_Acula wrote: »
    Ah yes, I see, you have a couple of cognews in that code.

    My experience with cognew is to use it to load pasm into a cog. Pasm is for speed and for background processes. So I like to load some pasm code to drive a vga screen in the background, another to drive a keyboard and buffer the input, and another to run the mouse, and another to run some serial ports. All these things need speed.

    Interpreter only loads in COG-0 with start of Propeller.
    Successive COGNEW calls to SPIN code loads next free COG and RNU that code in Parallel with COG-0 interpreter. NOT faster that first one BUT not interrupted by first one and only have some execution time/Phase diference.
    Dr_Acula wrote: »
    But just to confuse things further, there is a thing called the spin interpreter. This is sort of hidden from the programmer in that it loads up into cog 0 and interprets the code. Normally it is just happily running in the background (unless you come along with Catalina and replace it with your own custom driver).


    Can't agree at all with that.
    As every NEW started Interpreter run theirs SPIN code in parallel it give big difference if You run entire SPIN only from Primary Interpreter else divide it to use more COG's to have all necessary answers next in same time with not interrupted procesing
    Dr_Acula wrote: »
    Yes, you can open up more spin interpreters but it may or may not be the most efficient way to be using spin. I've never coded like that, as generally I tend to put all the fast things into cogs with pasm code, then the slow lumbering "main" part of the program can happily cycle through everything, checking first if anything is in the keyboard buffer, then if the mouse has moved, then if there is anything in the serial port. This "main" does not need to run fast, because it knows that keypresses are not going to be missed because the keyboard buffer is handling those.

    Sorry NO comments.
    As that other thread was OK in my opinion from Yours end. Even if I handle that situations differently.

    Dr_Acula wrote: »
    Of course, the way you are doing things is fine and someone will hopefully pitch in soon with some code suggestions. I'm also mindful of some comments on another thread, so I'm posting less here about code structure than perhaps I might. This line though does have me a little stumped about what it does and what it ought to be doing
    though that is more my lack of understanding of the propeller than anything else.

      KeypadCheckCog:= cognew(MonitorKeypad, @KeypadCheckStack)  
    
  • idbruceidbruce Posts: 6,197
    edited 2011-01-15 17:06
    Okay Another Round

    Here is the same application cut down to the bare bones. Still has problems.

    Bruce
  • SapiehaSapieha Posts: 2,964
    edited 2011-01-15 17:21
    Hi Bruce.

    As I not have same things that You on my Propeller I can't directly test it. BUT if You describe what type of problems. Maybe it be possible to find solution logically in code.

    idbruce wrote: »
    Okay Another Round

    Here is the same application cut down to the bare bones. Still has problems.

    Bruce
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2011-01-15 17:24
    ok, so this is your keyboard input routine
    PUB MonitorKeypad
    
      DIRA[0..3]~  
      DIRA[5]~     
    
      REPEAT  
      
        WAITPEQ(|<5, |<5, 0)
    
        KeyPressed := TRUE      
        
        PressedKey := INA[3..0]
    
        IF PressedKey == STOP AND AbleToStopExample == TRUE
    
          COGSTOP(TimeTrackCog~ -1)
          COGSTOP(TimeDisplayCog~ -1)
    
          LCD.Clear
          LCD.Move(1,1)
          LCD.Str(STRING("End Of The Example"))
    
          LCD.Move(1,2)
          LCD.Str(STRING("Goodbye :)"))
    
          Reset := TRUE
    
          QUIT   
        
    
        WAITPNE(|<5, |<5, 0)
    

    and you start this and when you press Enter, nothing happens?

    There are several possibilities.
    The code did not start
    The code is not running in a loop
    The mask for the keypress is incorrect
    The flag you have set isnot what you think they are because something else changed it . AbleToStopExample
    There is a mixup with variables somewhere else (I know myself I'd get muddled with "pressedkey" and "keypressed" in the same program

    Where to start?

    You said it does not detect Enter. I'd be thinking you need some way of printing "enter" after this line PressedKey := INA[3..0]

    A quick and dirty solution might be to add 65 to PressedKey and print it out - at least you will get an ascii character and you can work out the bit pattern from that.

    Next, maybe split this line
    IF PressedKey == STOP AND AbleToStopExample == TRUE

    into two IF statements and put a debug after the first and then after the second.

    Or am I in the wrong bit of code?

    Hmm, I just saw this:
      KeyPressed := FALSE
      AbleToStopExample := FALSE
      Reset := FALSE
    
      KeypadCheckCog:= cognew(MonitorKeypad, @KeypadCheckStack)
    

    which runs this
    PUB MonitorKeypad
    
      DIRA[0..3]~  
      DIRA[5]~     
    
      REPEAT  
      
        WAITPEQ(|<5, |<5, 0)
    
        KeyPressed := TRUE      
        
        PressedKey := INA[3..0]
    
        IF PressedKey == STOP AND AbleToStopExample == TRUE
    
          COGSTOP(TimeTrackCog~ -1)
          COGSTOP(TimeDisplayCog~ -1)
    
          LCD.Clear
          LCD.Move(1,1)
          LCD.Str(STRING("End Of The Example"))
    
          LCD.Move(1,2)
          LCD.Str(STRING("Goodbye :)"))
    
          Reset := TRUE
    
          QUIT   
        
    
        WAITPNE(|<5, |<5, 0)
    

    If "abletostopexample" is set as false, how will it ever exit? (it is still false in your latest code too)
  • idbruceidbruce Posts: 6,197
    edited 2011-01-15 17:32
    Dr_Acula

    You are not following the code correctly. After the three cogs are called AbleToStopExample is set to TRUE. When the button #8 from the keypad is pressed all the cogs should end and the Propeller should reset.

    Bruce
  • SapiehaSapieha Posts: 2,964
    edited 2011-01-15 17:39
    Hi Bruce.

    I'm not good programmer in SPIN but send You my edition of Yours code for test.
    Maybe You understand my mods to it.
    And maybe it give You some solution's



    idbruce wrote: »
    Dr_Acula

    You are not following the code correctly. After the three cogs are called AbleToStopExample is set to TRUE. When the button #8 from the keypad is pressed all the cogs should end and the Propeller should reset.

    Bruce
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2011-01-15 18:01
    PUB BareBones
    
      KeyPressed := FALSE
      AbleToStopExample := FALSE
      Reset := FALSE
    
      LCD.Start
    
      KeypadCheckCog:= cognew(MonitorKeypad, @KeypadCheckStack)  
      TimeTrackCog := cognew(TrackTimeAndDate, @TimeTrackStack)
      TimeDisplayCog := cognew(DisplayTimeAndDate, @TimeDisplayStack)
      AbleToStopExample := TRUE 
    

    Yes, you are right, it gets changed.

    Unless... variables are not updated once a cog spin pub is started??

    Or somehow those other two cogs fail to start for some reason.

    I'd be interested to see a trace on that variable printing out continuously.
       PressedKey := INA[3..0]          
       If AbleToStopExample == TRUE
          LCD.Str(STRING("True"))
       else
          LCD.Str(STRING("False"))
    
  • idbruceidbruce Posts: 6,197
    edited 2011-01-15 18:15
    Dr_Acula and Sapieha

    Okay guys you need to look at the code and understand it before sending me messages. I appreciate your effort, but you guys are missing very important aspects of the source code. I keep responding and that takes time to explain that you need to understand the code before offering suggestions. A new sample will be arriving shortly with FullDuplexSerial instead of LCD display.

    Bruce
  • idbruceidbruce Posts: 6,197
    edited 2011-01-15 18:32
    Alright

    Here is another sample with FullDuplexSerialPlus instead of LCD display. It is not operating correctly. Baud rate is set correctly, but funny characters show up in the terminal window.

    Bruce
Sign In or Register to comment.