Adding Even Parity to One Port in Tracy Allen's 4-Port Serial Object
Duane Degn
Posts: 10,588
I was going to post this in Tracy Allen's four port serial thread but I didn't want to hijack the thread so I'm starting at new thread to ask my question about even parity.
I'm hoping to add even parity to one of the port's tx line.
In an attempt to change port #1 to output even parity, I changed the "transmit 1" code from:
To:
Does this look like it should work?
As I understand it, the parity bit is the second to the last bit. "shl txdata1,#2" makes room for two stop bits. Only one of the stop bits is high in the original code. Am I correct in thinking I want the second to the last bit also high if there are an odd number of bits in "txdata1"?
"txbitor" (1,025 or $401) adds two bits to txdata1. One bit is the start bit in the tenth position from the right and the other is the final stop bit in the far right position.
From my reading on the internet, it looks like even parity means the total number of bits sent per character should be even. The parity bit is added when the total number of bits would otherwise be odd.
I haven't tested this. I think I have a program that will provide even parity output so I'll likely compare the output from the Propeller with the output from the even parity program (Modbus Poll).
Is there a better way to do this?
I'm hoping to add even parity to one of the port's tx line.
In an attempt to change port #1 to output even parity, I changed the "transmit 1" code from:
'' Transmit1 ------------------------------------------------------------------------------------- ' transmit1 jmpret txcode1,rxcode2 'run a chunk of receive code, then return txcts1 test ctsmask1,ina wc 'if flow-controlled dont send rdlong t1,tx_head_ptr1 cmp t1,tx_tail1 wz ctsi1 if_z jmp #transmit1 'may be patched to if_z_or_c or if_z_or_nc rdbyte txdata1,txbuff_tail_ptr1 add tx_tail1,#1 cmpsub tx_tail1,txsize1 wz ' (TTA) for individually sized buffers, will zero at rollover wrlong tx_tail1,tx_tail_ptr1 if_z mov txbuff_tail_ptr1,txbuff_ptr1 'reset tail_ptr if we wrapped if_nz add txbuff_tail_ptr1,#1 'otherwise add 1 jmpret txcode1,rxcode2 'run a chunk of receive code, then return shl txdata1,#2 [COLOR=#ff0000] [B]or txdata1,txbitor 'ready byte to transmit[/B][/COLOR] mov txbits1,#11 mov txcnt1,cnt txbit1 shr txdata1,#1 wc txout1 muxc outa,txmask1 'maybe patched to muxnc dira,txmask add txcnt1,bit_ticks1 'ready next cnt :wait1 jmpret txcode1,rxcode2 'run a chunk of receive code, then return mov t1,txcnt1 'check if bit transmit period done sub t1,cnt cmps t1,#0 wc if_nc jmp #:wait1 djnz txbits1,#txbit1 'another bit to transmit? txjmp1 jmp ctsi1 'byte done, transmit next byte
To:
shl txdata1,#2 [COLOR=#ff0000] or txdata1,txbitor wc 'ready byte to transmit[/COLOR] [COLOR=#ff0000] if_c or txdata1,#2 'add even parity if needed? [/COLOR] mov txbits1,#11
Does this look like it should work?
As I understand it, the parity bit is the second to the last bit. "shl txdata1,#2" makes room for two stop bits. Only one of the stop bits is high in the original code. Am I correct in thinking I want the second to the last bit also high if there are an odd number of bits in "txdata1"?
"txbitor" (1,025 or $401) adds two bits to txdata1. One bit is the start bit in the tenth position from the right and the other is the final stop bit in the far right position.
From my reading on the internet, it looks like even parity means the total number of bits sent per character should be even. The parity bit is added when the total number of bits would otherwise be odd.
I haven't tested this. I think I have a program that will provide even parity output so I'll likely compare the output from the Propeller with the output from the even parity program (Modbus Poll).
Is there a better way to do this?
Comments
Here's the original Here's the changed version:
For now the planned baud is 19,200 bps.
I noticed in the Propeller manual the "or" command will set the c flag based on the parity. I thought I'd take advantage of this and make the change in PASM.
My first attempt as posted above did not work correctly. I'll change the "if_c" to "if_nc" and see if it works. If not, I'll use your Spin code.
Thank you very much.
BTW, This port will be communicating via Modbus. I was fortunate to come across one of your earlier posts with Modbus CRC code which worked perfectly. Thanks for this and the CRC code both!
RS232 data is shifted out lsb first. So you have the parity bit in the wrong position.
The msb is at bit position 9, so, I think the following should work. (You can't use #512 as a literal.) This is predicated on having a zero in the msb at entry. XOR could work even if a one bit wiggled in there. I think your logic for creating even parity is otherwise correct. The OR operation will set carry if parity is odd, so inserting the "1" bit will make it even. The pasm is cleaner than the Spin in the sense that pasm calculates the parity for you.
It's supposed to be 8-bit even parity.
The lsb first thing was just occurring to me as I was looking at the logic traces.
I noticed the Propeller didn't like receiving 8-bit even one stop bit from Modbus Poll. I had to set the the parity to none for the Propeller to receive the command. As I mentioned earlier, I'm using your 4-port object (probably incorrectly).
I think I might need to go work on a robot for a while. I'm feeling the insanity creeping in from watching too many bits go by on the LA.
I'll report back on progress (or not) later.
Thank you very much Tracy and Mike. I'm not sure what I'd do without the help I receive on the forum.
Right now I'm not sure about this.
This is the setting on Modbus Poll I'm hoping to use when communicating with the Propeller.
Am I correct in thinking this setting corresponds with the notation 8E1?
Here's a LA trace from the output using the above settings. As indicated by the LA, the output is a zero followed by a one.
I don't want you to have to spend your time teaching me basic serial communication. I need to spend some time and get start and stop bits straight in my mind. I'm guessing the even parity bit takes the place of what had been the stop bit?
I'll do some more testing (and reading) and try to come back with some (hopefully) intelligent questions.
Thank you for your help so far.
Edit: I'm pretty sure I can make the changes to the serial driver you suggest. I just need to figure out what I really want the driver to do.
Yes, 8E1. 9 bits total between start and stop, compared with 8 bits between start and stop for 8N1. There is still a stop bit, after parity.
That's exactly want I wanted to know.
The code didn't change much from post #1 but Tracy's diagram of the various bits was just what I need to figure this out.
I originally used:
But I found the LA traces included two stop bits rather than just one. I realize now the normal code uses two stop bits not just one.
The Modbus Poll program read the 8E2 data just fine but I changed the "#12" back to "#11" and got rid of the extra stop bit. I believe the code now outputs 8E1 serial data!
I shifted the msb of txbitor left one position and stored in the variable "txbitor1"
As Tracy pointed out the parity bit couldn't be added as a literal so I added one more variable "parity".
I added these extra variables to the list after "txbitor".
I changed the number of bits read in the rx portion of port #1 from 9 to 10 and modified the "justify and trim" line.
I'm not bothering to check the parity on the incoming messages. I have Mike's CRC algorithm checking the entire message so it's not a big deal if a bad byte gets by.
This is great to be able to modify the serial object like this. It's very "empowering". Tracy, I guess I did want you to spend your time teaching me basic serial communication after all.
Thank you again Tracy!
It does do the trick doesn't it.
LSB leading is named Little Endian. MSB leading is know as Big Endian. You'll notice them in various cases from time to time from now on. You might also recognise you'd missed it in the past as well.
On the subject of Modbus; Are you explicitly using binary mode? If not then 7E1 is the nicer fit.
Yes, I'm aware of Endianess. I've done enough LED projects that shift bytes around in memory to be very aware of what bytes go where in longs. I remember when I first learned the Prop was Little Endian, I thought Chip must be crazy for doing something so counter intuitive. Now that I've been programming the Prop (a lot) over the last six years I can see how Little Endian is really the only choice that makes sense for the Propeller.
Yes, it's RTU Modbus. Data being sent Big Endian for each register but least significant register first (for 32-bit values).
The programs Modbus Poll and Modbus Slave along with a logic analyzer finally made the makeup of a Modbus packet make sense. I was having trouble with the CRC until I found Mike Green's Spin code. Tracy Allen's guidance helped me finish finally figure out how to add even parity. This forum is great!
16 bit "registers" I presume? So, the byte significance order is 1, 0(LSB), 3(MSB), 2?
Yes, or in Modbus Poll's notation, "CD AB" where"A is MSB and D is LSB.
The strange byte order is only used when sending data. It's stored in the Propeller's "registers" as little endian longs. Having the (double) registers as longs makes using the values much easier in the program. The bytes get unscrambled with received and scrambled again when sent.
You noticed that the existing code sends two stop bits instead of one. A couple of people have complained to me about that in PMs, why 2 bits, slow down the tx, why 11 bits instead of 10? It is fairly easy to correct that, per the code segment below. The old way commences by shifting out a stop bit (huh?!), then the start bit, then 8 bits of data, then stop. So in operation, the two stop bits you see are coming from two ends of the candle, as it were. The code below commences right in with a start bit, then 8 data bits, and one stop bit. The txbitor1 $FFFFFE00 allows you to get up to 23 stop bits (interchar pacing) by patching the number of bits, because the extras will be stop bits. Your 8N1 would patch in pretty much like you have it.
The OBEX object is still the old way, with two stop bits on tx. That dates I think from the original fullDuplexSerial. Someday soon I'll update it.
Two stops at 9600:
One stop at 9600:
I had wondered why we were shifting the byte by two places initially. Your new code (and your explanation) makes much more sense as I attempt to understand it than the previous code with a leading stop bit.
My modifications in post #10 left in this leading stop bit but took out the trailing one. Since the line idles high, the missing final stop bit didn't cause a problem. I will change my driver to match your new changes. Now I'm surprised the code in post #10 worked.
Thank you again for your help!
I think I neglected to mention, by removing the extra stop bit, I had to change the parity check from "if_c" to "if_nc".
Here are the current values of the added variables.
I haven't removed the extra stop bit from the other ports yet.
I agree that it shouldn't be too hard to make the parity configurable but doing so would increase the size of the program. I've already had to make a two port version of your driver for a project that was running out of space. I'm not anxious to increase the size of the four port driver.
I think it would be nice to include instructions on how to modify the driver to add parity if desired. The instructions could even be a link to the forum where adding parity is shown.
How do devices which require parity respond to incorrect parity? Do they ignore just the character or do they ignore the whole message? As I type this I realize it's likely a "it depends" type answer. I can see a Modbus device initially ignoring a character with a bad parity bit but the ignored character would also cause the CRC to be incorrect for the message so the entire message would be ignored.
It sure seems like having parity and a CRC is kind of like having a belt and suspenders.
Thank you again for your help.
One thing I've added to my own version is another fast co-routine that implements a poke and peek function from spin to the cog registers. I originally wrote it to allow access to the cog counter registers, but it also allows patching stuff like the baud rate or pins used by a port, without stopping and restarting the cog. As always, poke is a dangerous function and requires knowing where everything is.
One question: It appears that no modifications are required to the "port receive" code to handle even parity? (Yes, I'm working on a Modbus project.) If I'm thinking correctly, when the parity bit is low, the "wait for stop bit" routine will just have to wait a bit longer for the stop bit. If the parity bit is high, "wait for stop" will assume it received the stop bit and exit. Almost like 2 stop bits?
P.S. Once again, the four-port serial driver is simply amazing!
This is the port #1(the port with even parity) PASM section of the serial driver I frequently use. The entire PASM code exceeded the character limit of the forum software.
The receive code receives the extra bit but it doesn't check the parity.
I've attached the first version of a driver with parity I could find. The Spin portion of the code is different from the version Tracy originally posted. You should be able to use the PASM section from my object in a more traditional version of Tracy's driver.
I use the attached code mainly for debugging programs since it uses locks and can be used from multiple objects and multiple cogs.
Looked at your code--oh yes, you are completely correct with regards to that version! I'm actually using a four-port serial driver that has the following acknowledgements:
And the receive code for one of the ports:
In MY case, then, it appears that the code does not need modified to receive even parity. Because the parity bit is immediately followed by the stop bit, and the code has a separate loop to wait for the stop bit. It seems to me that if the parity bit is high, it'll be seen as "two stop bits", otherwise identified by a longer delay before the next "start" bit can come. And if the parity bit is low, it'll be seen as an "extra long data bit", and the "wait for stop" loop will simply wait a little longer until the line goes high (for the actual stop bit.)
Didn't realize that we were talking about two entirely different versions of a four-port serial driver!
http://forums.parallax.com/discussion/160275/reduced-latency-1x-and-4x-serial/p1