Hi Jonathan, here are a couple of preliminary scans. Each was taken with the transmitter only, repeatedly sending an ascii null at 57600. Not much of a test, I know. But the first is using 10MHz with the crystal, to compare with the second, RCfast. In this I made no setBaud adjustment for the actual RCfast frequency. The sigma isn't bad, though, just 0.015, but your algorithm timing is great, because the crystal came in with sigma identically zero.
The real test comes from banging on it on the receive side. Any particular test you want?
By the way, I found that it locks up if the receive pin sees a BREAK condition or if the pin is floating when the object is initialized.
No specific tests in mind (though some testing at 460_800 would be nice), I just want to squish any bugs before a formal release. Thanks for the heads up on the break condition...I will try to track that down tomorrow for yet another release.
It should be possible to use the video generator to transmit a byte, this would make a very precise bit timing with no jitters.
And you get more processing time for the receive task in the same cog.
Andy
You don't need the video generator, just the counter. You put your bit pattern in the counter high bits, then every N clock cycles you simply shl the counter and it appears on the designated pin. You can queue up to 3 bytes this way. In fact, this would be the way to redesign FDS to have enough cycles in the read loop to get very accurate timing all around.
EDIT: Zombie thread!
Another idea, use the other counter in free run capture mode. If you are time slicing the receiver and the transmitter, you look at phsX value of the counter to see if there is a bit transition that's happened since the last look. Each look corresponds to something like this:
cmp phsb, (some value greater than 1/2 bit period but less than 1 full period) wc
mov phsb, #0
shl input, #1
muxnc input, #1
The idea is that you run it really fast and loose. The sample period you run the loop should be close to the bit period. This way you use the counter to vote the bit value high or low and you don't need to detect the edges. Of course the downside is that you can't get more than 1 transmitter and 1 receiver per COG, but you could possibly sample at very high speeds. I think you could get between 1-3Mbps full duplex. You could compensate for jitter and drift by subtracting or adding to phsX so it works out over time, this would also help with phase delay. If the remote device sends the start bit and you have some phase offset error, just add or subtract that into the phase accumulator of the counter.
Larger default RX buffer (you can set it, of course)
Added a non-blocking transmit buffer (TxBufNoWait)
Testing code uses that non-blocking send to stress the RX *while transmitting*
Tightened up some code, and refactored to avoid the lock-up mentioned by Tracy
Added more comments to the PASM
@Tracy: I could not duplicate the lock-up on BREAK, but I did find some code that could be responsible. Did the lock-up only happen on RCFAST at 57_600?
@pedward: I use a counter to align the RX code with the start bit (if we are closer than 1/4 bit width to the front of the start bit, then I wait another 1/2 bit, guaranteeing we will always be at least 1/4 bit period away from the transition). But using it to actually decide the bit value actually takes one instruction more. The simple way does a TEST then RCR. Using the counter needs a CMP, RCR, then MOV to reset the PHSx register. So other than strengthening the start-bit alignment, I opted to simply use the TEST command.
Jonathan,
I'm attaching the simple spin program I was using to sample the tx output to p0 and input from p1. All is well if p1 is high. But if I bring it low, the serial output stops.
-- okay! just tried it with your latest release. Whatever you did, the problem is fixed.
Here are statistics at 460800 baud (clkfreq=80MHz). Again this is without any activity into the receiver.
In order to scope out the receive timing in relation to bit edges, I'd need to insert a pin toggle in your receive routine. Could a pin toggle fit in right next to the test instruction?
[FONT=courier new][SIZE=1] ' read in 8 bits
:get_bit jmpret lockstep_ret, tx_jump
test maskRX, ina wc
rcr data_in, #1
jmpret lockstep_ret, tx_jump
djnz bits_in, #:get_bit
[/SIZE][/FONT]
By the way, I expect one clock's worth of jitter for a single bit on the RX timing in the following circumstance:
The bit period is an odd number of clocks.
The cog started transmitting a byte in the middle of receiving a byte.
This is because of the carry-clock operation. I only had room to shoe-horn it into the transmit code...the receive code is (or at least should be) robust enough to handle the bit period being 170 (at a minimum) clocks instead of 171. If TX isn't running, though, the actual bit period will be an even number. If TX is actively sending out a byte and the period P is an odd number, then it will toggle the 1/2 bit period between P/2 and P/2+1.
This is one of those features that I like in principle, but it probably doesn't matter, and if I can't figure out a way to get it working all the time I may just dump it. Thoughts / opinions?
Comments
Jonathan
EDIT: removed attachment...the one 4 posts down is better
The real test comes from banging on it on the receive side. Any particular test you want?
By the way, I found that it locks up if the receive pin sees a BREAK condition or if the pin is floating when the object is initialized.
xtal1 5MHz PLLx2:
RCfast:
No specific tests in mind (though some testing at 460_800 would be nice), I just want to squish any bugs before a formal release. Thanks for the heads up on the break condition...I will try to track that down tomorrow for yet another release.
Thanks!
Jonathan
You don't need the video generator, just the counter. You put your bit pattern in the counter high bits, then every N clock cycles you simply shl the counter and it appears on the designated pin. You can queue up to 3 bytes this way. In fact, this would be the way to redesign FDS to have enough cycles in the read loop to get very accurate timing all around.
EDIT: Zombie thread!
Another idea, use the other counter in free run capture mode. If you are time slicing the receiver and the transmitter, you look at phsX value of the counter to see if there is a bit transition that's happened since the last look. Each look corresponds to something like this:
The idea is that you run it really fast and loose. The sample period you run the loop should be close to the bit period. This way you use the counter to vote the bit value high or low and you don't need to detect the edges. Of course the downside is that you can't get more than 1 transmitter and 1 receiver per COG, but you could possibly sample at very high speeds. I think you could get between 1-3Mbps full duplex. You could compensate for jitter and drift by subtracting or adding to phsX so it works out over time, this would also help with phase delay. If the remote device sends the start bit and you have some phase offset error, just add or subtract that into the phase accumulator of the counter.
@Tracy: I could not duplicate the lock-up on BREAK, but I did find some code that could be responsible. Did the lock-up only happen on RCFAST at 57_600?
@pedward: I use a counter to align the RX code with the start bit (if we are closer than 1/4 bit width to the front of the start bit, then I wait another 1/2 bit, guaranteeing we will always be at least 1/4 bit period away from the transition). But using it to actually decide the bit value actually takes one instruction more. The simple way does a TEST then RCR. Using the counter needs a CMP, RCR, then MOV to reset the PHSx register. So other than strengthening the start-bit alignment, I opted to simply use the TEST command.
Jonathan
I'm attaching the simple spin program I was using to sample the tx output to p0 and input from p1. All is well if p1 is high. But if I bring it low, the serial output stops.
-- okay! just tried it with your latest release. Whatever you did, the problem is fixed.
Here are statistics at 460800 baud (clkfreq=80MHz). Again this is without any activity into the receiver.
In order to scope out the receive timing in relation to bit edges, I'd need to insert a pin toggle in your receive routine. Could a pin toggle fit in right next to the test instruction?
Yep, there is time for a single instruction right after the TEST on line 309.
Jonathan
- The bit period is an odd number of clocks.
- The cog started transmitting a byte in the middle of receiving a byte.
This is because of the carry-clock operation. I only had room to shoe-horn it into the transmit code...the receive code is (or at least should be) robust enough to handle the bit period being 170 (at a minimum) clocks instead of 171. If TX isn't running, though, the actual bit period will be an even number. If TX is actively sending out a byte and the period P is an odd number, then it will toggle the 1/2 bit period between P/2 and P/2+1.This is one of those features that I like in principle, but it probably doesn't matter, and if I can't figure out a way to get it working all the time I may just dump it. Thoughts / opinions?
Jonathan
- removed the carry-clock code (simpler, not really much less accurate)
- Added string to integer helper functions (AToI, HToI)
Jonathan