Shop OBEX P1 Docs P2 Docs Learn Events
Real time Clock passing global variables — Parallax Forums

Real time Clock passing global variables

GrantmcFGrantmcF Posts: 30
edited 2012-04-29 19:22 in Propeller 1
I'm still new at this and haven't gotten the hang of passing variables yet. I have modified a RTC object I found on the object exchange to use 3 buttons and display on a serial LCD. Everything works fine when I run it on one cog. I have tried to modify it to run on 2 cogs with display and setup in the primary cog and the time keeping functions in the 2nd cog. It works ok until I try to write the setup data to the global variables with this instruction, rtc.setDatetime(month, day, year, dow, hour, minute, second) I know I'm not passing the variables between the cogs properly, but every configuration I have tried has choked. I have tried many variations base on the examples in the programming and lab manuals but I'm apparently missing something. Attached is the code without the mess from all my attempts. If anyone can show me what I'm doing wrong it would be greatly appreciated.

Comments

  • kuronekokuroneko Posts: 3,623
    edited 2012-04-25 19:24
    The RTC object you are talking to in the top level object is not the same as the one initialised & Co in the RTC_new_cog object. You'd have to find a way of communicating your top level RTC related calls to the 2nd cog (i.e. pass the data) which will then do the calls for you in the correct context.
  • GrantmcFGrantmcF Posts: 30
    edited 2012-04-26 00:00
    Correct, and this is what I am having trouble with, and why I have asked for help.
  • kuronekokuroneko Posts: 3,623
    edited 2012-04-26 00:32
    Quick and dirty. The child object starts a new cog running an endless (command) loop. Commands are sent from the top level object and acted on by the background loop. When the command has finished the data array (held in the child object) is stable and can be inspected/updated by the top level object. Note that both object are merged here for simplicity. When separated the commented child references need to be resolved to whatever you object name is, e.g. {child.}init may become clock.init. The example below will simply increment the LED bar on the demoboard. Only the child object accesses the pins.
    CON
      #1, READ, WRITE
      
    VAR
      long  dta[16]
      long  command
    
      long  stack[32]
      
    [COLOR="#FFA500"]PUB selftest | n
    ' This piece of code represents the top level object.
    
      {child.}init                                          ' initialise child object
    
      repeat
        {child.}run({child#}READ)                           ' send read command
        n := {child.}get(0) + 1                             ' read and manipulate data
        {child.}set(0, n)                                   ' update data
        {child.}run({child#}WRITE)                          ' send write command
        waitcnt(clkfreq + cnt)
    [/COLOR]
    PUB init
    
      cognew(helper, @stack{0})
    
    PUB get(idx) : v
    
      v := dta[idx]
    
    PUB set(idx, v)
    
      dta[idx] := v
    
    PUB run(cmd)
    
      command := cmd
      repeat
      while command
      
    PRI helper
    
      dira[16..23]~~                                        ' init h/w (only talked to from here)
    
      repeat
        repeat until command                                ' idle until <> 0
        case command
          READ:  ' read from h/w, update local data array
            dta[0] := ina[16..23]
          WRITE: ' write to h/w, using local data array
            outa[16..23] := dta[0]
        command := 0                                        ' done, say so
        
    DAT
    
    Also, the loop doesn't have to sit there idling. It can do other tasks originating from somewhere else but should every now and then look at the command state. As usual, this is one of many ways of doing it ...

    For your RTC setup this simply means you send the time related data with set to the e.g. clock object then instruct it to write the data to the RTC. You can also move the dta array to the top level object and tell the child object its location. This would remove the need for get/set methods.

    A variation which shows the background loop doing other stuff and checking command periodically (about 8 times/sec).
    PRI helper
    
      dira[16..23]~~                                        ' init h/w (only talked to from here)
    
      repeat
        repeat until command                                ' busy until <> 0
          [COLOR="blue"]outa[16..18]--
          waitcnt(clkfreq/8 + cnt)[/COLOR]
        case command
          READ:  ' read from h/w, update local data array
            dta[0] := ina[20..23]
          WRITE: ' write to h/w, using local data array
            outa[20..23] := dta[0]
        command := 0                                        ' done, say so
    
    DAT
    
  • GrantmcFGrantmcF Posts: 30
    edited 2012-04-29 00:27
    Sorry for the response delay, I was trying to understand your example and I have to say I have trouble following it. I would like to try working through it using my program, because I have a better understanding of it, if you are still willing to help. Going by the example in the Education kit lab book on page 168, in my parent object I changed, Pub clockcog to Clock.start(@hour, @minute, @second, @day, @month, @year, @dow, @ampm, @hour12). In RTC_new_cog I moved the variables hour, minute, @second, day, month, year, dow, ampm, hour12 to the parameters of the Start object. This causes it to have compile issues when it gets to rtc.readDate(@day, @month, @year, @dow). It wants variables instead of addresses. When I put in variables it wants an expression. Any clues as to what it really wants?
  • kuronekokuroneko Posts: 3,623
    edited 2012-04-29 01:07
    So it looks like you decided to keep all variables in the top level object. It's probably easier to just communicate the address of hour (all the others follow with an offset of 1). This address then has to be stored in the child object as the base address, e.g.
    CON
      #0, hour, minute, second, day, month, year, dow, ampm, hour12
    
    VAR
      long  base
    
    PUB start(base_address)
    
      base := base_address
      ...
    
    Access to the relevant elements is then done like this (in the child object):
    byte[base][minute] := 42
    
  • Duane DegnDuane Degn Posts: 10,588
    edited 2012-04-29 01:28
    I went through and did pretty much what kuroneko suggested.

    This is a really awkward way to do this, but I tried to change as little of your original code as possible.

    I didn't change the file names so don't extract it to the same folder as your original files.

    I added the address of hour to the start method of "RTC_new_cog".
    Clock.Start (Lcd_Pin ,up_Button1, down_Button2, down_Button2, @hour)
    

    Here's the new start method of the child object.
    Pub Start(display_Pin, Button1, Button2, Button3, address)
    '  Stop
      parameterAddress := address
      ClockcogID := cognew (Main, @stack1)
    '   cognew (Main, @stack1)
    
    

    I added these constants to keep track of which byte to use for which value.
    ' enumerate time parameters
      #0, _hour, _minute, _second, _day, _month, _year, _dow, _ampm, _hour12
          
    

    Here's the main loop of the child object.
      repeat
        if setDateFlag == 1
          rtc.setDatetime(monthSet, daySet, yearSet, dowSet, hourSet, minuteSet, secondSet)
          setDateFlag := 0
        rtc.readTime(parameterAddress + _hour, parameterAddress + _minute, parameterAddress + _second )    'read time from DS1302
        if byte[parameterAddress + _hour] > 12
          byte[parameterAddress + _hour12] := byte[parameterAddress + _hour] - 12
        else
          byte[parameterAddress + _hour12] := byte[parameterAddress + _hour]
          if byte[parameterAddress + _hour] == 0
            byte[parameterAddress + _hour12] := 12 
        if byte[parameterAddress + _hour] => 12
          byte[parameterAddress + _AMPM] := 1
        else
          byte[parameterAddress + _AMPM] := 0 
        rtc.readDate(parameterAddress + _day, parameterAddress + _month, parameterAddress + _year, parameterAddress + _dow )  'read date from DS1302
     
    

    Since the top object just had one call to the RTC object, I changed the call to be to the child object instead. This way two different cogs wont try to access the RTC at the same time which would cause errors.

    Here's the added method to the child object.
    Pub setDatetime(month, day, year, dow, hour, minute, second)
      monthSet := month
      daySet := day
      yearSet := year
      dowSet := dow
      hourSet := hour
      minuteSet := minute
      secondSet  := second
      setDateFlag := 1
      repeat while setDateFlag == 1
      
    

    All these methods in the child object are no longer needed since the variables in the top object are automaically updated.
    Pub Getday
    Pub Getmonth
    Pub Getyear
    Pub Getdow
    Pub Getampm
    Pub Gethour
    Pub Gethour12
    Pub Getminute
    Pub Getsecond
    

    The code compiles, but I don't have a DS1302 to test it with.

    As I mentioned, this is really awkward. Hopefully seeing your own code modified to have the child object write to the variables of the top object will help you understand the way this all works and you can get this code to do what you want.
  • GrantmcFGrantmcF Posts: 30
    edited 2012-04-29 02:52
    Thanks, I will try this as soon as I get a chance. I'm working night shift right now so not much time to work with this at the moment..
  • GrantmcFGrantmcF Posts: 30
    edited 2012-04-29 19:22
    I had a couple minutes to try it and it works. Now to study it and see if I understand it. Thanks again.
Sign In or Register to comment.