Sign in Join
Wiki copytemporary

AVR Embedded Tutorial - Software I2C, TWI: what changed

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

Title: AVR Embedded Tutorial - Software I2C, TWI

OldNewLine
1+# Software I2C / TWI for ATmega328 / Arduino
2+
3+Many AVR controllers offer a hardware I2C interface. Sometimes you need an I2C interface on other pins, or several I2C interfaces. Software I2C helps in these situations.
4+
5+For the basics of I2C see this WikiPedia [article](https://de.wikipedia.org/wiki/I2c).
6+
7+# TWI Master software
8+
9+## TWI header
10+
11+The pins for SCL and SDA can be set as desired, but must all be on one port. For pins on different ports, the pin accesses have to be adjusted in the following routines.
12+
13+``` pascal
14+ unit test_twi;
15+
16+ {$mode objfpc}
17+ {$goto on}
18+
19+ interface
20+
21+ uses
22+ ;
23+
24+ procedure twi_start();
25+ procedure twi_stop();
26+
27+ function twi_write(data : uint8) : boolean;
28+ function twi_readbyte(ackn : boolean) : uint8;
29+ function twi_readword(ackn : boolean) : uint16;
30+
31+ const
32+ Psclin = 1 shl 5; // PC5 any pins, but on the same port
33+ Psdain = 1 shl 4; // PC4
34+
35+ var
36+ DDRtwi : byte absolute DDRC; // TWI pins on port C
37+ PRTtwi : byte absolute PORTC;
38+ PINtwi : byte absolute PINC;
39+
40+ implementation
41+```
42+
43+## Delays
44+
45+The clock rate is adjusted over the duration of the delays, the numbers after **ldi r16**. Inline assembler does not allow comments here and for timing reasons the values ​​should be entered directly and not passed as variables.
46+
47+With the given values ​​9 and 10, a clock rate of 100kHz results at 8MHz clock frequency, with 59 and 60 a clock rate of 10kHz can be used for long data lines.
48+
49+``` pascal
50+ // pause TWI delays
51+
52+ procedure delay2();
53+ label
54+ loop;
55+ begin
56+ asm
57+ ldi r16, 9
58+ loop:
59+ dec r16
60+ brne loop
61+ end['r16'];
62+ end;
63+
64+ procedure delay3();
65+ label
66+ loop;
67+ begin
68+ asm
69+ ldi r16, 10
70+ loop:
71+ dec r16
72+ brne loop
73+ end['r16'];
74+ end;
75+```
76+
77+## TWI start
78+
79+The start sequence for a transmission.
80+
81+``` pascal
82+ // Start TWI
83+
84+ procedure twi_start();
85+ begin
86+ DDRtwi := DDRtwi or Psdain; // SDA low
87+ delay3();
88+ DDRtwi := DDRtwi or Psclin; // SCL low
89+ delay3();
90+ end;
91+```
92+
93+## TWI stop
94+
95+The stop sequence. For a restart, as required by some data sheets, you simply use a stop sequence followed by a start sequence.
96+
97+``` pascal
98+ // TWI stop sequence
99+
100+ procedure twi_stop();
101+ begin
102+ DDRtwi := DDRtwi or Psdain; // SDA low
103+ delay3();
104+ DDRtwi := DDRtwi and (not Psclin); // SCL high
105+ delay3();
106+ DDRtwi := DDRtwi and (not Psdain); // SDA high
107+ delay3();
108+ end;
109+```
110+
111+## Write TWI byte
112+
113+Hand over byte and go. Duration is about 10x cycle time, that is 100µsec at 100kHz. The routine may be interrupted by interrupts, the slave then waits.
114+
115+``` pascal
116+ // Write TWI byte
117+
118+ function twi_write(data : uint8) : boolean;
119+ var
120+ i : uint8;
121+ begin
122+ for i := 0 to 7 do // output 8 bits
123+ begin
124+ if(data and (1 shl 7)) <> 0 then
125+ DDRtwi := DDRtwi and (not Psdain) // SDA high if bit is set
126+ else
127+ DDRtwi := DDRtwi or Psdain; // SDA low if bit is not set
128+
129+ data := data shl 1; // shift bit, 7 to 0
130+ delay2();
131+ DDRtwi := DDRtwi and (not Psclin); // SCL high
132+ delay3();
133+ DDRtwi := DDRtwi or Psclin; // SCL low
134+ end;
135+
136+ DDRtwi := DDRtwi and (not Psdain); // SDA high
137+ delay2();
138+ DDRtwi := DDRtwi and (not Psclin); // SCL high
139+ delay2();
140+
141+ if(PINtwi and Psdain) = 0 then // test SDA on Acknowledge low
142+ twi_write := true // set ack flag
143+ else
144+ twi_write := false; // otherwise unset ack flag
145+
146+ DDRtwi := DDRtwi or Psclin; // SCL low
147+ end;
148+```
149+
150+## Read TWI data byte
151+
152+``` pascal
153+ // read TWI byte
154+
155+ function twi_readbyte(ackn : boolean) : uint8;
156+ var
157+ data : uint8 = 0;
158+ i : uint8;
159+ begin
160+ for i := 0 to 7 do // output 8 bits
161+ begin
162+ data := data shl 1; // shift bit, 7 to 0
163+ delay2();
164+ DDRtwi := DDRtwi and (not Psclin); // SCL high
165+ delay2();
166+
167+ if(PINtwi and (Psdain)) <> 0 then // test SDA on high
168+ data := data or (1 shl 0); // if high, set bit 0
169+
170+ DDRtwi := DDRtwi or Psclin; // SCL low
171+ end;
172+
173+ if ackn then
174+ DDRtwi := DDRtwi or Psdain // SDA low, acknowledge
175+ else
176+ DDRtwi := DDRtwi and (not Psdain); // SDA high, no acknowledge
177+
178+ delay2();
179+ DDRtwi := DDRtwi and (not Psclin); // SCL high
180+ delay3();
181+ DDRtwi := DDRtwi or Psclin; // SCL low
182+ DDRtwi := DDRtwi and (not Psdain); // SDA high
183+
184+ twi_readbyte := data; // return data
185+ end;
186+```
187+
188+## Read TWI data word
189+
190+``` pascal
191+ // Read TWI Word, MSB + LSB
192+
193+ function twi_readword(ackn : boolean ) : uint16;
194+ var
195+ data : uint16 = 0;
196+ i : uint8;
197+ begin
198+ for i := 0 to 7 do // output 8 bits
199+ begin
200+ data := data shl 1; // shift bit, 7 to 0
201+ delay2();
202+ DDRtwi := DDRtwi and (not Psclin); // SCL high
203+ delay2();
204+
205+ if(PINtwi and (Psdain)) <> 0 then // test SDA on high
206+ data := data or (1 shl 0); // if high, set bit 0
207+
208+ DDRtwi := DDRtwi or Psclin; // SCL low
209+ end;
210+
211+ DDRtwi := DDRtwi or Psdain; // SDA low, acknowledge
212+ delay2();
213+ DDRtwi := DDRtwi and (not Psclin); // SCL high
214+ delay3();
215+ DDRtwi := DDRtwi or Psclin; // SCL low
216+ DDRtwi := DDRtwi and (not Psdain); // SDA high
217+
218+ for i := 0 to 7 do // output 8 bits
219+ begin
220+ data := data shl 1; // shift bit, 7 to 0
221+ delay2();
222+ DDRtwi := DDRtwi and (not Psclin); // SCL high
223+ delay2();
224+
225+ if(PINtwi and (Psdain)) <> 0 then // test SDA on high
226+ data := data or (1 shl 0); // if high, set bit 0
227+
228+ DDRtwi := DDRtwi or Psclin; // SCL low
229+ end;
230+
231+ if ackn then
232+ DDRtwi := DDRtwi or Psdain // SDA low, acknowledge
233+ else
234+ DDRtwi := DDRtwi and (not Psdain); // SDA high, no acknowledge
235+
236+ delay2();
237+ DDRtwi := DDRtwi and (not Psclin); // SCL high
238+ delay3();
239+ DDRtwi := DDRtwi or Psclin; // SCL low
240+ DDRtwi := DDRtwi and (not Psdain); // SDA high
241+
242+ twi_readword := data; // return data
243+ end;
244+```
245+
246+## End
247+
248+The unit is completed with the following line.
249+
250+``` pascal
251+ end.
252+```
253+
254+# See also
255+
256+- Overview page - [[AVR Embedded Tutorial]]
257+
258+---
259+*From the Free Pascal wiki, page "AVR Embedded Tutorial - Software I2C, TWI", as it stood on 2020-03-07 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