Shop OBEX P1 Docs P2 Docs Learn Events
Single Cog 1 Mbaud full-duplex serial — Parallax Forums

Single Cog 1 Mbaud full-duplex serial

DelusDelus Posts: 79
edited 2017-06-07 18:40 in Propeller 1
I just finished a 1Mbaud UART object for a project I'm working on right now. I realize this isn't the fastest anyone has managed on the prop, but my quick search before starting didn't show any single cog 1 Mbaud+ objects that could receive and transmit simultaneously. This code uses 2x oversampling on the receiver thread using a counter to determine which sampling window to use on each start bit and takes 9.5 bit periods to complete a read to accommodate slight clock mismatches when receiving continuous data.

My application reads each byte in real time so there aren't any receive or transmit buffers implemented but there are some instructions left in the tx code should someone wish to implement buffer logic (all hub r/w occur in tx thread to maintain hub sync). And the Rx and Tx hub registers are simple enough that many Rx and Tx buffers could be implemented in a second cog.

I hope someone finds this useful, or if it has already been done better I'd love a link (though I'll kick myself for missing it).

Cheers,
David

Edit: I should probably note that the spin tx and rx methods are there for testing life-signs and may not be able to keep up with a full speed connection.

Code has been posted on the object exchange:1Mbaud FullDuplexSerial
con
  RX_RDY        = $40_00_00_00
  TX_RTS        = $80_00_00_00

var
  long  RxReg
  long  TxReg

pub start(rxpin, txpin)
  pinRx := (1 << rxpin)
  pinTx := (1 << txpin)
  pRxReg := @RxReg
  pTxReg := @TxReg
  rxCtrPin := rxpin
  tx_ror := (31 - txpin) + 1
  if (tx_ror == 32)
    tx_ror := 0

  TxReg := 0
  cognew(@asm_start, 0)
  'wait for cog startup     
  repeat while ((TxReg & TX_RTS) == 0)

pub tx(value)
  repeat while ((TxReg & TX_RTS) == 0)
  TxReg := value & $ff 

pub rx | value
  repeat while ((RxReg & RX_RDY) == 0)
  value := RxReg & $ff
  RxReg := 0
  return value

pub RxRegAddr
  return @RxReg

pub TxRegAddr
  return @TxReg 

dat
asm_start
org
              'flag cog started
              wrlong    tx_flagRTS, pTxReg
              'configure tx
              mov       dira, pinTx
              mov       outa, high
              'tx starts on bit 7 (currently set high by outa = high) this is where new data is read
              mov       txcode, #tx_bit_7
              mov       rxcode, #rx_wait_1
              'configure rx
              andn      dira, pinRx  
              mov       frqa, #1
              mov       ctra, rxCtrMode
              movs      ctra, rxCtrPin  
              mov       phsa, #0   
              mov       frqa, #1
              mov       rx_dataReg, #0
              'Hold Tx line high for one byte time before starting
              mov       tmp, cnt
              add       tmp, byteTime
              waitcnt   tmp, byteTime
              'jumb to execution code
              jmp       txcode
       
{-------------------------------------------------------------------------------------
*********************************  RX Section  ***************************************
-------------------------------------------------------------------------------------}




'note if rxcode is not updated this becomes a loop
rx_wait_1
              'inst 1/5
              and       pinRx, ina              nr, wz  
              'inst 2/5
              mov       phsa, #0
              'inst 3/5                 
        if_nz mov       rxcode, #rx_wait_0                                      
              'inst 4/5   
              nop                                   
              'inst 5/5
              jmp       txcode   
'note if rxcode is not updated this becomes a loop
rx_wait_0
              'inst 1/5
              mov       tmp, phsa
              'inst 2/5                  
              mov       phsa, #0                         
              'inst 3/5
              'test how long it's been sinse the last falling edge
              ' and decide wheter to use this sampling interval or
              ' the next (2x over-sampling)            
              cmp       tmp, #22               wc, wz                 
              'inst 4/5
        if_ae mov       rxcode, #rx_read_bit_start  
              'inst 5/5
              jmp       txcode    
rx_read_bit_start   
              'inst 1/5
              mov       rx_bitcount, #8
              'inst 2/5
              mov       rx_bit, #1
              'inst 3/5
              mov       rx_data, #0
              'inst 4/5
              nop
              'inst 5/5
              jmpret    rxcode, txcode 
'read rx bit 
rx_read_bit            
              'inst 1/5
              and       pinRx, ina              nr, wz
              'inst 2/5
              muxnz     rx_data, rx_bit
              'inst 3/5
              shl       rx_bit, #1
              'inst 4/5
              sub       rx_bitcount, #1
              'inst 5/5
              jmpret    rxcode, txcode
rx_mid_bit            
              'inst 1/5
              cmp       rx_bitcount, #0         wc, wz
              'inst 2/5
        if_e  mov       rxcode, #rx_check_frame
              'inst 3/5
        if_ne mov       rxcode, #rx_read_bit
              'inst 4/5
              or        rx_data, rx_flagRdy
              'inst 5/5
              jmp       txcode
rx_check_frame  
              'inst 1/5
              and       pinRx, ina              nr, wz       
              'inst 2/5
              'reset low time counter
              mov       phsa, #0
              'inst 3/5
              'successfull read, write data to reg for write to hub (handled by tx code)
        if_nz mov       rx_dataReg, rx_data
              'inst 4/5
              mov       rxcode, #rx_wait_0
              'inst 5/5
              jmp       txcode



{-------------------------------------------------------------------------------------
*********************************  TX Section  ***************************************
-------------------------------------------------------------------------------------}

              

tx_bit_start                          
              'inst 1/5 'hub sync
              nop
              'inst 2/5
              nop
              'inst 3/5
              mov       outa, tx_dataReg
              'inst 4/5
              nop
              'inst 5/5
              jmpret    txcode, rxcode
tx_idle_start
              'inst 1/5
              and       rx_dataReg, rx_flagRDY  nr, wz
              'inst 2/5
        if_z  mov       txcode, #tx_bit_0_norm
              'inst 3/5 'hub sync
        if_nz mov       txcode, #tx_bit_0_rx2hub
              'inst 4/5
              nop
              'inst 5/5
              jmp       rxcode   
tx_bit_0_norm
              'inst 1/5 'hub sync
              mov       txcode, #tx_idle_0
              'inst 2/5
              nop
              'inst 3/5
              ror       outa, #1
              'inst 4/5
              nop
              'inst 5/5                
              jmp       rxcode 
tx_bit_0_rx2hub
              'inst 1-2/5 'hub sync
              wrlong    rx_dataReg, pRxReg
              'inst 3/5
              ror       outa, #1
              'inst 4/5
              mov       rx_dataReg, #0
              'inst 5/5
              jmpret    txcode, rxcode
tx_idle_0
              'inst 1/5
              nop
              'inst 2/5
              nop
              'inst 3/5 'hub sync
              nop
              'inst 4/5
              nop
              'inst 5/5
              jmpret    txcode, rxcode
tx_bit_1
              'inst 1/5 'hub sync
              nop
              'inst 2/5
              nop
              'inst 3/5    
              ror       outa, #1
              'inst 4/5
              nop
              'inst 5/5
              jmpret    txcode, rxcode
tx_idle_1
              'inst 1/5
              nop
              'inst 2/5
              nop
              'inst 3/5 'hub sync
              nop
              'inst 4/5
              nop
              'inst 5/5
              jmpret    txcode, rxcode 
tx_bit_2
              'inst 1/5 'hub sync
              nop
              'inst 2/5
              nop
              'inst 3/5     
              ror       outa, #1
              'inst 4/5
              nop
              'inst 5/5
              jmpret    txcode, rxcode
tx_idle_2
              'inst 1/5
              nop
              'inst 2/5
              nop
              'inst 3/5 'hub sync
              nop
              'inst 4/5
              nop
              'inst 5/5
              jmpret    txcode, rxcode 
tx_bit_3
              'inst 1/5 'hub sync
              nop
              'inst 2/5
              nop
              'inst 3/5     
              ror       outa, #1
              'inst 4/5
              nop
              'inst 5/5
              jmpret    txcode, rxcode
tx_idle_3
              'inst 1/5
              nop
              'inst 2/5
              nop
              'inst 3/5 'hub sync
              nop
              'inst 4/5
              nop
              'inst 5/5
              jmpret    txcode, rxcode                  
tx_bit_4
              'inst 1/5 'hub sync
              nop
              'inst 2/5
              nop
              'inst 3/5     
              ror       outa, #1
              'inst 4/5
              nop
              'inst 5/5
              jmpret    txcode, rxcode
tx_idle_4                             
              'inst 1/5
              and       rx_dataReg, rx_flagRDY  nr, wz
              'inst 2/5
        if_z  mov       txcode, #tx_bit_5_norm
              'inst 3/5 'hub sync
        if_nz mov       txcode, #tx_bit_5_rx2hub
              'inst 4/5
              nop
              'inst 5/5
              jmp       rxcode         
tx_bit_5_norm                       
              'inst 1/5 'hub sync
              mov       txcode, #tx_idle_5
              'inst 2/5
              nop
              'inst 3/5
              ror       outa, #1
              'inst 4/5
              nop
              'inst 5/5                
              jmp       rxcode 
tx_bit_5_rx2hub                      
              'inst 1-2/5 'hub sync
              wrlong    rx_dataReg, pRxReg
              'inst 3/5
              ror       outa, #1
              'inst 4/5
              mov       rx_dataReg, #0
              'inst 5/5
              jmpret    txcode, rxcode
tx_idle_5
              'inst 1/5
              nop
              'inst 2/5
              nop
              'inst 3/5 'hub sync
              nop
              'inst 4/5
              nop
              'inst 5/5
              jmpret    txcode, rxcode  
tx_bit_6
              'inst 1/5 'hub sync
              nop
              'inst 2/5
              nop
              'inst 3/5   
              ror       outa, #1
              'inst 4/5
              nop
              'inst 5/5
              jmpret    txcode, rxcode
tx_idle_6
              'inst 1/5
              nop
              'inst 2/5
              nop
              'inst 3/5 'hub sync
              nop
              'inst 4/5
              nop
              'inst 5/5
              jmpret    txcode, rxcode 
tx_bit_7
              'inst 1-2/5 'hub sync
              rdlong    tx_dataReg, pTxReg
              'inst 3/5   
              ror       outa, #1
              'inst 4/5
              nop
              'inst 5/5
              jmpret    txcode, rxcode
tx_idle_7
              'inst 1/5
              and       tx_dataReg, tx_flagRTS  nr, wz
              'inst 2/5
        if_nz mov       txcode, #tx_bit_stop_idle
              'inst 3/5 'hub sync   
        if_z  mov       txcode, #tx_bit_stop_tx
              'inst 4/5
              nop
              'inst 5/5
              jmp       rxcode 
tx_bit_stop_idle
              'inst 1/5 'hub sync  
              mov       tx_dataReg, high
              'inst 2/5
              nop
              'inst 3/5
              mov       outa, high
              'inst 4/5
              nop
              'inst 5/5
              jmpret    txcode, rxcode
tx_idle_stop_idle
              'inst 1/5              
              mov       txcode, #tx_bit_start  
              'inst 2/5
              nop
              'inst 3/5 'hub sync
              nop
              'inst 4/5  
              nop                      
              'inst 5/5
              jmp       rxcode  
tx_bit_stop_tx
              'inst 1/5 'hub sync
              'set stop bit of tx data
              shl       tx_dataReg, #1
              'inst 2/5
              'shift data to proper position in outs
              ror       tx_dataReg, tx_ror
              'inst 3/5
              mov       outa, high
              'inst 4/5
              nop
              'inst 5/5
              jmpret    txcode, rxcode
tx_idle_stop_tx
              'inst 1/5      
              mov       txcode, #tx_bit_start   
              'inst 2/5
              nop
              'inst 3-4/5 'hub sync
              'flag data read and ready for next data in hub
              wrlong    tx_flagRTS, pTxReg                          
              'inst 5/5
              jmp       rxcode 
              

pinRx         long      0
pRxReg        long      0    
rx_flagRDY    long      RX_RDY
rxCtrPin      long      0
rxCtrMode     long      %0_10101_000_00000000_000000_000_000000 'Inc on pina == 0

pinTx         long      0
pTxReg        long      0
tx_flagRTS    long      TX_RTS
tx_ror        long      0  

high          long      $ff_ff_ff_ff
byteTime      long      800          

rxcode        res       1
rx_data       res       1
rx_dataReg    res       1
rx_bitcount   res       1
rx_bit        res       1

txcode        res       1
tx_dataReg    res       1

tmp           res       1
fit

Comments

  • Thanks for posting that. Interesting co-routine tricks! Your application must be pretty specialized, is it, with control of both ends of the comms?

    While a substantially different implementation, did you see the one by Lonesock (Jonathan Drummer)?
    fast-full-duplex-serial-1-cog-a-k-a-ffds1
    Like yours, it makes use of the cog counters, one to time the tx bits and the other to time the rx sampling. The speed claim is "only" 460800 baud, but it does also claim buffer management and the usual choice of baud rates etc.

  • I control the PCB level hardware at each end (propeller - arm and propeller - ftdi) and I suppose it is pretty specialized :). Thanks for the link, I did stumble across that one in my searching and found that it wasn't quite fast enough to handle all my ADC data + device commands.
  • DelusDelus Posts: 79
    edited 2017-06-06 21:30
    And now with a receive buffer!.. ran into some issues debugging short bursts of data in spin so I opted to implement a receive buffer in the tx nops.

    Edit: Forgot to remove some debug lines (now removed)
    con
      RX_RDY        = $40_00_00_00
      TX_RTS        = $80_00_00_00
      RxBufferSize  = 64
    
    var             
      long  TxReg
      byte  RxBuffer[RxBufferSize]
      long  RxReadPos
      long  RxWritePos
    
    pub start(rxpin, txpin)
      pinRx := (1 << rxpin)
      pinTx := (1 << txpin)  
      pRxWriteStart := @RxBuffer
      'exclusive end pointer
      pRxWriteEnd := @RxBuffer +  RxBufferSize
      pRxWritePos := @RxWritePos
      pTxReg := @TxReg
      rxCtrPin := rxpin
      tx_ror := (31 - txpin) + 1
      if (tx_ror == 32)
        tx_ror := 0
    
      TxReg := 0
      cognew(@asm_start, 0)
      'wait for cog startup     
      repeat while ((TxReg & TX_RTS) == 0)
    
    pub tx(value)
      repeat while ((TxReg & TX_RTS) == 0)
      TxReg := value & $ff 
    
    pub rx | value   
      repeat while RxReadPos == RxWritePos
      value := RxBuffer[RxReadPos++]
      if (rxReadPos == RxBufferSize)
        rxReadPos := 0           
      return value              
    
    pub RxBufAddr
      return @RxBuffer
    
    pub RxBufEndAddr
      return @RxBuffer + RxBufferSize
                           
    pub RxBufWritePosAddr
      return @RxWritePos
      
    pub RxBufReadPosAddr
      return @RxReadPos
    
    pub TxRegAddr
      return @TxReg 
    
    dat
    asm_start
    org
                  'flag cog started
                  wrlong    tx_flagRTS, pTxReg
                  'configure tx
                  mov       dira, pinTx
                  mov       outa, high
                  'tx starts on bit 7 (currently set high by outa = high) this is where new data is read
                  mov       txcode, #tx_bit_7
                  mov       rxcode, #rx_wait_1
                  'configure rx
                  andn      dira, pinRx  
                  mov       frqa, #1
                  mov       ctra, rxCtrMode
                  movs      ctra, rxCtrPin  
                  mov       phsa, #0   
                  mov       frqa, #1
                  mov       rx_dataReg, #0
                  mov       pRxWrite, pRxWriteStart
                  'Hold Tx line high for one byte time before starting
                  mov       tmp, cnt
                  add       tmp, byteTime
                  waitcnt   tmp, byteTime
                  'jumb to execution code
                  jmp       txcode
           
    {-------------------------------------------------------------------------------------
    *********************************  RX Section  ***************************************
    -------------------------------------------------------------------------------------}
    
    
    
    
    'note if rxcode is not updated this becomes a loop
    rx_wait_1
                  'inst 1/5
                  and       pinRx, ina              nr, wz  
                  'inst 2/5
                  mov       phsa, #0
                  'inst 3/5                 
            if_nz mov       rxcode, #rx_wait_0                                      
                  'inst 4/5   
                  nop                                   
                  'inst 5/5
                  jmp       txcode   
    'note if rxcode is not updated this becomes a loop
    rx_wait_0
                  'inst 1/5
                  mov       tmp, phsa
                  'inst 2/5                  
                  mov       phsa, #0                         
                  'inst 3/5
                  'test how long it's been sinse the last falling edge
                  ' and decide wheter to use this sampling interval or
                  ' the next (2x over-sampling)            
                  cmp       tmp, #22               wc, wz                 
                  'inst 4/5
            if_ae mov       rxcode, #rx_read_bit_start  
                  'inst 5/5
                  jmp       txcode    
    rx_read_bit_start   
                  'inst 1/5
                  mov       rx_bitcount, #8
                  'inst 2/5
                  mov       rx_bit, #1
                  'inst 3/5
                  mov       rx_data, #0
                  'inst 4/5
                  nop
                  'inst 5/5
                  jmpret    rxcode, txcode 
    'read rx bit 
    rx_read_bit            
                  'inst 1/5
                  and       pinRx, ina              nr, wz
                  'inst 2/5
                  muxnz     rx_data, rx_bit
                  'inst 3/5
                  shl       rx_bit, #1
                  'inst 4/5
                  sub       rx_bitcount, #1
                  'inst 5/5
                  jmpret    rxcode, txcode
    rx_mid_bit            
                  'inst 1/5
                  cmp       rx_bitcount, #0         wc, wz
                  'inst 2/5
            if_e  mov       rxcode, #rx_check_frame
                  'inst 3/5
            if_ne mov       rxcode, #rx_read_bit
                  'inst 4/5
                  or        rx_data, rx_flagRdy
                  'inst 5/5
                  jmp       txcode
    rx_check_frame  
                  'inst 1/5
                  and       pinRx, ina              nr, wz       
                  'inst 2/5
                  'reset low time counter
                  mov       phsa, #0
                  'inst 3/5
                  'successfull read, write data to reg for write to hub (handled by tx code)
            if_nz mov       rx_dataReg, rx_data
                  'inst 4/5
                  mov       rxcode, #rx_wait_0
                  'inst 5/5
                  jmp       txcode
    
    
    
    {-------------------------------------------------------------------------------------
    *********************************  TX Section  ***************************************
    -------------------------------------------------------------------------------------}
    
                  
    
    tx_bit_start                          
                  'inst 1/5 'hub sync
                  nop
                  'inst 2/5
                  nop
                  'inst 3/5
                  mov       outa, tx_dataReg
                  'inst 4/5
                  nop
                  'inst 5/5
                  jmpret    txcode, rxcode
    tx_idle_start
                  'inst 1/5
                  and       rx_dataReg, rx_flagRDY  nr, wz
                  'inst 2/5
            if_z  mov       txcode, #tx_bit_0_norm
                  'inst 3/5 'hub sync
            if_nz mov       txcode, #tx_bit_0_rx2hub
                  'inst 4/5
                  nop
                  'inst 5/5
                  jmp       rxcode   
    tx_bit_0_norm
                  'inst 1/5 'hub sync 
                  nop             
                  'inst 2/5
                  nop
                  'inst 3/5
                  ror       outa, #1
                  'inst 4/5
                  nop
                  'inst 5/5          
                  jmpret    txcode, rxcode    
    tx_idle_0_norm
                  'inst 1/5       
                  mov       txcode, #tx_bit_1
                  'inst 2/5
                  nop
                  'inst 3/5 'hub sync
                  nop
                  'inst 4/5
                  nop
                  'inst 5/5                        
                  jmp       rxcode 
    tx_bit_0_rx2hub
                  'inst 1-2/5 'hub sync  
                  wrbyte    rx_dataReg, pRxWrite
                  'inst 3/5
                  ror       outa, #1
                  'inst 4/5
                  mov       rx_dataReg, #0
                  'inst 5/5
                  jmpret    txcode, rxcode
    tx_idle_0_rx2hub
                  'inst 1/5
                  add       pRxWrite, #1
                  'inst 2/5
                  cmp       pRxWrite, pRxWriteEnd   wc, wz
                  'inst 3/5 'hub sync
            if_e  mov       pRxWrite, pRxWriteStart
                  'inst 4/5
                  nop
                  'inst 5/5
                  jmpret    txcode, rxcode
    tx_bit_1
                  'inst 1/5 'hub sync
                  nop
                  'inst 2/5
                  nop
                  'inst 3/5    
                  ror       outa, #1
                  'inst 4/5
                  nop
                  'inst 5/5
                  jmpret    txcode, rxcode
    tx_idle_1
                  'inst 1/5
                  mov       tmp, pRxWrite
                  'inst 2/5
                  sub       tmp, pRxWriteStart
                  'inst 3-4/5 'hub sync
                  wrlong    tmp, pRxWritePos
                  'inst 5/5
                  jmpret    txcode, rxcode 
    tx_bit_2
                  'inst 1/5 'hub sync
                  nop
                  'inst 2/5
                  nop
                  'inst 3/5     
                  ror       outa, #1
                  'inst 4/5
                  nop
                  'inst 5/5
                  jmpret    txcode, rxcode
    tx_idle_2
                  'inst 1/5
                  nop
                  'inst 2/5
                  nop
                  'inst 3/5 'hub sync
                  nop
                  'inst 4/5
                  nop
                  'inst 5/5
                  jmpret    txcode, rxcode 
    tx_bit_3
                  'inst 1/5 'hub sync
                  nop
                  'inst 2/5
                  nop
                  'inst 3/5     
                  ror       outa, #1
                  'inst 4/5
                  nop
                  'inst 5/5
                  jmpret    txcode, rxcode
    tx_idle_3
                  'inst 1/5
                  nop
                  'inst 2/5
                  nop
                  'inst 3/5 'hub sync
                  nop
                  'inst 4/5
                  nop
                  'inst 5/5
                  jmpret    txcode, rxcode                  
    tx_bit_4
                  'inst 1/5 'hub sync
                  nop
                  'inst 2/5
                  nop
                  'inst 3/5     
                  ror       outa, #1
                  'inst 4/5
                  nop
                  'inst 5/5
                  jmpret    txcode, rxcode
    tx_idle_4                             
                  'inst 1/5
                  and       rx_dataReg, rx_flagRDY  nr, wz
                  'inst 2/5
            if_z  mov       txcode, #tx_bit_5_norm
                  'inst 3/5 'hub sync
            if_nz mov       txcode, #tx_bit_5_rx2hub
                  'inst 4/5
                  nop
                  'inst 5/5
                  jmp       rxcode         
    tx_bit_5_norm                       
                  'inst 1/5 'hub sync  
                  nop               
                  'inst 2/5
                  nop
                  'inst 3/5
                  ror       outa, #1
                  'inst 4/5
                  nop
                  'inst 5/5   
                  jmpret    txcode, rxcode            
    tx_idle_5_norm
                  'inst 1/5     
                  mov       txcode, #tx_bit_6
                  'inst 2/5
                  nop
                  'inst 3/5 'hub sync
                  nop
                  'inst 4/5
                  nop
                  'inst 5/5                       
                  jmp       rxcode        
    tx_bit_5_rx2hub
                  'inst 1-2/5 'hub sync  
                  wrbyte    rx_dataReg, pRxWrite
                  'inst 3/5
                  ror       outa, #1
                  'inst 4/5
                  mov       rx_dataReg, #0
                  'inst 5/5
                  jmpret    txcode, rxcode
    tx_idle_5_rx2hub
                  'inst 1/5
                  add       pRxWrite, #1
                  'inst 2/5
                  cmp       pRxWrite, pRxWriteEnd   wc, wz
                  'inst 3/5 'hub sync
            if_e  mov       pRxWrite, pRxWriteStart
                  'inst 4/5
                  nop
                  'inst 5/5
                  jmpret    txcode, rxcode     
    tx_bit_6
                  'inst 1/5 'hub sync
                  nop
                  'inst 2/5
                  nop
                  'inst 3/5   
                  ror       outa, #1
                  'inst 4/5
                  nop
                  'inst 5/5
                  jmpret    txcode, rxcode
    tx_idle_6
                  'inst 1/5   
                  mov       tmp, pRxWrite
                  'inst 2/5
                  sub       tmp, pRxWriteStart
                  'inst 3-4/5 'hub sync
                  wrlong    tmp, pRxWritePos      
                  'inst 5/5
                  jmpret    txcode, rxcode 
    tx_bit_7
                  'inst 1-2/5 'hub sync
                  rdlong    tx_dataReg, pTxReg
                  'inst 3/5   
                  ror       outa, #1
                  'inst 4/5
                  nop
                  'inst 5/5
                  jmpret    txcode, rxcode
    tx_idle_7
                  'inst 1/5
                  and       tx_dataReg, tx_flagRTS  nr, wz
                  'inst 2/5
            if_nz mov       txcode, #tx_bit_stop_idle
                  'inst 3/5 'hub sync   
            if_z  mov       txcode, #tx_bit_stop_tx
                  'inst 4/5
                  nop
                  'inst 5/5
                  jmp       rxcode 
    tx_bit_stop_idle
                  'inst 1/5 'hub sync  
                  mov       tx_dataReg, high
                  'inst 2/5
                  nop
                  'inst 3/5
                  mov       outa, high
                  'inst 4/5
                  nop
                  'inst 5/5
                  jmpret    txcode, rxcode
    tx_idle_stop_idle
                  'inst 1/5              
                  mov       txcode, #tx_bit_start  
                  'inst 2/5
                  nop
                  'inst 3/5 'hub sync
                  nop
                  'inst 4/5  
                  nop                      
                  'inst 5/5
                  jmp       rxcode  
    tx_bit_stop_tx
                  'inst 1/5 'hub sync
                  'set stop bit of tx data
                  shl       tx_dataReg, #1
                  'inst 2/5
                  'shift data to proper position in outs
                  ror       tx_dataReg, tx_ror
                  'inst 3/5
                  mov       outa, high
                  'inst 4/5
                  nop
                  'inst 5/5
                  jmpret    txcode, rxcode
    tx_idle_stop_tx
                  'inst 1/5      
                  mov       txcode, #tx_bit_start   
                  'inst 2/5
                  nop
                  'inst 3-4/5 'hub sync
                  'flag data read and ready for next data in hub
                  wrlong    tx_flagRTS, pTxReg                          
                  'inst 5/5
                  jmp       rxcode 
                  
    
    pinRx         long      0     
    pRxWriteEnd   long      0
    pRxWriteStart long      0
    pRxWritePos   long      0
    rx_flagRDY    long      RX_RDY
    rxCtrPin      long      0
    rxCtrMode     long      %0_10101_000_00000000_000000_000_000000 'Inc on pina == 0
    
    pinTx         long      0
    pTxReg        long      0
    tx_flagRTS    long      TX_RTS
    tx_ror        long      0  
    
    high          long      $ff_ff_ff_ff
    byteTime      long      800          
    
    rxcode        res       1
    rx_data       res       1
    rx_dataReg    res       1
    rx_bitcount   res       1
    rx_bit        res       1 
    pRxWrite      res       1
    
    txcode        res       1
    tx_dataReg    res       1
    
    tmp           res       1
    fit
    
  • I have my own high-speed UART objects in Tachyon but for general-purpose stuff I have the HSUART "ROMs" which are loaded dynamically at runtime from upper EEPROM into cogs. However the point is that I routinely run these at 1M baud or more (up to 4M) as "auto-duplex" in that they will normally be in receive mode but will transmit when required as it is rare that full-duplex Is ever required since most serial comms are of the command/response type (I talk, you listen, you talk back, I listen). There is another one I use for RS485 or single I/O networking too as well as the high-speed serial console. All these are designed to be jitter free and receive with back-to-back one stop bit characters while buffering into hub RAM (requires well timed data and index writes).

    I find that the jmpret methods that normally are used for standard full-duplex introduce substantial jitter even at low speeds of 115k but how does your timing and jitter look with full-duplex?
  • If I didn't have asynchronous ADC events being sent while normal commands are running I probably would have gone with something like that. I did come across an object that was fast enough but switched between rx and tx which sounds a lot like your object (did you post some of your code on the forms I might have found?). But I can't drop ADC events when I'm sending commands(or vice-versa) on this project.

    As for jitter I was very careful to use either 5-instruction blocks between every context switch or 4-instruction blocks with one aligned hubop. This gives me jitter free transmit however prevents the receive function from aligning properly with the incoming bit stream meaning samples are taken +/- 250 ns from the center of each bit. Still no jitter between samples but this definitely reduces it's immunity to jitter or other noise sources coming from what ever it's connected to.
  • Funny thing is that I'm doing something similar at the moment where I am streaming 10 channels of 12-bit A/D data at high speed across the link. But if I had to sustain a 1Mbit rate and still wanted to handle commands then I would simply run it over a 2Mbit link. These ROMS are embedded in my initial Tachyon Forth code that gets loaded with the Prop tool and then transfered from lower to upper EEPROM once Tachyon source code is first loaded before it tries to backup to EEPROM itself. So essentially this releases 32k hub memory for more code.
  • I will take a look at this! I have never been able to get more than about 400kbits/sec to be received reliably by the prop from a PC using a serial USB UART. This includes writing custom code in PASM to read directly from the ring buffer and disabling the ping-pong task switching for RX and TX.

    I went the lazy route and wrote Full-Duplex Parallel for the FTDI FT245. It takes a lot more pins.

    Good job Delus!
  • Just curious, why did you not use separate cogs for rx and tx and thereby avoid the hassle; short on cogs? The code plots a tortuous path that must have required more than one cup of strong coffee to straighten out!
  • Just curious, why did you not use separate cogs for rx and tx and thereby avoid the hassle; short on cogs? The code plots a tortuous path that must have required more than one cup of strong coffee to straighten out!

    haha, yes that would have been MUCH easier (and I could have used pre-existing code) but I need two 1 Mbaud ports and don't have 4 cogs to spare. The code was actually much easier to write then I expected, I started by calculating hub timings and figuring out how many tx sections it would take to transmit a single byte (start, 8-bits, stop). After that I made the framework with half-bit tx dummy sections(with hub timings commented) and started replacing nops with actual code. The rx section took a little bit of mental gymnastics but as long as I kept each section to 5 instructions including the context switch and didn't use any hub-ops there I knew I'd be fine. (It also helps that each can be debugged independently by substituting dummy sections for the alternate task)

    ke4pjw - Thanks, I haven't had any issues receiving data yet but I did realize that one of my timing calculations was off yesterday reducing my error margins a bit(rx_wait_0 should compare phsa(tmp) to 16 instead of 22). I have noticed that if I start the PC connection in the middle of a continuous data stream I get much more garbled data (uart frame miss alignment) than I expected but this seems to be an ftdi/pc issue as it goes away after the first break in data transmission allows the ftdi to get a lock on frame alignment.

  • DelusDelus Posts: 79
    edited 2017-06-07 16:06
    Funny thing is that I'm doing something similar at the moment where I am streaming 10 channels of 12-bit A/D data at high speed across the link. But if I had to sustain a 1Mbit rate and still wanted to handle commands then I would simply run it over a 2Mbit link. These ROMS are embedded in my initial Tachyon Forth code that gets loaded with the Prop tool and then transfered from lower to upper EEPROM once Tachyon source code is first loaded before it tries to backup to EEPROM itself. So essentially this releases 32k hub memory for more code.

    That looks like it might be a slightly more sane approach. My biggest problem is that I don't have control over when the ARM transmits adc data or when there will be a break to send it a command, and the pc app expects the same data flow from the prop as it does when connected directly to the ARM. Admittedly my high speed data requirements are semi self-inflicted as each adc reading gets its own 32-bit timestamp and 16-bit command id which transmits 4x the data of the original 16-bit signal and I do have the power to change this on all 3 systems. This + the 10 bit encoding of uart + 4 adc channels + 2.44 ksps gives me a minimum baud rate of 780.8 kbuad for just the adc data.

Sign In or Register to comment.