Abstract
In this article author considers aspects of implementing RS-232 communication routines in Microchip PIC microcontroller’s software, describes technique to achieve high speed (>=115200) of transmitting and receiving data, dwells on hardware (CTS/RTS) flow control and illustrates how assembler macro may be used to generate transmitter and receiver routines for any given speed at any given frequency. A sample application supplied with the article provides tests for transmitter and receiver routines for baud rates 230400, 115200, 56700 and 38400 at clock frequency 4 MHz.
Take-off run
The application I am developing needs to send data (2-3 bytes) to PC between events in the external environment. Time between two consecutive events does not allow using even 115200 baud. Speeding up the PIC definitely would not help and using a different protocol is not desirable. While configuring COM port, I have noticed that there are higher baud rates available: 230400, 460800, and 921600. I tried to test them in a terminal application, but it did not work, because, as it turned out, the original Windows driver does not allow selecting these speeds regardless of whether UART chip support them or no. I have searched the web and found alternative drivers [3] that enables higher baud rates supported by UART chip. Now the goal is to implement this speed in PIC. In which one? Most popular among hobbyists 16F84A would fit for this purpose.
Diving to bottom
Baud rate 230400 requires one bit to be 4.34 ?µs long with allowed up to ?± 20% derivation in waveform. Instruction cycle at 4 MHz is 1?µs log, thus, bit should be 4.34 cycles long. Unfortunately, PIC does not operate in fractional instruction cycles, so we have to round it. However, being rounded to 4 it brings cumulative error, which at bit 3 already gives 50% error and 75% per 8 bits. What possible options for handling this problem? Most obvious is speeding up PIC to 10MHz. Second option is slowing down to 3.68 MHz clock. Third option is to use unequal bit lengths.
Varying the length
Bit length requirement 4.34 ?µs ?± 20% allows some variation: 3.47 ??“ 5.21. So, to avoid cumulative error we may implement some bits as 4 cycles long and some others as 5. Table 1 shows which bits should be longer. This approach, (let’s name it bit aligning), gives maximum bit-timing error of 8.8%.
Table 1 . Bit lengths for 230400
Bit | Time | Cycle | Length |
Start | 4.34 | 4 | 4 |
0 | 8,68 | 9 | 5 |
1 | 13,02 | 13 | 4 |
2 | 17.36 | 17 | 4 |
3 | 21.70 | 22 | 5 |
4 | 26.04 | 26 | 4 |
5 | 30.38 | 30 | 4 |
6 | 34.72 | 35 | 5 |
7 | 39.06 | 39 | 4 |
Stop | 43.40 | 43 | 4 |
Driving the port
Next challenge is to drive port within 4 instructions. Most commonly used approach (roll data, test carry, branch to BSF or BCF) is too long to fit in 4 cycles. On PICLIST (see [1]) I found a brilliant idea suggested by Regulus Berdin. The core of his idea is to use XORWF PORT, F and to drive port only if level has to be changed. This requires the data byte to be prepared so it indicates level alternations instead of levels. He does it as simple as
rrf | data, W | ; prepare data for output: | |
|
xorwf | data, F | ; '1' in DATA means toggle port |
This code puts first data bit into carry (STATUS,C) while bits 0-6 in data indicate level alternations, which are used as the following:
btfsc | data, 1 | ; test data | |
xorwf | port, F | ; send bit |
There is no room left for any bit counting (which takes 3 cycles), so we cannot use a loop to send a byte. Instead we will use linear code (unrolled loop). But before we may start writing this routine we have to decide
To space or to mark
RS-232 protocol operates in terms of SPACE and MARK. SPACE is positive voltage, indicating logical 0. MARK is negative voltage indicating logical 1 and this is also an idle state of the interface lines. PIC cannot be directly connected to RS-232 lines, so there should be some intermediate hardware that converts TTL levels to RS-232. Depending on implementation, this hardware may either drive SPACE on level 0 or on level 1. Similarly, it may convert SPACE either to 0 or 1. For simplicity, we assume that SPACE is driven by logical 0.
Post a Comment