Shop OBEX P1 Docs P2 Docs Learn Events
Ho to reuse FullDuplexSerial from multiple COGs? [RESOLVED - use cserial] — Parallax Forums

Ho to reuse FullDuplexSerial from multiple COGs? [RESOLVED - use cserial]

Andrey DemenevAndrey Demenev Posts: 377
edited 2010-05-05 01:32 in Propeller 1
I have 2 cogs running SPIN code, and need to write data to serial port from each. I have tried, the following, without success:

debug.spin

VAR
    LONG gLock

OBJ
    fd : "FullDuplexSerial"

PUB init
    gLock := lockNew
    fd.start(31, 30, 0, 115200)

PUB str(s)
    repeat until not lockSet(gLock)
    result := fd.str(s)
    lockClr(gLock)

PUB tx(b)
    repeat until not lockSet(gLock)
    result := fd.tx(b)
    lockClr(gLock)

PUB dec(b)
    repeat until not lockSet(gLock)
    result := fd.dec(b)
    lockClr(gLock)

PUB hex(b, n)
    repeat until not lockSet(gLock)
    result := fd.hex(b,n)
    lockClr(gLock)




main.spin:
CON
    _CLKMODE = XTAL1 + PLL8X
    _CLKFREQ = 96_000_000

OBJ
    debug: "debug"
    another: "another"

PUB main
    debug.init
    another.start
    repeat
        debug.str(string("MAIN", $0D))
        WAITCNT(CLKFREQ + CNT)







OBJ
    debug: "debug"

var 
    LONG stack[noparse][[/noparse]32]

PUB start
    CogNew(main, @stack)

PUB main
    repeat
        debug.str(string("ANOTHER", $0D))
        WAITCNT(CLKFREQ + CNT)






I receive "MAIN" twice, then nothing.

What is the correct way of doing this?

Post Edited (Andrey Demenev) : 5/5/2010 1:49:55 AM GMT

Comments

  • pullmollpullmoll Posts: 817
    edited 2010-05-04 07:35
    You are starting the debug object twice, which doesn't work, because two cogs will be writing to the same pins. Only because you have a 1 second delay and 2 cogs running asynchronously you get the "MAIN" twice.

    What you would have to do is to write an object that can stuff data to the tx buffer of the (once) running fd object. Therefore you need to know the fd object's tx_head, tx_tail and tx_buffer pointers. You would then do the same as the fd.tx itself does: check if long[noparse]/noparse]tx_head_ptr]+1 == long[noparse][[/noparse]tx_tail], and wait if they are equal. Otherwise write byte[noparse][[/noparse]tx_buffer][noparse][[/noparse]long[noparse][[/noparse]tx_head := data and add 1 to the head with wrapping at the buffer size: long[noparse][[/noparse]tx_head_ptr] := (long[noparse][[/noparse]tx_head_ptr] + 1) & 15
    In code - add this to FullDuplexSerial.spin
    
    PUB get_tx_head
      return @tx_head
    
    PUB get_tx_tail
      return @tx_tail
    
    PUB get_tx_buffer
      return @tx_buffer
    
    



    and in your debug.init code write:
    
    PUB init(head, tail, buffer)
       tx_head_ptr := head
       tx_tail_ptr := tail
       tx_buffer_ptr := buffer
    
    PUB chr(ch)
    '' Print a character by stuffing it to the tx buffer of a running FullDuplexSerial object
       repeat while ((long[noparse][[/noparse]tx_head_ptr] + 1) & 15) == long[noparse][[/noparse]tx_tail_ptr]
       byte[noparse][[/noparse]tx_buffer_ptr][noparse][[/noparse]long[noparse][[/noparse]tx_head_ptr]] := ch
       long[noparse][[/noparse]tx_head_ptr] := (long[noparse][[/noparse]tx_head_ptr] + 1) & 15
    
    PUB str(strptr) | index
    '' Print a NUL terminated string
       repeat index from 0 to strsize(strptr)
          chr(byte[noparse][[/noparse]strptr][noparse][[/noparse]index])
    
    PUB dec(value) | _i
    '' Print a decimal number
        result := 0
        if value < 0
            chr("-")
            if (value == NEGX)
                chr("2")
                value += 2_000_000_000
            -value
        _i := 1_000_000_000
        repeat 10
            if value => _i
                chr(value / _i + "0")
                value //= _i
                result~~
            elseif result or _i == 1
                chr("0")
            _i /= 10
    
    PUB hex(value, digits)
    '' Print a hexadecimal number
    
        value <<= (8 - digits) << 2
        repeat digits
            chr(lookupz((value <-= 4) & $F : "0".."9", "A".."F"))
    
    
    DAT
    tx_head_ptr   long 0
    tx_tail_ptr   long 0
    tx_buffer_ptr  long 0
    
    



    The other methods of debug should then use chr(ch) to send bytes to the fd object.
    From main you call fd.init() once and then debug.init(fd.get_tx_head, fd.get_tx_tail, fd.get_tx_buffer) to setup the pointers.

    Every object that wants to use debug would then have to be passed the 3 pointers as well. You could set up an array of 3 longs and put the 3 pointers in there, then you'd have to pass just the address of that array to your objects, which would then call debug.init() with the 3 values from the array.

    Locking is not strictly necessary, but if you want to add it, you would pass the lock handle as well and try to acquire the lock at the start of each function in debug.spin, then release it at the end of the function.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Pullmoll's Propeller Projects

    Post Edited (pullmoll) : 5/4/2010 8:05:02 AM GMT
  • Dave HeinDave Hein Posts: 6,347
    edited 2010-05-04 13:54
    The cserial.spin object in CLib can handle multiple cogs.· You call it the same way you would call the FullDuplexSerial methods, except you set bit 4 in the mode flag to make it·cog-safe.· You would call the start·function as follows:

    · fd.start(31, 30, %10000, 115200)

    The·start method·should only be called once, normally from cog 0 in the top object.· Check out the test program in CLib.· I have several cogs waiting on the same flag, and then they all print at the same time.

    You can download CLib from the OBEX at http://obex.parallax.com/objects/594/·.

    Dave
  • Dave HeinDave Hein Posts: 6,347
    edited 2010-05-04 15:17
    Just to make it clear your source files would be as follows:

    main.spin
    CON
        _CLKMODE = XTAL1 + PLL8X
        _CLKFREQ = 96_000_000
    OBJ
        debug: "cserial"
        another: "another"
    PUB main
        debug.start(31, 30, %10000, 115200)
        another.start
        repeat
            debug.str(string("MAIN", $0D))
            WAITCNT(CLKFREQ + CNT)
    
    

    another.spin
    OBJ
        debug: "cserial"
    var 
        LONG stack[noparse][[/noparse]32]
    PUB start
        CogNew(main, @stack)
    PUB main
        repeat
            debug.str(string("ANOTHER", $0D))
            WAITCNT(CLKFREQ + CNT)
    
    

    I have also attached cserial.spin.

    Dave
  • Andrey DemenevAndrey Demenev Posts: 377
    edited 2010-05-05 01:32
    Dave, tanks a lot! this works just great!
Sign In or Register to comment.