ser.rxtime Discovery
T Chap
Posts: 4,223
I like to read data by setting the first read as an .rx so the loop just sits there till something arrives. Then any reads after that are rxtime. In the past I have rarely used speeds of 115200, but needed to on this project. After a number of hours I finally figured out the problem of why rx would would but rxtime would not on the same data stream. Even at 57600, the rxtime was taking too much time doing it's math.
repeat until (rxbyte := rxcheck) => 0 or (cnt - t) / (clkfreq / 1000) > ms
So I tried a different method shown below that still allows the rx to time out, but it works perfectly so far.
repeat until (rxbyte := rxcheck) => 0 or (cnt - t) / (clkfreq / 1000) > ms
So I tried a different method shown below that still allows the rx to time out, but it works perfectly so far.
Repeat ser.rxflush ms := 1 i :=0 ' Start loop here for Data in SerialReadBuffer[i++] := ser.rx ' waits here for first PACKET HEADER byte (1F) from USB SerialReadBuffer[i++] := ser.rxtime(ms) ' waits here for second byte OPCODE SerialReadBuffer[i++] := ser.rxtime(ms) ' waits here for second byte LENGTH Repeat 199 'SerialReadBuffer[2] + 10 SerialReadBuffer[i++] := ser.rxtime(ms)
PUB rxtime(ms) : rxbyte | t '' Wait ms milliseconds for a byte to be received '' returns -1 if no byte received, $00..$FF if byte ' added these next 5 repeat while (rxbyte := rxcheck) < 0 rxtimeout++ if rxtimeout++ > 10000 'prevent getting stuck in a rx rxtimeout~ return -1 't := cnt 'repeat until (rxbyte := rxcheck) => 0 or (cnt - t) / (clkfreq / 1000) > ms ' original
Comments
Right now I have code with .rxtime(ms) instead of .rx, but I am using "PBnJ_serial" library.
Tested with short data packets (20 bytes) ad 115_200. No problems.
Current FIFO buffer length 32 bytes.
Tomorrow I will test with 400- 24_000 byte packets.
In the new method ms does nothing. The main idea is that you send data and it cannot lock up ever. It is not required to specify the length of data as long as you have enough repeats to capture the max data stream. If the data is less it doesn't matter
One possibility is that your incoming data at 115k is overrunning the serial data buffer. The Spin code is slow and isn't removing characters from the serial data buffer as fast as they appear there. The solution to that is to either increase the size of the buffer, or (as you have done) increase the speed of de-buffering the data.
Note that computations within a repeat loop are recalculated every time around the loop, and this applies to the costly division of clkfreq/1000. That could be precomputed and taken out of the loop. pre-compute clk1000 := clkfreq/1000, then That takes the the division out of the repeat loop, but still a long expression with a multiply to evaluate before returning a value. The following is more like your approach, so it can respond quickly if a character is already in the buffer.
I'm uncomfortable with your approach in that its timeout is not based on clkfreq. Just a number of spin loops, good enough for escape but hard to figure the definite time allowed.
Below is the actual code. This allows any length of data to be sent and can never hang up.
As a bug this bit me in a situation using RS485 (or SPI), where occasionally and unpredictably the device on the other end did not echo, and that caused the Prop to lock up waiting for an Rx that never came. There'd be other workarounds, but NOECHO is the most convenient way to separate commands from returned data.