Spin school - can serial tx be done this simple?
Erlend
Posts: 612
For some serial communications I only need to shoot off a few bytes, then go on executing the main code. For this I want to call a very very simple serial tranmission method - without starting a new cog for it. My question is; can it be thus simple? -and is the code correct?
I have pinched and stolen parts of this code, and honestly I do not understand why the byte needs << 2 to give room for 1 stop bit, and does it really need to be | $100?
I could do with some mentoring, Erlend
PRI Tx96(txByte,txPin) | t, bitDur bitDur := clkfreq / 9600 txByte := (txByte | $100) << 2 ' add stop bit outa[txPin] := 1 ' idle state dira[txPin]~~ ' could instead do this outside this method - once and for all t := cnt ' sync repeat 10 ' start + eight data bits + stop waitcnt(t += bitDur) ' wait bit duration, first wait keeps 'idle state' for one bit duration outa[txPin] := (txByte >>= 1) & 1 ' output lsb, then shift right to move next bit in place for tx
I have pinched and stolen parts of this code, and honestly I do not understand why the byte needs << 2 to give room for 1 stop bit, and does it really need to be | $100?
I could do with some mentoring, Erlend
Comments
You can calculate the bitdur as a constant rather than caclulating each time. Since asynch transmits lsb first the << 2 just makes room for a start bit (a zero) plus an extra bit because of the way it outputs each bit it wastes the very first bit. The $100 that is OR'd before it is shifted left is to make sure that the 10th bit (9th<<2-1) that is shifted out is a 1 or stop bit. Looking at the bits just before it starts to send them you have from lsb to msb --> DUMMY=0 + START=0 + DATA(0)..(DATA(7) + STOP=1
I didn't first get that the shift-right was done prior to tranmitting. So, if instead of if I do a tx first and then shift-right, the first bit will not be wasted - which means the initial <<2 can be changed to <<1. That would - at least for me - make the code more logical and understandable, like this:
Does this look OK? Question: what about the duration of the stop bit at the end? -there is no waitcnt to control it's duration, but as long as there is no dira[txPin]~ (tidy up) before the method ends, the stop bit will just stay high until next call - but what happens if that call comes really quick and cuts off the stop bit too early? Maybe the stop bit duration isn't critical.
Erlend
Erlend
The <<2 part I think was just to try and keep it efficient, at least for Spin when it did the (txbyte >>= 1) & 1 in a single operation, the compiler generates: vs your version So for the sake of an extra bit shift before the loop it becomes more efficient during the loop.
This isn't a problem at low baud rates but makes a difference at high baud rates.
The stop bit should be included in loop too with a waitcnt but these routines don't normally run that fast and nor does Spin.
By way of contrast a high level loop like this in my Tachyon Forth runs up to 250k baud vs the 19.2k baud or so of Spin (which takes 38 bytes).
I didn't realise that code penalty was so high for my suggested change in the code. It doesn't matter in practice, but from a 'coding estetics' point of view I guess it hurts. Same goes for the half-hearted coding of the stop bit.
Erlend
Addr : 0040: 3D B4 : Register [Bit] op OUTA Write
So the compact form didn't really save anything at all, just one byte!
As for Forth you are missing all the fun of interacting with the Prop itself. I can't say about the "wiring" thing because I don't have a problem with "verbal" (do you swear at it? ) languages but they don't live on the Prop or interact with it, only on the PC.
Look at the loop for the start and data bits (9 bits)
9 FOR WAITCNT SHROUT NEXT
How simple is that?, and only 6 bytes.
Yes, Peter I did see that and thought: Wow, I am sorry I am not part of this joy. Well, I may have a long life ahead of me, so you never know if I will some day go Forth and enlighten myself : )
Erlend
outa[txPin] := (txByte >>= 1) & 1
Erlend