Shop OBEX P1 Docs P2 Docs Learn Events
Imitating an Interrupt driven system — Parallax Forums

Imitating an Interrupt driven system

shanghai_foolshanghai_fool Posts: 149
edited 2008-12-04 23:51 in Propeller 1
To all the Gurus out there.

My application requires doing some things at specific intervals. I understand waitcnt but it doesn't address what I really want.

Lets say I have a main loop in which I want to run 1 routine 100 times each second or at 10ms intervals,
and a second routine that runs 50 times a second or 20ms intervals,
and a third routine that runs at 5/sec or 200ms,
and finally 1 routine that runs once per second.
Can this be done when you have no timer interrupt?

That is assumming each process is done well within its allotted timeslot.

Or does this require each function to be in its own cog?
·

Comments

  • BaggersBaggers Posts: 3,019
    edited 2008-12-02 11:22
    Hi shanghai_fool

    you could have a main_loop checking to see if cnt has gone over a value for each routine, then call it's function if it has.
    initmain
          mov prevcnt1,cnt
          mov prevcnt2,prevcnt1
          mov prevcnt3,prevcnt1
          mov prevcnt4,prevcnt1
    mainloop
          mov tmp,cnt         ' get current cnt
          sub tmp,prevcnt1 ' subtract prevcnt1, ie when routine 1 last had a value
          cmp tmp,addcnt1 wz,wc
     if_ae add prevcnt1,addcnt1
     if_ae call #routine1
    
          mov tmp,cnt         ' get current cnt
          sub tmp,prevcnt2 ' subtract prevcnt1, ie when routine 2 last had a value
          cmp tmp,addcnt2 wz,wc
     if_ae add prevcnt2,addcnt2
     if_ae call #routine2
    
          mov tmp,cnt         ' get current cnt
          sub tmp,prevcnt3 ' subtract prevcnt1, ie when routine 3 last had a value
          cmp tmp,addcnt3 wz,wc
     if_ae add prevcnt3,addcnt3
     if_ae call #routine3
    
          mov tmp,cnt         ' get current cnt
          sub tmp,prevcnt4 ' subtract prevcnt1, ie when routine 4 last had a value
          cmp tmp,addcnt4 wz,wc
     if_ae add prevcnt4,addcnt4
     if_ae call #routine4
    
          jmp  #mainloop
    
    routine1
          nop    ' put code for routine 1 here
    routine1_ret ret
    
    routine2
          nop    ' put code for routine 2 here
    routine2_ret ret
    
    routine3
          nop    ' put code for routine 3 here
    routine3_ret ret
    
    routine4
          nop    ' put code for routine 4 here
    routine4_ret ret
    
    tmp long 0
    prev1cnt long 0
    prev2cnt long 0
    prev3cnt long 0
    prev4cnt long 0
    
    'assuming 80 Mhz tick speed
    
    add1cnt long 80_000_000 / 100
    add2cnt long 80_000_000 / 50
    add3cnt long 80_000_000 / 5
    add4cnt long 80_000_000
    
    



    Hope this helps [noparse];)[/noparse]

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    http://www.propgfx.co.uk/forum/·home of the PropGFX Lite

    ·
  • Mike HuseltonMike Huselton Posts: 746
    edited 2008-12-02 12:25
    Excellent code snippit, Baggers.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    JMH - Electronics: Engineer - Programming: Professional
  • BaggersBaggers Posts: 3,019
    edited 2008-12-02 12:31
    Thx Quantum [noparse]:)[/noparse] glad you like it, hope it helps.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    http://www.propgfx.co.uk/forum/·home of the PropGFX Lite

    ·
  • shanghai_foolshanghai_fool Posts: 149
    edited 2008-12-02 13:21
    Thanks Baggers,

    It looks like it may work except no routine can run over 20s. My 200ms routine actually takes ~80ms so it will have to go into its own cog. I haven't finished or timed the others yet.

    Donald
  • BaggersBaggers Posts: 3,019
    edited 2008-12-02 15:12
    You're welcome [noparse]:)[/noparse]

    How do you mean no routine can run over 20s?

    On a side note, if they do overrun into another routine's time, it the other routine will be delayed until the one executing is finished, then it will execute, slightly late, but should re-steady itself, should it not over run again.

    but yes, if it's timing critical, that no routine stops another, any that will overflow into another's execution timescale, then by all means put it into a seperate cog [noparse]:)[/noparse]

    also on another note, on the init part, you might want to add an offset for each routine's start.

    if all your routines times add up to more than 10 ms then you'll want to move one or some of the bigger ones to another cog, as if they should start on same tick, they'll be delayed.

    so add something like this.

    initmain
          mov prevcnt1,cnt
          mov prevcnt2,prevcnt1
          mov prevcnt3,prevcnt1
          mov prevcnt4,prevcnt1
          add prevcnt1,add1off
          add prevcnt2,add2off
          add prevcnt3,add3off
          add prevcnt4,add4off
    mainloop
    ... rest of stuff from before
    
    add1off long 80_000_000 / 1000
    add2off long 80_000_000 / 2000
    add3off long 80_000_000 / 3000
    add4off long 80_000_000 / 4000
    
    

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    http://www.propgfx.co.uk/forum/·home of the PropGFX Lite

    ·
  • shanghai_foolshanghai_fool Posts: 149
    edited 2008-12-04 06:53
    I have several different objects working ok independantly so now its time to try and tie them all together. I am trying to figure out how to manage the cogs. I may be trying to do too much. The 200ms routine is the GPS/FPU object. The 5Hz GPS needs 80ms out of the 200ms to handle the GPS input capture and manipulation for variables. It is asychronous, so will need its own cog. The RC receiver input is ~ 50 Hz, asychronous so will have its own cog. I have decided to use separate prop for servo32 as I need more outputs. I also need a separate cog for the SD read/write. The 1 to 5 Hz for RTC (DS1307) ,SCP1000 baro alt. SRF05 ultrasonic alt and mag compass (HMC6352 or HMC6343) can run in main loop. My biggest problem is figuring out how many cogs I have left after loading IMU so I know where to put things. I will have to have either full-duplex serial or spi serial between the props. It would be nice to have the GPS/FPU on the same MCU as IMU so it can utilize the FPU and not have to run 2 more cogs for floating point routines. I also don't know if the FPU will have enough time between GPS strings to do the IMU calculations.

    Jim Woods, who wrote the IMU objects says it needs 4 cogs including the 2 floating point objects, so if I put that on the same MCU as the GPS/FPU, then both should use 3 cogs. Since most of the data to be transferred to the SD card will be located here, it stands to reason that the SD object should be there also. That makes 5 plus the RC Input makes 6. The serial to prop#2 makes 7 and the main loop makes 8. Everything else can go into prop #2. Whew! If I can do that, it will beat the heck out of 60Mhz ARM. The main loop cog will also use its counters to measure RPM for 2 motors but that takes very little cpu time. The IMU MCP3208 interface will possibly have 2 8 input A/D so I can measure other analog inputs as well for battery voltage/current, air speed, etc.

    I think its going to take me some time but I certainly think I can use your algorithms.

    Donald
  • BaggersBaggers Posts: 3,019
    edited 2008-12-04 08:17
    Cool, I'm glad you can do it [noparse];)[/noparse] and glad that the algorithms helped [noparse]:)[/noparse]

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    http://www.propgfx.co.uk/forum/·home of the PropGFX Lite

    ·
  • shanghai_foolshanghai_fool Posts: 149
    edited 2008-12-04 08:34
    Notice I said "I want". Not that I "will". I've come a long way in 3 weeks but I'm far from having the necessary expertise to accomplish all this right away. I am just trying to discover if its possible. I'm still having trouble passing parameters sometimes. I'm never sure where the data is at times. I think all cogs read/write to main ram, never between cogs so if I set up my data in a main memory linear array for each cog, then I can fill the aray with whatever each cogs needs. I should be able to do it. I'm now working on a spreadsheet to determine best pin arrangement. From working with the FPU, it seems that a call only passes the 1 address (parm) so all data is indexed from that point (parm+4,parm+8, etc). Its mind-boggling.
  • BaggersBaggers Posts: 3,019
    edited 2008-12-04 08:58
    Yes all cogs comms are through HUB-RAM and yes, you can only pass one pointer to a cog, on it's initialisation, so you point it to the first entry in your data structure, and then lke you said, read it indexed from that address, param 0 = PAR, param 1 = PAR+4 etc. assuming you use longs for each entry

    you could have something like this

    CON
    entry1 = 0
    entry2 = 4
    entry3 = 8
    entry4 = 12
    entry5 = 16
    
    


    etc..

    then to access it in your cog asm program
      mov tempptr,PAR
      add tempptr,#entry5
      rdlong value,tempptr
    
    



    hope this helps.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    http://www.propgfx.co.uk/forum/·home of the PropGFX Lite

    ·
  • LawsonLawson Posts: 870
    edited 2008-12-04 19:32
    Baggers said...
    Yes all cogs comms are through HUB-RAM and yes, you can only pass one pointer to a cog, on it's initialisation, so you point it to the first entry in your data structure, and then lke you said, read it indexed from that address, param 0 = PAR, param 1 = PAR+4 etc. assuming you use longs for each entry

    Not quite true. My favorite way to pass pointers into ASM is to have "psychic code" I.e. all the pointers are written into variables in my code BEFORE I start the code in a new cog.

    Pub Start(some_pointer)    'start is passed a pointer to a variable in Hub-ram
        Hub_ptr_1 = some_pointer   'modify my ASM code to contain the pointer value
        cognew(@entry,0)
    
    org 0
    entry        'asm code here
                 .
                 .
                 RDlong  temp, Hub_ptr_1
                 .
                 .
    Hub_ptr_1    Long   0-0    'the "0-0" tells me my code will change this value at run-time.  
    temp         res    1
    fit          496
    
    



    Best of luck,
    Marty

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Lunch cures all problems! have you had lunch?
  • BaggersBaggers Posts: 3,019
    edited 2008-12-04 23:14
    I didn't say it was the only way [noparse];)[/noparse]
    your way is good for savng room.
    but my way was a simple way for having a joined buffer for sharing info between all the cogs that need access to it, plus less chance of missing setting up a pointer [noparse];)[/noparse]

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    http://www.propgfx.co.uk/forum/·home of the PropGFX Lite

    ·
  • Timothy D. SwieterTimothy D. Swieter Posts: 1,613
    edited 2008-12-04 23:51
    Wow - this is all very interesting to see the different code structures happening here. I don't know if this will help, but in the latest Graphics LCD driver I wrote in ASM I set it up to behave in a format of wait for a command, then execute the command and then return to waiting. This is like the way the graphics or Float32 driver is structured.

    You can review the object here: http://obex.parallax.com/objects/389/

    I have commented it pretty heavily. In time I will post a template and app note for this time of structure so that others can take advantage of it.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Timothy D. Swieter, E.I.
    www.brilldea.com - Prop Blade, LED Painter, RGB LEDs, uOLED-IOC, eProto for SunSPOT, BitScope
    www.tdswieter.com
Sign In or Register to comment.