Shop OBEX P1 Docs P2 Docs Learn Events
Selection of objects at run time — Parallax Forums

Selection of objects at run time

ftkalcevicftkalcevic Posts: 10
edited 2009-12-13 10:26 in Propeller 1
Is it possible to select which object you want loaded into cogs (and the number) at runtime?

I am writing a simple pwm motor controller.· It sends a signal to the motor driver to run the motor.· The signal can be PWM+Direction, Step/Dir, or the two halves of an H-Bridge.· I'd like to be able to write a .spin file (in PASM) for each individual type.· Then, via serial communications, the host pc can configure the type of output, and the main cog can load the one that is required.

Can this be done?

Thanks,
Frank

Comments

  • Mike GreenMike Green Posts: 23,101
    edited 2009-12-11 23:09
    You want to dynamically configure a program, loading one of a set of low-level I/O drivers from some kind of storage at run-time. It's theoretically possible to do this, but very difficult and you'd have to have a very deep knowledge of the internals of Spin to accomplish this. It would be easier to do if your low-level I/O drivers were written in assembly. In practice, your low-level drivers would not be very complex and would not take much memory, so all the objects could reside in hub memory at the same time and you could just start up a cog or several with the ones you wanted. If they communicate through the same kind of data structure (variables), it wouldn't matter to your higher level routines (in Spin) which one of a set is actually executing in the cog. This scheme is actually pretty straightforward in Spin.
  • stevenmess2004stevenmess2004 Posts: 1,102
    edited 2009-12-11 23:41
    If you want to load spin objects from sd cards it is quite possible like Mike says. However without the right tool chain it is really a pain in the neck and extremly prone to errors. I've been working at it on and off for the last year or two. I'm going away on holidays next week (no net access) and will hopefully get it all in a useable state now that we have sphinx.
    If all the different code fits in the prop chip than it should fairly easy to do. You can use a trick like this to make it easy. However, if you do this than the methods that you call have to be have the same number of arguments and be in the same order for all of the objects.
    OBJ
      PWM:"pwmObject"
      step:"stepObject"
      hbridge:"hbridgeObject"  'these need to be after each other
    PUB main|object
      object:=getObjectFromPC 'object needs to be 0,1 or 2
      PWM[noparse][[/noparse]object].start  'start whichever object you want to use. The "[noparse][[/noparse]object]" will select the right object and needs to be used
                                 'whenever you call one of the methods.
      PWM[noparse][[/noparse]object].setSpeed(speed) 'an example 
      PWM[noparse][[/noparse]object.setDirection(direction) 'another example
      '...
    
    


    Post Edited (stevenmess2004) : 12/11/2009 11:54:24 PM GMT
  • ftkalcevicftkalcevic Posts: 10
    edited 2009-12-11 23:54
    Thanks for the replies.

    These are small routines, so they should all fit into memory at the same time.

    stevenmess2004, what happens with any VAR data that is declared in an object.· If I spin up more than one instance, will they all point to the same VAR data?· Will I need to manage main memory myself?·


    Thanks,
    Frank
    ·
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2009-12-11 23:58
    VAR data are unique for each instance of an object. DAT data are shared.

    -Phil
  • stevenmess2004stevenmess2004 Posts: 1,102
    edited 2009-12-12 00:02
    Every object declared has it's own set of var variables but the dat variables are shared by all objects of the same type. So for example
    OBJ
    obj1:"pwmobject"
    obj2:"pwmobject"
    obj3:"otherobject"
    
    


    In this code there will be one copy of the spin code and dat variables for pwmobject and two copies of the var variables for pwmobject. other object has its own complete copy of its spin, var variables and dat variables.

    (well at least most of the time. If the code in otherobject is exactly the same as pwmobject it will be treated as if it was another copy of pwmobject.)
  • ftkalcevicftkalcevic Posts: 10
    edited 2009-12-12 00:10
    So in the case of dynamically creating multiple instances...

    OBJ
    obj1: pwmobj
    obj2: stepdirobj
    
    PUB main
    obj1.Start ' Create instance 1
    obj1.Start ' Create a second instance (assumes there's a cognew in Start
    obj1.Start ' 3
    

    Will these instances share the same VAR from the obj1?

    Do I need to allocate the data myself? ....
    OBJ
    obj1: pwmobj
    obj2: stepdirobj
    
    VAR
    long data[noparse][[/noparse]8]
    
    PUB main
    obj1.Start( @data[noparse][[/noparse]0] ) ' Create instance 1
    obj1.Start( @data[noparse][[/noparse]1] ) ' Create a second instance (assumes there's a cognew in Start
    obj1.Start( @data[noparse][[/noparse]2] ) ' 3
    


    Post Edited (ftkalcevic) : 12/12/2009 12:15:09 AM GMT
  • stevenmess2004stevenmess2004 Posts: 1,102
    edited 2009-12-12 04:13
    Okay, lets try explaining this a little better. In spin all objects are statically allocated (unless you play with stuff that is not supported by any compilers). Using my example above
    OBJ
    obj1:"pwmobject"
    obj2:"pwmobject"
    obj3:"otherobject"
    


    The Memory endups looking something like this
    DAT overallObject
    Spin overallObject - pub and pri methods
    DAT pwmObject
    Spin pwmObject - pub and pri methods
    DAT otherobject
    Spin otherobject - pub and pri methods
    VAR overallObject
    VAR obj1
    VAR obj2
    VAR obj3
    
    


    This memory layout remains fixed throughout the life of the program and you can't change it. When I use instance in spin I mean a reference to an object such as obj1 or obj2. It doesn't matter what cog an object is running in, when you access any of the VAR or DAT variables they will still reference the same thing.

    Local variables are a different matter though. Because local variables live on the stack and each cog has it's own stack the local variables will be different for each cog.

    If you do want to use different data in each cog than you will need to either create different instances (not just start the same instance in a different cog) or write your code to use pointers and then pass in different pointers. Don't forget that you can have an array of objects that will all have their own VAR sections. You could do something like this.
    OBJ
    obj1:"pwmobj"
    obj2:"stepdirobj"
    
    PUB main
    obj1[noparse][[/noparse]0].start
    obj1.start
    obj2.start
    
    
  • ftkalcevicftkalcevic Posts: 10
    edited 2009-12-12 05:07
    Understood, but I don't think this has answered my original question...

    How can I decided the number and types of objects I run at runtime?

    I can see this as one solution....

    CON
      NUM_DEVICES = 7
    
        
    OBJ
      type1[noparse][[/noparse]NUM_DEVICES]: "DeviceType1"
      type2[noparse][[/noparse]NUM_DEVICES]: "DeviceType2"
      type3[noparse][[/noparse]NUM_DEVICES]: "DeviceType3"
      type4[noparse][[/noparse]NUM_DEVICES]: "DeviceType4"
      type5[noparse][[/noparse]NUM_DEVICES]: "DeviceType5"
     
    PUB Start
     
      type1[noparse][[/noparse]0].Start
      type1[noparse][[/noparse]1].Start
      type2[noparse][[/noparse]0].Start
      type3[noparse][[/noparse]0].Start
      type4[noparse][[/noparse]1].Start
      type1[noparse][[/noparse]2].Start
      type1[noparse][[/noparse]3].Start
      type5[noparse][[/noparse]0].Start
     
    
    
    
    
    
    
    
    

    Here I allocate storage for the maximum number of each instance.· COGS are only started when Start is called.· This wastes lots of memory.

    My other idea, the confusing post above, was to define one object instance of each type, then pass in a pointer to some space allocated to it.· So the object would be...

      
    VAR
      long data_ptr
    
      
    PUB Start( _data_ptr )
      data_ptr := _data_ptr
      
      cognew(@main, @data_ptr)
     
    DAT           
       org       0
     
    main
    
            mov     temp, par
            rdlong  data_addr, temp                ' data ptr
     
    ' do stuff with data_addr
                             
    data_addr  res  1            
    
    


    The VAR data_ptr, is only used in starting the·PASM in the COG.· It is a pointer to shared memory, stored in COG memory.· It is then up to me to ensure there is enough longs (shared memory)·allocated for the object.

    And I can create COGS by...

    OBJ
      obj1: pwmobj
      obj2: stepdirobj
    
    VAR
      long data[noparse][[/noparse]8]
    
    PUB main
      obj1.Start( @data[noparse][[/noparse]0] )  ' Create instance 1.  Give 1 long of shared memory.
      obj1.Start( @data[noparse][[/noparse]1] )  ' Create a second instance (assumes there's a cognew in Start
      obj1.Start( @data[noparse][[/noparse]2] )  ' 3
    
    
  • stevenmess2004stevenmess2004 Posts: 1,102
    edited 2009-12-12 05:32
    Yes, that looks right. Just remember that a cognew will chop off the last two bits of your address so it needs to be long aligned. Another alternative would be something like this

     
    PUB Start( _data_ptr )
      data_ptr := _data_ptr
      
      cognew(@main, 0)
     
    DAT          
       org       0
     
    main
    ' do stuff with data_ptr
    data_ptr    long 0                         
    data_addr  res  1
    
    


    Just saves a little bit of code and you don't have to worry about it being long aligned.
  • ftkalcevicftkalcevic Posts: 10
    edited 2009-12-12 05:48
    How does that work?· Is data_ptr in COG memory, or main memory?·

    Is the spin code changing the DAT section in main memory, amd then copying it into the COG?·
    ·
  • stevenmess2004stevenmess2004 Posts: 1,102
    edited 2009-12-12 06:03
    data_ptr is in hub memory but when you start the assembly cog it gets loaded in with the rest of your code. So when you change in in Start it is in the hub. Then when the cog gets started it gets copied into cog ram and the cog can use it. Because it gets copied into the cog you can then change it (in the hub) for the next cog that you start and everything will be fine.
  • MagIO2MagIO2 Posts: 2,243
    edited 2009-12-13 10:26
    As I understand your original post there is no need to replace the SPIN-code?! Just the PASM driver has to be replaced on demand.

    What I do - mainly to save RAM - is that I put all my PASM-drivers (keyboard, tv, SD ...) into upper part of the 64kB EEPROM. The SPIN-part of the drivers has been changed to load it into a temporary global buffer and start the COG. So, there is no PASM in a DAT section of the drivers any more.
    But with this it's also possible to select a driver during startup or replace it during runtime.
Sign In or Register to comment.