Shop OBEX P1 Docs P2 Docs Learn Events
Concurrent Serial Interface — Parallax Forums

Concurrent Serial Interface

inakiinaki Posts: 262
edited 2006-09-30 22:48 in Propeller 1
I am using the Full-Duplex serial interface for a robot. It works fine.
Currently I send commands and read parameters from the robot and it is ok.

However I would like to write a set of parameters on the TV-Display at the same time I·send·and read commands. That is to say, I want to perform two/three tasks at the same time with the serial object. Should I use 3 serial objects·with some sort of synchronization or ·should I use only one ?

I want to so the following at the same time:

- Send a command to the robot
- Read parameters: load, temperature, position, etc.
- Display the full status·for each servo or a particular servo

I have devised a classic round robin communication. Is this the right approach ?

Notes: the servos are daisy chained on a serial bus. Each servo has an ID. The serial bus master (the Propeller)·is synchornized with the the servos but I do not have any synchronization for running several communication tasks at the same time.



▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔

Comments

  • Jim FouchJim Fouch Posts: 395
    edited 2006-09-30 21:49
    I a project I'm working on I use one Serial object to receive information from another uController and then post the new values into a global variable (A common memory area location). The Main cod then displays the new info on the TV.

    In my Main Cog...

    ·
    Var
     
      Long  Signals,Gear,Speed,TachValue,CoolantTemp,BatteryVoltage
     
    OBJ
     
      DP      : "DataPump"
     
    
    


    Then when I Start my Cog that uses a serial Object...

    DP.Start(@Signals) ' Pass Location of First Var to be shared 
    


    In the DataPump Object...Notice I create a copy of the same memory structure I use in my main Cog. When I get a valid packet I use a LONGMOVE to copy the local vars to the Main ones. You may want to use locks to make sure you're not reading the vars in the main cog.

    Var
      Long Stack[noparse][[/noparse]45]       
      byte cog
      Long Signals,Gear,Speed,TachValue,CoolantTemp,BatteryVoltage
    Obj
      UART   : "FullDuplexSerial"
      delay  : "timing" 
                 
    Pub Start(GlobalPointer): Success | i
      Stop
      Success := (Cog := CogNew(Run(GlobalPointer), @Stack) + 1)
     
    Pub Stop
      if cog
        CogStop(Cog~ - 1)
     
    Pub Run(GlobalPointer)|T,State,SubState, PC ,T2, CheckSum, Pass
      'DirA[noparse][[/noparse]16..23]~~
      
      Uart.Start(25,26,%1,115200)   
      LongFill(@Signals,0,6) ' Default All Vals to ZEROS  State:=0
      State:=0
      PC:=0
       { State #    State
          0          Waiting for next Packet
          1          Confirming Packet Header
          2          Reading Packet                                                 
       }
      Repeat
        Repeat
          T:=Uart.rxTime(1000) ' Get Next Byte
          If T==-1
            State:=0
            LongFill(@Signals,0,6) ' Default All Vals to ZEROS  State:=0
            Next
          Case State    
            0:
              Case T
                1 :
                  State:=1
            1:
              Case T
                254:
                  ' We have received the Packet Header Now Set the state for receiving the
                  ' Packet
                  State:=2
                  PC:=0 ' Reset Position Counter
                  CheckSum:=255
                  LongFill(@Signals,0,6) 'Default All Vals 0                                                      
                OTHER: State:=0 ' Abort back to State 0
            2:
              PC++
              If PC<11
                CheckSum ^= T
              Case PC
                1:  Signals.Byte[noparse][[/noparse]0]:=T
                2:  Signals.Byte[noparse][[/noparse]1]:=T
                3:  TachValue.Byte[noparse][[/noparse]0]:=T
                4:  TachValue.Byte[noparse][[/noparse]1]:=T
                5:  Gear:=T
                6:  Speed:=T
                7:  CoolantTemp.Byte[noparse][[/noparse]0]:=T
                8: CoolantTemp.Byte[noparse][[/noparse]1]:=T
                9: BatteryVoltage.Byte[noparse][[/noparse]0]:=T
                10: BatteryVoltage.Byte[noparse][[/noparse]1]:=T
                11:
                  Pass:=(CheckSum==T)
                  State:=0 
                  Quit
        If Pass
          LongMove(GlobalPointer,@Signals,6)
    
                             
    
  • Mike GreenMike Green Posts: 23,101
    edited 2006-09-30 22:48
    inaki,
    Correct me if I'm wrong, but it sounds like you have one bidirectional serial channel to your robot. You can send commands to the robot or you can read sensors from the robot. The servos are addressable, but it's not clear how you read the sensors. Maybe they have addresses too?

    Since you only have one serial channel, you have a single resource that must be shared among the tasks that want to use it. The easiest way to do this is to have a lock (semaphore) that represents the serial channel "serialLock := LOCKNEW". Each task that wants to use it (servo command routine, sensor reading routine, and status display routine) has to wait for the serial channel to be available "REPEAT WHILE LOCKSET(serialLock)". Once the task has control of the serial channel, it can do anything necessary with it. When the task is done with its transaction, it frees the serial channel "LOCKCLR(serialLock)".

    This forces each task to wait until the serial channel is available. You could buffer the transactions by having only one task handle the serial interaction (and it wouldn't need a lock then). This task would have a buffer for each kind of transaction (new servo settings, current sensor values, other status data) that it would handle in a round-robin basis. The actual tasks that compute new servo settings, process sensor values, and display the status information would copy their data to/from local variables, then mark the buffer as full/available for the round-robin task to process on the next cycle. You could even queue up multiple requests for the round-robin routine if necessary. It depends on the complexity and time required for the processing of the data. A single buffer is simpler and allows you to overlap the processing with the I/O transfer. Multiple buffers are useful if you need to "smooth" out an unpredictable processing time.
Sign In or Register to comment.