Sign in Join
Wiki copytemporary

AVR Embedded Tutorial - I²C, TWI: what changed

Revision 1 to 2. Removed lines have a minus sign; added lines have a plus sign.

OldNewLine
11# I²C / TWI
22
33This code is for an Atmega328/Arduino with 16MHz clock.
44
55How to control the UART can be found here: [[AVR Embedded Tutorial - UART|UARTInit and UARTSendString (...]]
66
77## Description
88
99This example demonstrates the communication with the I²C/TWI interface.
1010
1111Two AD1115 A/D converters are used as slave devices. These are very easy to use and are also very easy to obtain. What is very important is that with TWIStart you shift the address one bit to the left and then combine it with *or* using Write/Read. There are many tutorials on this.
1212
1313PulUp resistors are not necessary because they are already installed on the ADS1115 board (**Caution**: check *your* board for pullup resistors).
1414
1515## I²C functions
1616
1717### Constants
1818
1919``` pascal
2020 const
2121 CPU_Clock = 16000000; // Arduino clock frequency, default 16MHz.
2222 ADSaddr0 = $48; // Address converter 0
2323 ADSaddr1 = $49; // Address converter 1
2424 I2C_clock = 400000; // I²C clock (400KHz)
2525 TWI_Write = 0;
2626 TWI_Read = 1;
2727```
2828
2929### Initialize I²C
3030
3131``` pascal
3232 procedure TWIInit;
3333 const
3434 TWBR_val = byte((CPU_Clock div I2C_clock) - 16) div 2;
3535 begin
3636 TWSR := 0;
3737 TWBR := byte(TWBR_val);
3838 end;
3939```
4040
4141### Start I²C send/receive
4242
4343``` pascal
4444 procedure TWIStart(addr : byte);
4545 begin
4646 // Initiate sending / receiving
4747 TWCR := 0;
4848 TWCR := (1 shl TWINT) or (1 shl TWSTA) or (1 shl TWEN);
4949
5050 while ((TWCR and (1 shl TWINT)) = 0) do
5151 begin
5252 end;
5353
5454 // Send the address of the end device
5555 TWDR := addr;
5656 TWCR := (1 shl TWINT) or (1 shl TWEN);
5757
5858 while((TWCR and (1 shl TWINT)) = 0) do
5959 begin
6060 end;
6161 end;
6262```
6363
6464### I²C transmission / reception ended
6565
6666``` pascal
6767 procedure TWIStop ;
6868 begin
6969 TWCR := (1 shl TWINT) or (1 shl TWSTO) or (1 shl TWEN);
7070 end;
7171```
7272
7373### Send characters
7474
7575``` pascal
7676 procedure TWIWrite(u8data : byte);
7777 begin
7878 TWDR := u8data;
7979 TWCR := (1 shl TWINT) or (1 shl TWEN);
8080
8181 while((TWCR and (1 shl TWINT)) = 0) do
8282 begin
8383 end;
8484 end;
8585```
8686
8787### Receive characters
8888
8989Except for the last character, characters must be read with **TWIReadACK (...**. The last character must be read with **TWIReadNACK(...**
9090
9191``` pascal
9292 // Read to the penultimate character.
9393 function TWIReadACK : byte;
9494 begin
9595 TWCR := (1 shl TWINT) or (1 shl TWEN) or (1 shl TWEA);
9696
9797 while (TWCR and (1 shl TWINT)) = 0 do
9898 begin
9999 end;
100100
101101 Result := TWDR;
102102 end;
103103
104104 // read last character.
105105 function TWIReadNACK : byte ;
106106 begin
107107 TWCR := (1 shl TWINT) or (1 shl TWEN);
108108
109109 while(TWCR and (1 shl TWINT)) = 0 do
110110 begin
111111 end;
112112
113113 Result := TWDR;
114114 end;
115115```
116116
117117> **Note:** These functions get stuck in the event of a hardware error or the slave address is wrong!
118118
119119### Character received with error query
120120
121121So that these functions do not get stuck, you have to install a counter in the while loop.
122122
123123When the counter reaches 255, the loop is interrupted and an error is output.
124124
125125255 is reached if no device is found at the I²C address.
126126
127127``` pascal
128128 // Read to the penultimate character.
129129 function TWIReadACK_Error : byte;
130130 var
131131 err : byte;
132132 begin
133133 err := 0;
134134 TWCR := (1 shl TWINT) or (1 shl TWEN) or (1 shl TWA);
135135
136136 while ((TWCR and (1 shl TWINT)) = 0) and (err < 255) do
137137 begin
138138 Inc(err);
139139 end;
140140
141141 if err = 255 then
142142 begin
143143 UARTSendString('I²C-Timeout');
144144 Result := 0;
145145 end
146146 else
147147 begin
148148 Result := TWDR;
149149 end;
150150 end;
151151
152152 // read last character.
153153 function TWIReadNACK_Error : byte;
154154 var
155155 err : byte;
156156 begin
157157 err := 0;
158158 TWCR := (1 shl TWINT) or (1 shl TWEN);
159159
160160 while((TWCR and (1 shl TWINT)) = 0) and (err < 255) do
161161 begin
162162 Inc(err);
163163 end;
164164
165165 if err = 255 then
166166 begin
167167 UARTSendString('I²C-Timeout');
168168 Result := 0;
169169 end
170170 else
171171 begin
172172 Result := TWDR;
173173 end;
174174 end;
175175```
176176
177177## ADS1115 specific code
178178
179179This code is ADS1115 specific, for other I²C devices you will have to check their data sheets.
180180
181181``` pascal
182182 // Send parameters to ADS1115 and initiate measurement
183183 procedure WriteADS1115(addr : UInt16);
184184 begin
185185 TWIStart((addr shl 1) or TWI_Write);
186186 TWIWrite(1);
187187 TWIWrite(%11000011); // High
188188 TWIWrite(%11100011); // low
189189 TWIStop;
190190 end;
191191
192192 // Read out measurement from ADS1115.
193193 function ReadADS1115(addr : UInt16) : UInt16;
194194 begin
195195 TWIStart((addr shl 1) or TWI_Write);
196196 TWIWrite(0);
197197 TWIStop;
198198
199199 TWIStart((addr shl 1) or TWI_Read);
200200 Result := TWIReadACK * $100 + TWIReadNACK;
201201 TWIStop;
202202 end;
203203```
204204
205205## Example
206206
207207``` pascal
208208 var
209209 Data : Integer;
210210 s : ShortString;
211211
212212 begin
213213 asm cli end ; // block interrupt
214214 UARTInit;
215215 TWIInit;
216216 asm be end; // release interrupt
217217
218218 repeat
219219 WriteADS1115(ADSaddr0);
220220 Data := ReadADS1115(ADSaddr0);
221221
222222 str(Data : 6, s);
223223 UARTSendString('Channel 0:');
224224 UARTSendString(s);
225225
226226 WriteADS1115(ADSaddr1);
227227 Data := ReadADS1115(ADSaddr1);
228228
229229 str(Data : 6, s);
230230 UARTSendString('Channel 1:');
231231 UARTSendString(s);
232232 UARTSendString(#13#10);
233233 until 1 = 2;
234234 end.
235235```
236236
237237## ADS1115 parameters
238238
239239A list of the parameters for the ADS1115. More information is in the data sheet.
240240
241241Bit assignment of the ADS1115:
242242
243243**Low:** 11100011 **High:** 11000011
244244
245-<table>
246245<thead>
247-<tr>
248-<th>Bit</th>
249-<th>Name</th>
250-<th>Description</th>
251-</tr>
246+
252247</thead>
253248<tbody>
254-<tr>
255-<td>15</td>
256-<td><strong>OS:</strong> Operational status or single-shot conversion start</td>
257-<td><strong>0</strong> : no effect<br />
249+
258250<strong>1</strong> : Start a single conversion (when in power-down state)</td>
259-</tr>
260-<tr>
261-<td>14:12</td>
262-<td><strong>MUX[2:0]:</strong> Input multiplexer configuration (ADS1115 only)</td>
263-<td><strong>000</strong> : AINP = AIN0 and AINN = AIN1 (default)<br />
251+
264252<strong>001</strong> : AINP = AIN0 and AINN = AIN3<br />
265253<strong>010</strong> : AINP = AIN1 and AINN = AIN3<br />
266254<strong>011</strong> : AINP = AIN2 and AINN = AIN3<br />
267255<strong>100</strong> : AINP = AIN0 and AINN = GND<br />
268256<strong>101</strong> : AINP = AIN1 and AINN = GND<br />
269257<strong>110</strong> : AINP = AIN2 and AINN = GND<br />
270258<strong>111</strong> : AINP = AIN3 and AINN = GND</td>
271-</tr>
272-<tr>
273-<td>11:9</td>
274-<td><strong>PGA[2:0]:</strong>Programmable gain amplifier configuration</td>
275-<td><strong>000</strong> : FSR = ±6.144 V<br />
259+
276260<strong>001</strong> : FSR = ±4.096 V<br />
277261<strong>010</strong> : FSR = ±2.048 V (default)<br />
278262<strong>011</strong> : FSR = ±1.024 V<br />
279263<strong>100</strong> : FSR = ±0.512 V<br />
280264<strong>101</strong> : FSR = ±0.256 V<br />
281265<strong>110</strong> : FSR = ±0.256 V<br />
282266<strong>111</strong> : FSR = ±0.256 V<br />
283-</td>
284-</tr>
285-<tr>
286-<td>8</td>
287-<td><strong>MODE:</strong> Device operating mode</td>
288-<td><strong>0</strong> : Continuous-conversion mode<br />
267+
289268<strong>1</strong> : Single-shot mode or power-down state (default)</td>
290-</tr>
291-<tr>
292-<td>7:5</td>
293-<td><strong>DR[2:0]:</strong> Data rate</td>
294-<td><strong>000</strong> : 8 SPS<br />
269+
295270<strong>001</strong> : 16 SPS<br />
296271<strong>010</strong> : 32 SPS<br />
297272<strong>011</strong> : 64 SPS<br />
298273<strong>100</strong> : 128 SPS (default)<br />
299274<strong>101</strong> : 250 SPS<br />
300275<strong>110</strong> : 475 SPS<br />
301276<strong>111</strong> : 860 SPS<br />
302-</td>
303-</tr>
304-<tr>
305-<td>4</td>
306-<td><strong>COMP_MODE:</strong> Comparator mode</td>
307-<td><strong>0</strong> : Traditional comparator (default)<br />
277+
308278<strong>1</strong> : Window comparator</td>
309-</tr>
310-<tr>
311-<td>3</td>
312-<td><strong>COMP_POL:</strong> Comparator polarity</td>
313-<td><strong>0</strong> : Active low (default)<br />
279+
314280<strong>1</strong> : Active high</td>
315-</tr>
316-<tr>
317-<td>2</td>
318-<td><strong>COMP_LAT:</strong> Latching comparator</td>
319-<td><strong>0</strong> : Nonlatching comparator (default)<br />
281+
320282<strong>1</strong> : Latching comparator</td>
321-</tr>
322-<tr>
323-<td>1:0</td>
324-<td><strong>COMP_QUE[1:0]:</strong> Comparator queue and disable</td>
325-<td><strong>00</strong> : Assert after one conversion<br />
283+
326284<strong>01</strong> : Assert after two conversions<br />
327285<strong>10</strong> : Assert after four conversions<br />
328286<strong>11</strong> : Disable comparator and set ALERT/RDY pin to high-impedance (default)</td>
329-</tr>
287+
330288</tbody>
331-</table>
332289
333290# See also
334291
335292- Overview page - [[AVR Embedded Tutorial]]
336293
337294---
338295*From the Free Pascal wiki, page "AVR Embedded Tutorial - I²C, TWI", as it stood on 2020-03-06 after a change by Trev, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history