----- /-------------\-/-------------\-/-------------\-/---- | start bit / data bit 0 X data bit 1 X data bit 2 X |--------------/---------------/-\-------------/-\-------------/-\---- ------ /-------------\-/-------------\-/-------------\-/---- | start bit / data bit 0 X data bit 1 X data bit 2 X |--------------/---------------/-\-------------/-\-------------/-\---- | | | | 0000000000111111111122222222223333333333444444444455555555556666666666 0123456789012345678901234567890123456789012345678901234567890123456789 ^ ^ ^ ^ start bit detected first data bit subsequent data within first 1/16 bit sampled 24 bits sampled every time of leading edge intervals later 16 sample intervals thereafterMost UARTs will actually sample the middle of the start bit (eight sample periods after the leading edge is recognized) and verify that it is low in case the detected leading edge was just a glitch. Some UARTs will also take multiple samples in the middle of the bit time (i.e, at 23, 24, and 25 in the diagram above) and set error flags for noise if they don't all match. Many application notes on implementing software UARTs, including the Microchip ap notes, suggest sampling at two times the bit rate. This results in the following:
----- /-------------\-/-------------\-/-------------\-/---- | start bit / data bit 0 X data bit 1 X data bit 2 X |--------------/---------------/-\-------------/-\-------------/-\---- ------------- /-------------\-/-------------\-/-------------\- | start bit / data bit 0 X data bit 1 X data bit 2 X |--------------/---------------/-\-------------/-\-------------/- | | | | | 0 1 2 3 4 5 6 7 8 ^ ^ ^ ^ ^ start bit detected first data bit subsequent data within first 1/2 bit sampled 2 bits sampled every time of leading edge intervals later 2 sample intervals thereafterThis results in a 1/2 bit time uncertainty regarding when the start bit actually arrived. As a consequence the data bit sampling can occur any time within the first half of the data bit, including right at the leading edge. This allows no margin for rate mismatch. An alternative would be to sample the first data bit three sample periods after the start bit is detected, and every two sample periods thereafter. This is no better as the window is then from the middle to the end of the data bit, so the bits could be sampled right at the trailing edge, again allowing no margin for rate mismatch. The Microchip ap note does at least suggest waiting 1.25 bit times from the leading edge of the start bit to sample the first data bit, which results in the sample window being in the middle 50% of the bit. That's great unless you want to do full duplex serial and use the same time base for transmit. Since you can't get a 1.25 bit time delay using a 0.5 bit time timebase, you maintain proper transmitter timing during that 1.25 bit time delay. The correct solution (IMHO) is to sample at 3 times the bit rate:
----- /------------\-/------------\-/------------\-/----------- | start bit / data bit 0 X data bit 1 X data bit 2 X |-------------/--------------/-\------------/-\------------/-\----------- ---------- /------------\-/------------\-/------------\-/------- | start bit / data bit 0 X data bit 1 X data bit 2 X |-------------/--------------/-\------------/-\------------/-\------- | | | | | 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 1 2 3 4 5 6 7 8 9 0 1 2 3 ^ ^ ^ ^ ^ start bit detected first data bit subsequent data within first 1/3 bit sampled 4 bits sampled every time of leading edge intervals later 3 sample intervals thereafterAs you can see, this reduces the uncertainty of the timing of the start bit to 1/3 of a bit time, and guarantees that the sampling of the data bits will occur within the middle 1/3 of the bit time, thus providing better tolerance to speed variation than the 1/2 bit time scheme provides (even with the 1.25 bit time delay). It also uses fewer CPU cycles than would be required to sample at 4 times the bit rate. I've implemented this scheme on a PIC16C84 and it seems to work quite well. I use the RTCC timer to generate interrupts at three times the bit rate, and the interrupt routine has simple receive and transmit state machines to do the work. I'll make the code available after I do some more testing.
Last updated June 5, 1995
Copyright 1995 Eric Smith