Structure of @rx_head in FullDuplexSerialPlus
ke4pjw
Posts: 1,257
I need to receive data with the prop via serial => 512kbps and find that spin appears to top out at about 115.2kbps. I want to rewrite my code in PASM, but understanding FullDuplexSerialPlus has me scratching my head a bit. It looks like all of the intercog communication happens through @rx_head. (But I could be way off here)
Does anyone know the structure of @rx_head in FullDuplexSerialPlus? Or maybe point me to a tutorial on FullDuplexSerialPlus that will explain it to me like I was a 4year old [noparse];)[/noparse]
Thanks in advance.
--Terry
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
-- Terry
Does anyone know the structure of @rx_head in FullDuplexSerialPlus? Or maybe point me to a tutorial on FullDuplexSerialPlus that will explain it to me like I was a 4year old [noparse];)[/noparse]
Thanks in advance.
--Terry
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
-- Terry

Comments
There are head and tail pointers into the buffer which is 16 bytes long.
The system works like this. Both the head and tail pointer start off at zero equal to each other. When a byte comes in off the serial line the byte is put into the serial buffer like this "buffer[noparse][[/noparse]headIndex] := byteOffSerialLine" Then the head pointer (which is actual and index in the serial buffer - it goes from 0 to 15) is incremented and then anded wtih $F to make sure it nevers gets above 15.
When the spin code then wants to get a byte from the serial buffer it grabs the byte pointed to by the tail index in the serial buffer and then increments the tail pointer by 1 and ANDs it with $F.
So, by doing this you have a First In First Out (FIFO) buffer in which the head and tail pointer tell you where valid data is and isn't.
The amount of stuff in the FIFO buffer is equal to ((head - tail) & $F). So this means the buffer can hold 15 bytes or space at maximum and when the head and tail pointer are equal to each other at any point the buffer is empty.
I hope this helps. "Google circular FIFO buffer otherwise"
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Nyamekye,
ser.rxfill("A", 10) repeat j from 0 to 9 i := ser.rx pdata[noparse][[/noparse]j] := iThis loop took·about 80 usec per byte, which is 125 kbps.· It would have been slightly faster if I used pdata[noparse][[/noparse]j] := i instead of doing this in two lines.· However, it wouldn't have achieved 512 kbps.· There is a significant amount of overhead in calling ser.rx.· You might be able to achieve 512 kbps if you create a block read function in FDS+ as follows:
PUB rxblock(ptr, num) result := (rx_head - rx_tail) & $f if num < result result := num ifnot result return repeat result byte[noparse][[/noparse]ptr++] := rx_buffer[noparse][[/noparse]rx_tail] rx_tail := (rx_tail + 1) & $FThis method will copy up to "num" bytes from the RX serial buffer to the buffer pointed to by "ptr".· It will return the number of bytes transferred.· If I get a chance I'll run a timing test on this to see how fast it is.
Dave
·
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
-- Terry
Dave
PUB rxblock(ptr, num) | num1, num2 if rx_head => rx_tail num1 := rx_head - rx_tail num2 := 0 else num1 := 128 - rx_tail num2 := rx_head if num1 > num num1 := num num2 := 0 elseif num1 + num2 > num num2 := num - num1 bytemove(ptr, rx_buffer + rx_tail, num1) bytemove(ptr + num1, rx_buffer, num2) result := num1 + num2 rx_tail := (rx_tail + result) & 127·Edit: I forgot to update rx_tail.· I added the necessary line above.
Post Edited (Dave Hein) : 6/19/2010 11:20:30 PM GMT
Dave
PUB rxblock(ptr, num) | num1, num2, rxhead rxhead := rx_head if rxhead => rx_tail num1 := rxhead - rx_tail num2 := 0 else num1 := 128 - rx_tail num2 := rxhead if num1 > num num1 := num num2 := 0 elseif num1 + num2 > num num2 := num - num1 bytemove(ptr, rx_buffer + rx_tail, num1) bytemove(ptr + num1, rx_buffer, num2) result := num1 + num2 rx_tail := (rx_tail + result) & 127·
I have now figured out how and why the pointer that is passed off to the cog running the UART interfaces with the locations in hub memory. I have written some PASM to pull a byte from the buffer and compare it with the ASCII value of the capitol letter "D". It runs in a separate cog from the UART, though the pointer to rx_head is passed to this code.
The code works 100% up to 250kbps. Does not decode at 460.8kbps or 921.6kbps. It will decode properly about 10% of the time at 1Mbps. Since I am only sending one character at a time, by hand, I do not believe this to be a buffer over run issue. I suspect that either I have a hardware issue (RF needs to be decoupled or standing waves on the transmission line) or I am running against the limits of a cog's processing power that is running FullDuplexSerialPlus. I am thinking of removing the ping-pong multitasking and separating the UART into two cogs. One for RX and one for TX. I do have some doubt if this is a software issue, as Dave was able to reliably receive data at 1Mbps.
I am not sure what direction to head to next. Hardware or software.
Thanks guys!
--Terry
' My serial rx test harness org rxentry mov t1,par 'get structure address add t1,#4 << 2 'skip past heads and tails rdlong t2,t1 'get rx_pin mov rxmask,#1 shl rxmask,t2 add t1,#4 'get tx_pin rdlong t2,t1 mov txmask,#1 shl txmask,t2 add t1,#4 'get rxtx_mode rdlong rxtxmode,t1 add t1,#4 'get bit_ticks rdlong bitticks,t1 add t1,#4 'get buffer_ptr rdlong rxbuff,t1 mov txbuff,rxbuff add txbuff,#16 test rxtxmode,#%100 wz 'init tx pin according to mode test rxtxmode,#%010 wc if_z_ne_c or outa,txmask if_z or dira,txmask mov PinsOut,#$0000 'Set PinsOut variable so that pins 0 - 15 are low or PinsOut,Pin15 'Set bitmask for Pin15 mov dira,PinsOut 'Set direction of Output pins :loop call #getabyte ' Go get a byte cmp rxdata,#68 wz ' Compare received byte with ASCII "D" if_z or PinsOut, Pin15 ' Prepare to turn on LED if compare was equal if_nz mov PinsOut,#$0000 ' Prepare to turn off LED if compare was not equal mov outa, PinsOut ' Turn LED on or off jmp #:loop ' Do it *all* *over* *again*! :) 'check for head <> tail getabyte mov t1,par ' Get address of rx_head rdlong t2,t1 ' Assign the value of rx_head to t2 add t1,#1 << 2 ' Move address up 4 bytes to get address of rx_tail rdlong t3,t1 ' Assign the value of rx_tail to t3 cmp t2,t3 wz ' Compare values of rx_heads and rx_tails if_z jmp #getabyte ' Jump to getabyte is result of compare was equal 'get byte and inc tail add t3,rxbuff ' Increment the value of rx_tails by the address of rxbuff rdbyte rxdata,t3 ' Assign the value at the buffer tail to rxdata sub t3,rxbuff ' Decrement t3 by the value of the address of rxbuff. Result is rx_tail add t3,#1 ' Increment rx_tail by 1 and t3,#$0F ' Perform AND operation on rx_tail with $0F (if > %1111 then rollover) wrlong t3,t1 ' Update value of rx_tail in hub memory getabyte_ret ret ' Uninitialized data ' Pin15 LONG 0-0 'Pointer to variable in Spin code PinsOut res 1 'Pin bitmask t1 res 1 t2 res 1 t3 res 1 rxtxmode res 1 bitticks res 1 rxmask res 1 rxbuff res 1 rxdata res 1 rxbits res 1 rxcnt res 1 rxcode res 1 txmask res 1 txbuff res 1 txdata res 1 txbits res 1 txcnt res 1 txcode res 1▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
-- Terry
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
-- Terry