Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C / C++ / MFC
  4. Setting Parity Bit (serial port) not working. Q for the driver guru's.

Setting Parity Bit (serial port) not working. Q for the driver guru's.

Scheduled Pinned Locked Moved C / C++ / MFC
data-structuresquestion
15 Posts 4 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • A Offline
    A Offline
    Andrew Pearson
    wrote on last edited by
    #1

    Quick Q. Trying to set mark parity, write some data, set space parity, write out some more data. Doing this to emulate a wakeup bit for an older serial protocol. Now I am not convinced that I can do it reliably. Initially I tried using SetCommsMask followed by WriteFile. When this failed, I also tried DeviceIOControl using IOCTL_SERIAL_SET_LINE_CONTROL, but alas, same result (SetCommsMask uses this anyway). The parity bit is not always set. I am not using overlapped comms. When I look at the standard serial port driver supplied with the WDK, I see that IOCTL_SERIAL_SET_LINE_CONTROL uses WdfInterruptSynchronize to set the Line Control Register, and from what I read this is not synchronous (ie waits for an interrupt), so possible means that the parity bit might not always be set in the UART before I write out the data. Is this correct, or am I barking up the wrong tree?

    P L 2 Replies Last reply
    0
    • A Andrew Pearson

      Quick Q. Trying to set mark parity, write some data, set space parity, write out some more data. Doing this to emulate a wakeup bit for an older serial protocol. Now I am not convinced that I can do it reliably. Initially I tried using SetCommsMask followed by WriteFile. When this failed, I also tried DeviceIOControl using IOCTL_SERIAL_SET_LINE_CONTROL, but alas, same result (SetCommsMask uses this anyway). The parity bit is not always set. I am not using overlapped comms. When I look at the standard serial port driver supplied with the WDK, I see that IOCTL_SERIAL_SET_LINE_CONTROL uses WdfInterruptSynchronize to set the Line Control Register, and from what I read this is not synchronous (ie waits for an interrupt), so possible means that the parity bit might not always be set in the UART before I write out the data. Is this correct, or am I barking up the wrong tree?

      P Offline
      P Offline
      Peter_in_2780
      wrote on last edited by
      #2

      Andrew Pearson wrote:

      the parity bit might not always be set in the UART before I write out the data.

      Very likely. The timing of access to UART control registers has ALWAYS been a horror.* Remember that there's a FIFO buffering your tx data. Suggestion: Unless you're using 8 data bits + parity, you can do it yourself. Just use 'n+1' data length and set/unset an appropriate high order bit. * Since the original WD1402 in 1972 or thereabouts. The 8250 and its 16xxx successors (as used in PCs) are not much better. You might get the wrong effect, but at least they don't hang if you write to them at the "wrong" time. :( ;P Cheers, Peter

      Software rusts. Simon Stephenson, ca 1994.

      A 1 Reply Last reply
      0
      • P Peter_in_2780

        Andrew Pearson wrote:

        the parity bit might not always be set in the UART before I write out the data.

        Very likely. The timing of access to UART control registers has ALWAYS been a horror.* Remember that there's a FIFO buffering your tx data. Suggestion: Unless you're using 8 data bits + parity, you can do it yourself. Just use 'n+1' data length and set/unset an appropriate high order bit. * Since the original WD1402 in 1972 or thereabouts. The 8250 and its 16xxx successors (as used in PCs) are not much better. You might get the wrong effect, but at least they don't hang if you write to them at the "wrong" time. :( ;P Cheers, Peter

        Software rusts. Simon Stephenson, ca 1994.

        A Offline
        A Offline
        Andrew Pearson
        wrote on last edited by
        #3

        Peter_in_2780 wrote:

        Very likely. The timing of access to UART control registers has ALWAYS been a horror.* Remember that there's a FIFO buffering your tx data.
         
        Suggestion: Unless you're using 8 data bits + parity, you can do it yourself. Just use 'n+1' data length and set/unset an appropriate high order bit.

        I figured as much. It is 8bits + parity, shame. Wonder if its worth trying at the driver level? Might go look at some datasheets, although it has been a long while since I have had to go that far!

        P 1 Reply Last reply
        0
        • A Andrew Pearson

          Peter_in_2780 wrote:

          Very likely. The timing of access to UART control registers has ALWAYS been a horror.* Remember that there's a FIFO buffering your tx data.
           
          Suggestion: Unless you're using 8 data bits + parity, you can do it yourself. Just use 'n+1' data length and set/unset an appropriate high order bit.

          I figured as much. It is 8bits + parity, shame. Wonder if its worth trying at the driver level? Might go look at some datasheets, although it has been a long while since I have had to go that far!

          P Offline
          P Offline
          Peter_in_2780
          wrote on last edited by
          #4

          Andrew Pearson wrote:

          Might go look at some datasheets

          I wish you lots of luck - you'll need it, seeing these days the UART functionality is typically embedded in an "all-in-one". Probably a microcontroller emulation... Cheers, Peter

          Software rusts. Simon Stephenson, ca 1994.

          A 1 Reply Last reply
          0
          • P Peter_in_2780

            Andrew Pearson wrote:

            Might go look at some datasheets

            I wish you lots of luck - you'll need it, seeing these days the UART functionality is typically embedded in an "all-in-one". Probably a microcontroller emulation... Cheers, Peter

            Software rusts. Simon Stephenson, ca 1994.

            A Offline
            A Offline
            Andrew Pearson
            wrote on last edited by
            #5

            Its very annoying actually, as I can step over WriteFile() and it all works perfectly. Run it and it fails. I have checked registers to make sure there is nothing in transmit holding register, i have turned off the FIFO's. Now I just set the Parity Bit, then Send out a byte using IOCTL_SERIAL_IMMEDIATE_CHAR and it still fails. Not sure there is much left that I can do. I notice that WDK makes mention of an internal call, IOCTL_SERIAL_INTERNAL_BASIC_SETTINGS. I am not right up there with drivers, but I need to port one to 64bit soon so might be good practice! Edit. Put a Sleep(10) after writing out first byte, but before setting parity back to space and guess what, it works. So Problem is not the fact the parity is not getting set fast enough, its because I am changing back parity bit BEFORE the first byte is being transmitted. Tried a few more IOCTL's to try and read Line Status Register but they all show it as clear. Will keep trawling through driver code and see if I can turn something up.

            L J 2 Replies Last reply
            0
            • A Andrew Pearson

              Quick Q. Trying to set mark parity, write some data, set space parity, write out some more data. Doing this to emulate a wakeup bit for an older serial protocol. Now I am not convinced that I can do it reliably. Initially I tried using SetCommsMask followed by WriteFile. When this failed, I also tried DeviceIOControl using IOCTL_SERIAL_SET_LINE_CONTROL, but alas, same result (SetCommsMask uses this anyway). The parity bit is not always set. I am not using overlapped comms. When I look at the standard serial port driver supplied with the WDK, I see that IOCTL_SERIAL_SET_LINE_CONTROL uses WdfInterruptSynchronize to set the Line Control Register, and from what I read this is not synchronous (ie waits for an interrupt), so possible means that the parity bit might not always be set in the UART before I write out the data. Is this correct, or am I barking up the wrong tree?

              L Offline
              L Offline
              Lost User
              wrote on last edited by
              #6

              Andrew Pearson wrote:

              When I look at the standard serial port driver supplied with the WDK, I see that IOCTL_SERIAL_SET_LINE_CONTROL uses WdfInterruptSynchronize to set the Line Control Register,

              Hmm, not sure if Microsoft actualy rewrote serial.sys to use WDF or not, so it cold just be a sample driver. The older DDK with WDM source code actually IS serial.sys on those older machines (XP and older) so it might be a more informative source since WDF can hide stuff. As the other poster says, watch out for the FIFO. I would make it 1 byte, that way you know that after any change you make to the parity bit settings will take effect immediately, and you might also like to have a slight delay, and possibly prod the UART before sending data. (You cold prod it by doing a disable/enable for example, or a flush, or toggling DTR...). A UART programming sheet could be useful, it will tell you exactly what is going on at the chip when you run the various IOCTL calls. How are you determining the value of the parity bit? DO you have a line sniffer? If not you might need to wire up the chip to a logic analyser to see what is actually on the wire. They are very useful, as well as scopes, in really getting HW to work as you want.

              ============================== Nothing to say.

              A 1 Reply Last reply
              0
              • A Andrew Pearson

                Its very annoying actually, as I can step over WriteFile() and it all works perfectly. Run it and it fails. I have checked registers to make sure there is nothing in transmit holding register, i have turned off the FIFO's. Now I just set the Parity Bit, then Send out a byte using IOCTL_SERIAL_IMMEDIATE_CHAR and it still fails. Not sure there is much left that I can do. I notice that WDK makes mention of an internal call, IOCTL_SERIAL_INTERNAL_BASIC_SETTINGS. I am not right up there with drivers, but I need to port one to 64bit soon so might be good practice! Edit. Put a Sleep(10) after writing out first byte, but before setting parity back to space and guess what, it works. So Problem is not the fact the parity is not getting set fast enough, its because I am changing back parity bit BEFORE the first byte is being transmitted. Tried a few more IOCTL's to try and read Line Status Register but they all show it as clear. Will keep trawling through driver code and see if I can turn something up.

                L Offline
                L Offline
                Lost User
                wrote on last edited by
                #7

                Andrew Pearson wrote:

                I can step over WriteFile() and it all works perfectly. Run it and it fails

                You know what this means dont you? In step through the code is taking a lot longer to run than in 'run' mode, so this gives you a clue that it is timing related. ie, you need to make sure the data is completely sentf before changing the UART settings and sending more data. SO look at doing a TX FIFO flush or some such.

                Andrew Pearson wrote:

                I need to port one to 64bit soon

                *Should* be OK, just use the size_t type pretty much everywhere. :)

                Andrew Pearson wrote:

                Put a Sleep(10)

                Yeah, timing. Flush, reset, disable/enable, 1 byte FIFO... All these can force the chip into the exact state you want.

                ============================== Nothing to say.

                1 Reply Last reply
                0
                • A Andrew Pearson

                  Its very annoying actually, as I can step over WriteFile() and it all works perfectly. Run it and it fails. I have checked registers to make sure there is nothing in transmit holding register, i have turned off the FIFO's. Now I just set the Parity Bit, then Send out a byte using IOCTL_SERIAL_IMMEDIATE_CHAR and it still fails. Not sure there is much left that I can do. I notice that WDK makes mention of an internal call, IOCTL_SERIAL_INTERNAL_BASIC_SETTINGS. I am not right up there with drivers, but I need to port one to 64bit soon so might be good practice! Edit. Put a Sleep(10) after writing out first byte, but before setting parity back to space and guess what, it works. So Problem is not the fact the parity is not getting set fast enough, its because I am changing back parity bit BEFORE the first byte is being transmitted. Tried a few more IOCTL's to try and read Line Status Register but they all show it as clear. Will keep trawling through driver code and see if I can turn something up.

                  J Offline
                  J Offline
                  Jochen Arndt
                  wrote on last edited by
                  #8

                  You may change your code to use overlapped IO. Then you can wait until the transmission has been finished before changing the parity setting.

                  L A 2 Replies Last reply
                  0
                  • J Jochen Arndt

                    You may change your code to use overlapped IO. Then you can wait until the transmission has been finished before changing the parity setting.

                    L Offline
                    L Offline
                    Lost User
                    wrote on last edited by
                    #9

                    This is why I dont like overlapped IO. A lot of coders think it must be somehow more 'cool', but end up with code that calls an IO, does a wait, and processes the response. Why not just leave it non overlapped?

                    ============================== Nothing to say.

                    1 Reply Last reply
                    0
                    • J Jochen Arndt

                      You may change your code to use overlapped IO. Then you can wait until the transmission has been finished before changing the parity setting.

                      A Offline
                      A Offline
                      Andrew Pearson
                      wrote on last edited by
                      #10

                      Tried overlapped, same behaviour.

                      J 1 Reply Last reply
                      0
                      • L Lost User

                        Andrew Pearson wrote:

                        When I look at the standard serial port driver supplied with the WDK, I see that IOCTL_SERIAL_SET_LINE_CONTROL uses WdfInterruptSynchronize to set the Line Control Register,

                        Hmm, not sure if Microsoft actualy rewrote serial.sys to use WDF or not, so it cold just be a sample driver. The older DDK with WDM source code actually IS serial.sys on those older machines (XP and older) so it might be a more informative source since WDF can hide stuff. As the other poster says, watch out for the FIFO. I would make it 1 byte, that way you know that after any change you make to the parity bit settings will take effect immediately, and you might also like to have a slight delay, and possibly prod the UART before sending data. (You cold prod it by doing a disable/enable for example, or a flush, or toggling DTR...). A UART programming sheet could be useful, it will tell you exactly what is going on at the chip when you run the various IOCTL calls. How are you determining the value of the parity bit? DO you have a line sniffer? If not you might need to wire up the chip to a logic analyser to see what is actually on the wire. They are very useful, as well as scopes, in really getting HW to work as you want.

                        ============================== Nothing to say.

                        A Offline
                        A Offline
                        Andrew Pearson
                        wrote on last edited by
                        #11

                        I am looking at the code from the latest DDK, but not sure if its WDF. I dont know a whole lot about MS drivers (although I am about to learn!). I am just referring to the sample. I have not looked in great detail yet, still feeling my way through it. I actually disabled FIFO, I know that the code worked, because if I wrote 5 bytes to the port, only the last byte was transmitted! However, as before it never worked, and I should have realised that doing this provided yet another clue as the what was happening. When using WriteFile without overlapped, it is supposed to block until its completed, which I am sure it does. But what does completed mean?? Judging by the observations I made, and after thinking about it a little more, it obviously blocks until the data is written to the driver, not the UART! So I am guessing that the driver buffers what you write to it, and waits for an interrupt before writing the data to the UART, or something along those lines. On Monday, I shall be looking back at the driver code again! So what I know now is: Setting parity is immediate. Transmitting the data is not immediate. I also tried IOCTL_SERIAL_IMMEDIATE_CHAR command with no luck. I have since talked to another developer who has had the same issue. He gave me a tip late friday which I will try on monday. I am using my own app to determine the value of the parity, setting space parity and using IOCTL_SERIAL_LSRMST_INSERT to get parity errors. This works really well actually. I was questioning weather there was a bug in this code too, but I came to the conclusion that it was fine after testing it against the hardware that uses this protocol. Was almost going to put the cro on it for my own sanity. BTW, will be posting this project on code project once its all working ok.

                        1 Reply Last reply
                        0
                        • A Andrew Pearson

                          Tried overlapped, same behaviour.

                          J Offline
                          J Offline
                          Jochen Arndt
                          wrote on last edited by
                          #12

                          One last idea, if this does not help I will give up: You can try to use SetCommMask() with EV_TXEMPTY and call WaitCommEvent() after writing data. When WaitCommeEvent returns false and GetLastError is ERROR_IO_PENDING, use WaitForSingleObject and call GetOverlappedResult when the event is signaled.

                          A 1 Reply Last reply
                          0
                          • J Jochen Arndt

                            One last idea, if this does not help I will give up: You can try to use SetCommMask() with EV_TXEMPTY and call WaitCommEvent() after writing data. When WaitCommeEvent returns false and GetLastError is ERROR_IO_PENDING, use WaitForSingleObject and call GetOverlappedResult when the event is signaled.

                            A Offline
                            A Offline
                            Andrew Pearson
                            wrote on last edited by
                            #13

                            Nope, that does not work either. Once again, I looked at the Driver Code for serial port, and the method for setting the EV_TXEMPTY flag is passed into the WdfInterruptSynchronize method, so it get called once the ISR is completed. It does not reflect the UARTS Line status register from what I can tell. I think the only way to do it reliably is to write a driver that does not use ISR's.

                            J 1 Reply Last reply
                            0
                            • A Andrew Pearson

                              Nope, that does not work either. Once again, I looked at the Driver Code for serial port, and the method for setting the EV_TXEMPTY flag is passed into the WdfInterruptSynchronize method, so it get called once the ISR is completed. It does not reflect the UARTS Line status register from what I can tell. I think the only way to do it reliably is to write a driver that does not use ISR's.

                              J Offline
                              J Offline
                              Jochen Arndt
                              wrote on last edited by
                              #14

                              You are right. The event is signaled when the last data byte has been copied from the TX buffer (transmitter holding register) to the transmit line register. What you need is the transmitter holding register and transmitter line register empty status. This is indicated by bit 6 of the line status register. Unfortunately, this event is not supported by the Windows SDK. If you can live with a wait function, you may use the EV_TXEMPTY event and wait until the data byte has been trasnmitted (start + parity + data + stop) / baud. Because transmission is done by the UART hardware, the time is constant .

                              A 1 Reply Last reply
                              0
                              • J Jochen Arndt

                                You are right. The event is signaled when the last data byte has been copied from the TX buffer (transmitter holding register) to the transmit line register. What you need is the transmitter holding register and transmitter line register empty status. This is indicated by bit 6 of the line status register. Unfortunately, this event is not supported by the Windows SDK. If you can live with a wait function, you may use the EV_TXEMPTY event and wait until the data byte has been trasnmitted (start + parity + data + stop) / baud. Because transmission is done by the UART hardware, the time is constant .

                                A Offline
                                A Offline
                                Andrew Pearson
                                wrote on last edited by
                                #15

                                Had another idea. The Line Status Register is sent when IOCTL_SERIAL_LSRMST_INSERT is used, and this IS the actual UART Line Status Register. Bit 6 of the LSR, THR is empty, and line is idle, looks like it may be interesting. Will try this out today.

                                1 Reply Last reply
                                0
                                Reply
                                • Reply as topic
                                Log in to reply
                                • Oldest to Newest
                                • Newest to Oldest
                                • Most Votes


                                • Login

                                • Don't have an account? Register

                                • Login or register to search.
                                • First post
                                  Last post
                                0
                                • Categories
                                • Recent
                                • Tags
                                • Popular
                                • World
                                • Users
                                • Groups