-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathuart-using-arduino-gpio.html
168 lines (167 loc) · 12 KB
/
uart-using-arduino-gpio.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
<html>
<head>
<title>Napster's Experiments with Freedom</title>
<link rel="stylesheet" type="text/css" href="http://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.7.0/styles/xt256.min.css">
<script src="http://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.7.0/highlight.min.js"></script>
<script>hljs.initHighlightingOnLoad();</script>
<script type="text/javascript" src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
<link rel="stylesheet" type="text/css" href="css/post.css">
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-20813670-9', 'auto');
ga('send', 'pageview');
</script>
</head>
<body><h1 id="uart-using-arduino-gpio">UART Using Arduino GPIO</h1>
<p>This weekend I tried using an Arduino to do UART communication using the <a href="https://www.arduino.cc/en/Reference/DigitalWrite">digitalWrite()</a> and the <a href="https://www.arduino.cc/en/Reference/DelayMicroseconds">delayMicroSeconds()</a> methods provided by the Arduino library. My primary goal was to find out if I can simulate the working of any simple serial communication libraries, simply by using GPIO pins and artificial delays. Before getting into the experiment, here is some basic information about UART. Universal Asynchronous Receive Transmit is basically the simplest form of serial communication in comparison with I2C or other such comparable methods. UART at a minimum needs 2 wires to establish a communication, namely an RX or TX and a Ground (GND). If you send something through the TX line, the receiver should be able to receive the data at their RX pin, and vice versa. Generally the TX line is kept high, and a LOW (digital zero) with reasonable width is sent to denote the start of data transmission. Similarly, you may send one or two HIGH (digital one) to denote the end of transmission as well. Additionally, there is one bit called parity bit, which can be sent right before the stop bits, and this parity bit can be used for a very rudimentary error checking. You may read more about how parity bit works <a href="https://en.wikipedia.org/wiki/Parity_bit">here</a>. For the rest of the experiment, I’m not using parity bit. The following image explains this in detail.</p>
<p><img src="images/uart-basic.png"></p>
<p>As you have notices, the receiver uses a sampling clock, which is generally running at 10 to 16 times the frequency of incoming data. Which means, the receiver samples at least 10 to 16 times during the period of one bit. Now, to achieve a similar waveform using Arduino, I need to select one output pin, and write digital HIGH and digital LOW with proper delays in between. For simplicity, the data I’m planning to send is nothing but english character <code>A</code>. The capital <code>A</code> is in ASCII terms, represented as integer <code>65</code>. Step number one is to convert this to hexadecimal, <code>65</code> —> <code>0x41</code> —> <code>0100 0001</code>. Now, this data needs to be sent in a particular order. As you may have noticed in the above image, the most significant bit (MSB) is sent at the end of the signal, and the least significant bit (LSB) is sent first. So after re-ordering, the data we need to send looks like <code>1000 0010</code>. Lets look into the program I have written now.</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode c"><code class="sourceCode c"><a class="sourceLine" id="cb1-1" data-line-number="1"><span class="co">/**</span></a>
<a class="sourceLine" id="cb1-2" data-line-number="2"><span class="co"> * A -> 65 -> 1000001 -> 0100-0001 -> 0x41</span></a>
<a class="sourceLine" id="cb1-3" data-line-number="3"><span class="co"> * Data -> 0-0100-0001-1</span></a>
<a class="sourceLine" id="cb1-4" data-line-number="4"><span class="co"> * In serial we should send least significant bit first -> so -> 0-1000-0010-11</span></a>
<a class="sourceLine" id="cb1-5" data-line-number="5"><span class="co"> */</span></a>
<a class="sourceLine" id="cb1-6" data-line-number="6"></a>
<a class="sourceLine" id="cb1-7" data-line-number="7"><span class="dt">int</span> output = <span class="dv">13</span>;</a>
<a class="sourceLine" id="cb1-8" data-line-number="8"><span class="dt">int</span> delayd = <span class="dv">3333</span>;</a>
<a class="sourceLine" id="cb1-9" data-line-number="9"></a>
<a class="sourceLine" id="cb1-10" data-line-number="10"><span class="dt">void</span> setup() {</a>
<a class="sourceLine" id="cb1-11" data-line-number="11"> pinMode(output, OUTPUT);</a>
<a class="sourceLine" id="cb1-12" data-line-number="12">}</a>
<a class="sourceLine" id="cb1-13" data-line-number="13"></a>
<a class="sourceLine" id="cb1-14" data-line-number="14"><span class="dt">void</span> loop() {</a>
<a class="sourceLine" id="cb1-15" data-line-number="15"></a>
<a class="sourceLine" id="cb1-16" data-line-number="16"> delay(<span class="dv">1000</span>);</a>
<a class="sourceLine" id="cb1-17" data-line-number="17"></a>
<a class="sourceLine" id="cb1-18" data-line-number="18"> <span class="dt">int</span> data[] = { <span class="dv">1</span>, <span class="dv">0</span>, <span class="dv">0</span>, <span class="dv">0</span>, <span class="dv">0</span>, <span class="dv">0</span>, <span class="dv">1</span>, <span class="dv">0</span> };</a>
<a class="sourceLine" id="cb1-19" data-line-number="19"></a>
<a class="sourceLine" id="cb1-20" data-line-number="20"> <span class="co">//</span></a>
<a class="sourceLine" id="cb1-21" data-line-number="21"> <span class="co">// Start Bit</span></a>
<a class="sourceLine" id="cb1-22" data-line-number="22"> <span class="co">//</span></a>
<a class="sourceLine" id="cb1-23" data-line-number="23"></a>
<a class="sourceLine" id="cb1-24" data-line-number="24"> digitalWrite(output, LOW); <span class="co">// Start Bit</span></a>
<a class="sourceLine" id="cb1-25" data-line-number="25"> delayMicroseconds(delayd);</a>
<a class="sourceLine" id="cb1-26" data-line-number="26"></a>
<a class="sourceLine" id="cb1-27" data-line-number="27"> <span class="co">//</span></a>
<a class="sourceLine" id="cb1-28" data-line-number="28"> <span class="co">// Data</span></a>
<a class="sourceLine" id="cb1-29" data-line-number="29"> <span class="co">//</span></a>
<a class="sourceLine" id="cb1-30" data-line-number="30"> </a>
<a class="sourceLine" id="cb1-31" data-line-number="31"> <span class="cf">for</span>(<span class="dt">int</span> i = <span class="dv">0</span>; i < <span class="dv">8</span>; i++) {</a>
<a class="sourceLine" id="cb1-32" data-line-number="32"> <span class="cf">if</span>(data[i] == <span class="dv">1</span>) {</a>
<a class="sourceLine" id="cb1-33" data-line-number="33"> digitalWrite(output, HIGH);</a>
<a class="sourceLine" id="cb1-34" data-line-number="34"> } <span class="cf">else</span> {</a>
<a class="sourceLine" id="cb1-35" data-line-number="35"> digitalWrite(output, LOW);</a>
<a class="sourceLine" id="cb1-36" data-line-number="36"> }</a>
<a class="sourceLine" id="cb1-37" data-line-number="37"> delayMicroseconds(delayd);</a>
<a class="sourceLine" id="cb1-38" data-line-number="38"> }</a>
<a class="sourceLine" id="cb1-39" data-line-number="39"></a>
<a class="sourceLine" id="cb1-40" data-line-number="40"> <span class="co">//</span></a>
<a class="sourceLine" id="cb1-41" data-line-number="41"> <span class="co">// Stop bit</span></a>
<a class="sourceLine" id="cb1-42" data-line-number="42"> <span class="co">//</span></a>
<a class="sourceLine" id="cb1-43" data-line-number="43"></a>
<a class="sourceLine" id="cb1-44" data-line-number="44"> digitalWrite(output, HIGH); <span class="co">// Stop bit</span></a>
<a class="sourceLine" id="cb1-45" data-line-number="45"> delayMicroseconds(delayd);</a>
<a class="sourceLine" id="cb1-46" data-line-number="46"> </a>
<a class="sourceLine" id="cb1-47" data-line-number="47">}</a>
<a class="sourceLine" id="cb1-48" data-line-number="48"></a>
<a class="sourceLine" id="cb1-49" data-line-number="49"><span class="co">/**</span></a>
<a class="sourceLine" id="cb1-50" data-line-number="50"><span class="co"> * 1 bit stays for 1/1000 sec -> 1000 bits / sec</span></a>
<a class="sourceLine" id="cb1-51" data-line-number="51"><span class="co"> */</span></a></code></pre></div>
<p>This is fairly simple. But, you may be wondering why I have chosen the <code>delays = 3333</code>. This is based on the following table.</p>
<p><img src="images/uart-common-speeds.png"></p>
<p>Now, this table will come handy down the line. If we reduce the delay between each bits, we can achieve higher data rates. I have compiled this program, and deployed to Arduino. Lets see the output for a second.</p>
<p><img src="images/uart-sending-a.png"></p>
<p>This is pretty decent. Now, lets try hooking it back to a serial port device (I run a laptop without an actual serial port, so I would just use one of the UART to USB adapter I have discussed in an <a href="http://xtel.in/usb-to-serial-adapters-comparison.html">earlier article</a>).</p>
<p><img src="images/uart-setup.jpg"></p>
<p>As you can see in the above image, my setup is pretty simple. One USB is connected to the Arduino, which sends data, and the data is received at a serial adaptor which is connected to the USB port on the other side. Now, simply look at the data coming from the serial adapter using CoolTerm.</p>
<p><img src="images/uart-coolterm.png"></p>
<p>Things are butter smooth so far. Now, lets try achieving higher data rates. I’m going to go step by step by reducing width of each bit. Here is my result as a table.</p>
<table>
<colgroup>
<col style="width: 14%">
<col style="width: 11%">
<col style="width: 8%">
<col style="width: 65%">
</colgroup>
<thead>
<tr class="header">
<th>Data Rate</th>
<th>delayd</th>
<th>Error</th>
<th>Notes</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>300 b/s</td>
<td>3333 us</td>
<td>NO</td>
<td></td>
</tr>
<tr class="even">
<td>600 b/s</td>
<td>1667 us</td>
<td>NO</td>
<td></td>
</tr>
<tr class="odd">
<td>1200 b/s</td>
<td>833 us</td>
<td>NO</td>
<td></td>
</tr>
<tr class="even">
<td>2400 b/s</td>
<td>417 us</td>
<td>NO</td>
<td></td>
</tr>
<tr class="odd">
<td>4800 b/s</td>
<td>208 us</td>
<td>NO</td>
<td></td>
</tr>
<tr class="even">
<td>9600 b/s</td>
<td>104 us</td>
<td>NO</td>
<td></td>
</tr>
<tr class="odd">
<td>14400 b/s</td>
<td>69 us</td>
<td>NO</td>
<td></td>
</tr>
<tr class="even">
<td>19200 b/s</td>
<td>52 us</td>
<td>YES</td>
<td>It starts to send/receive/interpret incorrect data <code>0x81</code> in between from this point onward.</td>
</tr>
<tr class="odd">
<td>38400 b/s</td>
<td>26 us</td>
<td>YES</td>
<td>Constantly receives <code>0x81</code> instead of <code>0x41</code>.</td>
</tr>
</tbody>
</table>
<p>Looks like there is some tiny timing issues from this point onward. Also the <a href="https://en.wikipedia.org/wiki/Ringing_(signal)">ringing</a> may be causing some issues, I don’t know for sure.</p>
<p><img src="images/uart-ringing.png"></p>
<p>Anyway, it looks like <code>14400 bits/second</code> is the highest achievable data rate with an Arduino UNO/Duemilanove with simple digitalWrite() and delayMicroSeconds() methods. I will look into this in depth and will update, if I could reach a conclusive finding, and a higher data rate with the same setup.</p>
<div id="disqus_thread"></div>
<script type="text/javascript">
var disqus_shortname = 'subinsebastien';
(function() {
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
})();
</script>
</body>
</html>