Shop OBEX P1 Docs P2 Docs Learn Events
Adding Even Parity to One Port in Tracy Allen's 4-Port Serial Object — Parallax Forums

Adding Even Parity to One Port in Tracy Allen's 4-Port Serial Object

Duane DegnDuane Degn Posts: 10,588
edited 2014-04-28 09:26 in Propeller 1
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:
'' 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

  • Mike GreenMike Green Posts: 23,101
    edited 2014-04-24 11:14
    Is there a speed issue here? It's easier to just add an even parity bit to the data as it's being put into the output buffer although it's relatively slow.

    Here's the original
    PUB tx(port,txbyte)
    '' Send byte (may wait for room in buffer)
      if port > 3
        abort
      repeat until (tx_tail[port] <> (tx_head[port] + 1) // txsize[port])
      byte[txbuff_ptr[port]+tx_head[port]] := txbyte
      tx_head[port] := (tx_head[port] + 1) // txsize[port]
    
      if rxtx_mode[port] & NOECHO
        rx(port)
    
    Here's the changed version:
    PUB tx(port,txbyte)
    '' Send byte (may wait for room in buffer)
      if port > 3
        abort
      repeat until (tx_tail[port] <> (tx_head[port] + 1) // txsize[port])
      if port == 1   ' The following computes the odd parity, then inverts it and places the bit into the high order bit of txbyte.  It could be done faster in PASM, but this works.
        txbyte |= (((txbyte & $40 << 1) ^ (txbyte & $20 << 2) ^ (txbyte & $10 << 3) ^ (txbyte & $08 << 4) ^ (txbyte & $04 << 5) ^ (txbyte & $02 << 6) ^ (txbyte & $01 << 7)) & $80) ^ $80
      byte[txbuff_ptr[port]+tx_head[port]] := txbyte
      tx_head[port] := (tx_head[port] + 1) // txsize[port]
    
      if rxtx_mode[port] & NOECHO
        rx(port)
    
  • Duane DegnDuane Degn Posts: 10,588
    edited 2014-04-24 11:44
    No there's not a speed issue.

    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!
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2014-04-24 11:51
    Duane, Just to be clear, this is supposed to be 7-bit even parity?

    RS232 data is shifted out lsb first. So you have the parity bit in the wrong position.
    [SIZE=1][FONT=courier new]txbit1   shr     txdata1,#1      wc    ' <--- shift right, stop, start, lsb to msb, stop
    txout1   muxc    outa,txmask1
    [/FONT][/SIZE]
    
    The msb is at bit position 9, so, I think the following should work. (You can't use #512 as a literal.)
    [SIZE=1][FONT=courier new]
      or  txdata1,txbitor      wc 'ready byte to transmit, test parity
      muxc  txdata1,parityBit   'add even parity if needed?    
    ...
    DAT
      txbitor   long  $0401
      parityBit long  %10_0000_0000   [/FONT][/SIZE]
    
    This is predicated on having a zero in the msb at entry. XOR could work even if a one bit wiggled in there.
    [SIZE=1][FONT=courier new]  if_c xor txdata1,parityBit
    [/FONT][/SIZE]
    
    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.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2014-04-24 12:08
    Duane, Just to be clear, this is supposed to be 7-bit even parity?

    RS232 data is shifted out lsb first. So you have the parity bit in the wrong position.

    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.
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2014-04-24 12:26
    8 bits plus parity require that one additional bit be sent. It is not a hard change to make, but it is not simply a matter of re-purposing one of the existing bits. Do you also need 8+parity on the receive side in the Prop? Otherwise I think the code will reject some bytes that come in with a parity bit where it is expecting a stop bit, that is, a framing error.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2014-04-24 21:22
    8 bits plus parity require that one additional bit be sent. It is not a hard change to make, but it is not simply a matter of re-purposing one of the existing bits. Do you also need 8+parity on the receive side in the Prop? Otherwise I think the code will reject some bytes that come in with a parity bit where it is expecting a stop bit, that is, a framing error.

    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.

    attachment.php?attachmentid=108318&d=1398370450

    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.

    attachment.php?attachmentid=108319&d=1398370450

    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.
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2014-04-24 23:14
    Screen shot 2014-04-24 at 11.00.58 PM.png


    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.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2014-04-24 23:21
    Thank you Tracy!

    That's exactly want I wanted to know.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2014-04-25 20:39
    Success!

    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.
    shl     txdata1,#2
                            or      txdata1,[COLOR=#ff0000]txbitor1 wc[/COLOR]   'ready byte to transmit
            [COLOR=#ff0000]if_c            or      txdata1,parity[/COLOR]        'add even parity if needed?       
                            mov     txbits1,#11           
    

    I originally used:
    mov     txbits1,#[COLOR=#ff0000]12[/COLOR]           
    
    
    

    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".
    txbitor                 long      $0401               'bits to or for transmitting, adding start and stop bits
    [COLOR=#ff0000]txbitor1                long      $0801[/COLOR]               'bits to or for transmitting, adding start and stop bits
    [COLOR=#ff0000]parity                  long      $0400[/COLOR]               ' 1 << 10 ' where stop bit had been for no parity
    

    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.
    mov     rxbits1,#[COLOR=#ff0000]10[/COLOR]           'ready to receive byte +1 DWD
    
    shr     rxdata1,#32-[COLOR=#ff0000]10[/COLOR]         'justify and trim received byte +1 DWD
    

    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!
  • evanhevanh Posts: 15,916
    edited 2014-04-25 21:15
    Duane Degn wrote: »
    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.

    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.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2014-04-25 21:43
    evanh wrote: »
    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.

    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.
    evanh wrote: »
    On the subject of Modbus; Are you explicitly using binary mode? If not then 7E1 is the nicer fit.

    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!
  • evanhevanh Posts: 15,916
    edited 2014-04-25 22:59
    Duane Degn wrote: »
    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.
    Either way is equal difficultly from a hardware point of view. The only sense is the human view.
    Yes, it's RTU Modbus. Data being sent Big Endian for each register but least significant register first (for 32-bit values).
    16 bit "registers" I presume? So, the byte significance order is 1, 0(LSB), 3(MSB), 2?
  • Duane DegnDuane Degn Posts: 10,588
    edited 2014-04-26 12:06
    evanh wrote: »
    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.
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2014-04-26 14:48
    Duane, that's a nice option to have documented. 7E1, 7E2 and 8E1 are fairly common, and instruments that use those options are often quite rigid about what they will accept and respond to. Those options could be included in the mode parameter when adding the port, maybe with minimum impact on the speed for moderate baud rates.

    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.

    [SIZE=1][FONT=courier new]' 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 (CTS handler, open vs driven, true vs inverted)
                    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,[COLOR=#ff0000]#1[/COLOR]             ' shifting left only one for start bit (TTA)
                    or      txdata1,[COLOR=#ff0000]txbitor1[/COLOR]       'ready byte to transmit (TTA, txbitor1 instead of txbitor)
                    mov     txbits1,[COLOR=#ff0000]#10[/COLOR]             ' 10 bits only, start,8 data, stop (TTA, 10 not 11, was stop,start,8data,stop)
                    mov     txcnt1,cnt
    txbit1          shr     txdata1,#1      wc
    txout1          muxc    outa,txmask1          'may be patched to muxnc dira,txmask to support open vs driven mode
                    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
    
    'need also,
    [COLOR=#ff0000]txbitor1     long      $FFFFFE00[/COLOR]  ' start and stop bit(s)for tx
    [/FONT][/SIZE]
    
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2014-04-26 14:53
    Here are a couple of Saleae shots for two bits from the original code vs 1 bit from the modification above.
    Two stops at 9600:
    Two stops.png


    One stop at 9600:
    One stop.png
    1017 x 347 - 54K
    957 x 375 - 57K
  • Duane DegnDuane Degn Posts: 10,588
    edited 2014-04-27 09:39
    This explains a lot I had been confused about. Your diagram in post #8 helped me see the start bit was low, yet before sending a byte of data you or'ed "txbitor" with the value $401 which has two high bits with 9 low bits in between the high bits. I see now the lsb is the leading stop bit.

    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!
  • Duane DegnDuane Degn Posts: 10,588
    edited 2014-04-28 07:20
    In order to place the stop bit in the correct location, I made these changes based on your suggestions.
    shl     txdata1,#[COLOR=#ff0000]1
    [/COLOR]                        or      txdata1,[COLOR=#ff0000]txbitor1[/COLOR] wc   'ready byte to transmit
    [COLOR=#ff0000]        if_nc           or      txdata1,parity[/COLOR]        'add even parity if needed?       
                            mov     txbits1,#11           
    
    
    

    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.
    txbitor                 long      $0401               'bits to or for transmitting, adding start and stop bits
    [COLOR=#ff0000]txbitor1                long      $0400[/COLOR]               'bits to or for transmitting, adding start and stop bit
    [COLOR=#ff0000]parity                  long      $0200[/COLOR]               ' 1 << 9
    

    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.
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2014-04-28 09:26
    Duane, I've made quite a few ad-hoc modifications to the driver myself, indeed, not much room left in the cog. Adding one long for parity for each driver does not add much time to that relatively short co-routine, but the init code to patch each of the 4 transmit routines for modes 8n1, 7e1, 8e1 (or others) would take quite a few instructions. If the long for adding parity is there, the variation can easily be patched in either at compile or run time.

    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.
  • Wonderful thread by the way! Just what I needed to modify Tracy's 22-Jan-2011 four-port driver, so one port outputs 8E1! Nice!
    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!
  • IIRC, the receive code needs to be modified a bit. The code needs to receive one additional bit.

    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.
    '
    ' Receive1 -------------------------------------------------------------------------------------
    '
    receive1                jmpret  rxcode1,txcode1       'run a chunk of transmit code, then return
                            
                            test    rxmask1,ina     wc
    start1  if_c            jmp     #norts1               'go check rts if no start bit
                              
                            mov     rxbits1,#10 '** 9            'ready to receive byte
                            mov     rxcnt1,bit4_ticks1    '1/4 bits
                            add     rxcnt1,cnt                          
    
    :bit1                   add     rxcnt1,bit_ticks1     '1 bit period
                            
    :wait1                  jmpret  rxcode1,txcode1       'run a chuck of transmit code, then return
                              
                            mov     t1,rxcnt1             'check if bit receive period done
                            sub     t1,cnt
                            cmps    t1,#0           wc
            if_nc           jmp     #:wait1
    
                            test    rxmask1,ina     wc    'receive bit on rx pin
                            rcr     rxdata1,#1
                            djnz    rxbits1,#:bit1
    
                            test    rxtx_mode1,#INVERTRX  wz      'find out if rx is inverted
            if_z_ne_c       jmp     #receive1              'abort if no stop bit   (TTA) (from serialMirror)
    
                            jmpret  rxcode1,txcode1       'run a chunk of transmit code, then return
                            shr     rxdata1,#32-10 '** 9         'justify and trim received byte
                                   
                            wrbyte  rxdata1,rxbuff_head_ptr1 '7-22
                            add     rx_head1,#1
                            cmpsub  rx_head1,rxsize1         ' (TTA) allows non-binary buffer size
                            wrlong  rx_head1,rx_head_ptr1
                            mov     rxbuff_head_ptr1,rxbuff_ptr1 'calculate next byte head_ptr
                            add     rxbuff_head_ptr1,rx_head1
    norts1                  rdlong  rx_tail1,rx_tail_ptr1    '7-22 or 8 will be patched to jmp #r3 if no rts
                            mov     t1,rx_head1
                            sub     t1,rx_tail1    wc
            if_c            add     t1,rxsize1           ' fix wrap, (TTA) change
                            cmps    t1,rtssize1     wc
    rts1                    muxc    outa,rtsmask1
    
    rec1i                   jmp     #receive1             'byte done, receive next byte                       
    
    '
    ' TRANSMIT =======================================================================================
    '
    ' 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,#1 '** 2          '** changed for even parity
                            or      txdata1,txbitor1 wc '** txbitor
            if_nc           or      txdata1,parity        'add even parity if needed?  '** added for parity
                            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
    
    
    txbitor                 long      $0401               'bits to or for transmitting, adding start and stop bits
    txbitor1                long      $0400               'bits to or for transmitting, adding start and stop bit
    parity                  long      $0200               ' 1 << 8 ' where stop bit had been for no parity
    
    

    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.
  • Thanks for the code, anyway! It turns out that my ModBus client requires NO parity...I should have checked the specs first! Worth noting is that it always send data with 2 stop bits, but accepts data with either one or two stop bits. Piece of cake...

    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:
    '       Based in part upon full-duplex serial driver v1.01                                
    '       Tracy Allen (TTA)   (c) 22-Jan-2011
    '       Copyright (c) 2006 Parallax, Inc.                             *
    '
    '       Other attributions include, in alphabetic order:
    '               Juergen Buchmueller
    '               Duane Degn
    '               Tim Moore
    '____________________________________________________________________________________________
    '
    ' Copyright (c) 2015 by Wayne Meretsky
    '
    ' This version of the serial port driver was rewritten entirely from scratch in early
    ' 2015 with three goals, in order: Correctness, Performance, Code Size. While it is
    ' an entirely new implementation, it draws heavily on the design and implementation of
    ' many original and derived works that preceed it. 
    

    And the receive code for one of the ports:
    ' Receiver for Port 0
    '
    P0_Rx                   mov     P0_Rx_BC,#8             ' We need to read 8 data bits
                            mov     P0_Rx_Timer,P0_SO       ' Get the sample offset
    
    :wait_for_start         jmpret  Rx0_PC,Tx0_PC           ' Run some Transmit code and return here
                            test    P0_RxM,ina      wc      ' Move the RxD into Carry
                    if_c    jmp     #:wait_for_start        ' Wait for the start bit to arrive
    
                            add     P0_Rx_Timer,cnt         ' Compute the sample time                          
    :next_bit               add     P0_Rx_Timer,P0_TPB      ' Add one bit time
                            
    :wait                   jmpret  Rx0_PC,Tx0_PC           ' Run some Transmit code and return here
                            mov     t1,P0_Rx_Timer          ' Get the sample time
                            sub     t1,cnt                  ' Compare to the current time
                            cmps    t1,#0           wc
                    if_nc   jmp     #:wait                  ' And wait until it's time to sample
    
                            test    P0_RxM,ina      wc      ' Get RxD into Carry
                            rcr     P0_RxD,#1               ' Rotate it into our byte; we receive LSB first
                            djnz    P0_Rx_BC,#:next_bit
    
                            jmpret  Rx0_PC,Tx0_PC           ' Run some Transmit code and return here  
                            
                            shr     P0_RxD,#32-8            ' Position the byte into the LSBs
                            mov     t1,P0_RxB
                            add     t1,P0_Rx_II
                            wrbyte  P0_RxD,t1
                            add     P0_Rx_II,#1             ' and maintain the buffer structure
                            cmpsub  P0_Rx_II,P0_RxS
                            wrlong  P0_Rx_II,P0_Rx_II_Ref
    
    :wait_for_stop          jmpret  Rx0_PC,Tx0_PC           ' Run some Transmit code and return here
                            test    P0_RxM,ina      wc      ' Move the RxD into Carry
                    if_nc   jmp     #:wait_for_stop         ' Wait for the stop bit to arrive
    
                            jmp     #P0_Rx                  ' Go get the next byte
    

    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!
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2016-07-28 22:55
    For the record, here is a link to Wayne's original thread where he posted his 4-port driver and stirred the waters of Prop 'r programming.
    http://forums.parallax.com/discussion/160275/reduced-latency-1x-and-4x-serial/p1
Sign In or Register to comment.