Skip to content

Commit e414202

Browse files
committed
Added support for repeated start conditions.
1 parent e5cc3c9 commit e414202

File tree

7 files changed

+213
-88
lines changed

7 files changed

+213
-88
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
namespace Raspberry.IO.InterIntegratedCircuit
2+
{
3+
using System;
4+
5+
public abstract class I2cAction
6+
{
7+
protected I2cAction(byte[] buffer)
8+
{
9+
if (buffer == null)
10+
{
11+
throw new ArgumentNullException("buffer");
12+
}
13+
14+
Buffer = buffer;
15+
}
16+
17+
public byte[] Buffer { get; private set; }
18+
}
19+
}

Raspberry.IO.InterIntegratedCircuit/I2cDeviceConnection.cs

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
namespace Raspberry.IO.InterIntegratedCircuit
22
{
3+
using System;
4+
35
/// <summary>
46
/// Represents a connection to the I2C device.
57
/// </summary>
@@ -39,14 +41,28 @@ public int DeviceAddress
3941
#endregion
4042

4143
#region Methods
44+
45+
/// <summary>
46+
/// Executes the specified transaction.
47+
/// </summary>
48+
/// <param name="transaction">The transaction.</param>
49+
public void Execute(I2cTransaction transaction)
50+
{
51+
if (transaction == null)
52+
{
53+
throw new ArgumentNullException("transaction");
54+
}
55+
56+
driver.Execute(deviceAddress, transaction);
57+
}
4258

4359
/// <summary>
4460
/// Writes the specified buffer.
4561
/// </summary>
4662
/// <param name="buffer">The buffer.</param>
4763
public void Write(params byte[] buffer)
4864
{
49-
driver.Write(deviceAddress, buffer);
65+
Execute(new I2cTransaction(new I2cWriteAction(buffer)));
5066
}
5167

5268
/// <summary>
@@ -55,7 +71,7 @@ public void Write(params byte[] buffer)
5571
/// <param name="value">The value.</param>
5672
public void WriteByte(byte value)
5773
{
58-
Write(value);
74+
Execute(new I2cTransaction(new I2cWriteAction(value)));
5975
}
6076

6177
/// <summary>
@@ -65,7 +81,10 @@ public void WriteByte(byte value)
6581
/// <returns>The buffer.</returns>
6682
public byte[] Read(int byteCount)
6783
{
68-
return driver.Read(deviceAddress, byteCount);
84+
var readAction = new I2cReadAction(new byte[byteCount]);
85+
Execute(new I2cTransaction(readAction));
86+
87+
return readAction.Buffer;
6988
}
7089

7190
/// <summary>

Raspberry.IO.InterIntegratedCircuit/I2cDriver.cs

Lines changed: 105 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -142,129 +142,149 @@ public I2cDeviceConnection Connect(int deviceAddress)
142142

143143
#region Internal Methods
144144

145-
internal void Write(int deviceAddress, byte[] buffer)
145+
/// <summary>
146+
/// Executes the specified transaction.
147+
/// </summary>
148+
/// <param name="deviceAddress">The address of the device.</param>
149+
/// <param name="transaction">The transaction.</param>
150+
internal void Execute(int deviceAddress, I2cTransaction transaction)
146151
{
147152
lock (driverLock)
148153
{
149-
EnsureDeviceAddress(deviceAddress);
154+
var control = bscAddress + (int)Interop.BCM2835_BSC_C;
155+
156+
foreach (I2cAction action in transaction.Actions)
157+
{
158+
if (action is I2cWriteAction)
159+
{
160+
Write(deviceAddress, action.Buffer);
161+
}
162+
else if (action is I2cReadAction)
163+
{
164+
Read(deviceAddress, action.Buffer);
165+
}
166+
else
167+
{
168+
throw new InvalidOperationException("Only read and write transactions are allowed.");
169+
}
170+
}
171+
172+
WriteUInt32Mask(control, Interop.BCM2835_BSC_S_DONE, Interop.BCM2835_BSC_S_DONE);
173+
}
174+
}
175+
176+
#endregion
150177

151-
var len = (uint) buffer.Length;
178+
#region Private Helpers
179+
180+
private void Write(int deviceAddress, byte[] buffer)
181+
{
182+
this.EnsureDeviceAddress(deviceAddress);
152183

153-
var dlen = bscAddress + (int) Interop.BCM2835_BSC_DLEN;
154-
var fifo = bscAddress + (int) Interop.BCM2835_BSC_FIFO;
155-
var status = bscAddress + (int) Interop.BCM2835_BSC_S;
156-
var control = bscAddress + (int) Interop.BCM2835_BSC_C;
184+
var len = (uint)buffer.Length;
157185

158-
var remaining = len;
159-
var i = 0;
186+
var dlen = this.bscAddress + (int)Interop.BCM2835_BSC_DLEN;
187+
var fifo = this.bscAddress + (int)Interop.BCM2835_BSC_FIFO;
188+
var status = this.bscAddress + (int)Interop.BCM2835_BSC_S;
189+
var control = this.bscAddress + (int)Interop.BCM2835_BSC_C;
160190

161-
// Clear FIFO
162-
WriteUInt32Mask(control, Interop.BCM2835_BSC_C_CLEAR_1, Interop.BCM2835_BSC_C_CLEAR_1);
191+
var remaining = len;
192+
var i = 0;
163193

164-
// Clear Status
165-
WriteUInt32(status, Interop.BCM2835_BSC_S_CLKT | Interop.BCM2835_BSC_S_ERR | Interop.BCM2835_BSC_S_DONE);
194+
// Clear FIFO
195+
WriteUInt32Mask(control, Interop.BCM2835_BSC_C_CLEAR_1, Interop.BCM2835_BSC_C_CLEAR_1);
166196

167-
// Set Data Length
168-
WriteUInt32(dlen, len);
197+
// Clear Status
198+
WriteUInt32(status, Interop.BCM2835_BSC_S_CLKT | Interop.BCM2835_BSC_S_ERR | Interop.BCM2835_BSC_S_DONE);
169199

170-
while (remaining != 0 && i < Interop.BCM2835_BSC_FIFO_SIZE)
200+
// Set Data Length
201+
WriteUInt32(dlen, len);
202+
203+
while (remaining != 0 && i < Interop.BCM2835_BSC_FIFO_SIZE)
204+
{
205+
WriteUInt32(fifo, buffer[i]);
206+
i++;
207+
remaining--;
208+
}
209+
210+
// Enable device and start transfer
211+
WriteUInt32(control, Interop.BCM2835_BSC_C_I2CEN | Interop.BCM2835_BSC_C_ST);
212+
213+
while ((ReadUInt32(status) & Interop.BCM2835_BSC_S_DONE) == 0)
214+
{
215+
while (remaining != 0 && (ReadUInt32(status) & Interop.BCM2835_BSC_S_TXD) != 0)
171216
{
217+
// Write to FIFO, no barrier
172218
WriteUInt32(fifo, buffer[i]);
173219
i++;
174220
remaining--;
175221
}
176222

177-
// Enable device and start transfer
178-
WriteUInt32(control, Interop.BCM2835_BSC_C_I2CEN | Interop.BCM2835_BSC_C_ST);
179-
180-
while ((ReadUInt32(status) & Interop.BCM2835_BSC_S_DONE) == 0)
181-
{
182-
while (remaining != 0 && (ReadUInt32(status) & Interop.BCM2835_BSC_S_TXD) != 0)
183-
{
184-
// Write to FIFO, no barrier
185-
WriteUInt32(fifo, buffer[i]);
186-
i++;
187-
remaining--;
188-
}
223+
this.Wait(remaining);
224+
}
189225

190-
Wait(remaining);
191-
}
226+
if ((SafeReadUInt32(status) & Interop.BCM2835_BSC_S_ERR) != 0) // Received a NACK
227+
throw new InvalidOperationException("Read operation failed with BCM2835_I2C_REASON_ERROR_NACK status");
228+
if ((SafeReadUInt32(status) & Interop.BCM2835_BSC_S_CLKT) != 0) // Received Clock Stretch Timeout
229+
throw new InvalidOperationException("Read operation failed with BCM2835_I2C_REASON_ERROR_CLKT status");
230+
if (remaining != 0) // Not all data is sent
231+
throw new InvalidOperationException(string.Format("Read operation failed with BCM2835_I2C_REASON_ERROR_DATA status, missing {0} bytes", remaining));
192232

193-
if ((SafeReadUInt32(status) & Interop.BCM2835_BSC_S_ERR) != 0) // Received a NACK
194-
throw new InvalidOperationException("Read operation failed with BCM2835_I2C_REASON_ERROR_NACK status");
195-
if ((SafeReadUInt32(status) & Interop.BCM2835_BSC_S_CLKT) != 0) // Received Clock Stretch Timeout
196-
throw new InvalidOperationException("Read operation failed with BCM2835_I2C_REASON_ERROR_CLKT status");
197-
if (remaining != 0) // Not all data is sent
198-
throw new InvalidOperationException(string.Format("Read operation failed with BCM2835_I2C_REASON_ERROR_DATA status, missing {0} bytes", remaining));
199-
200-
WriteUInt32Mask(control, Interop.BCM2835_BSC_S_DONE, Interop.BCM2835_BSC_S_DONE);
201-
}
202233
}
203234

204-
internal byte[] Read(int deviceAddress, int byteCount)
235+
private void Read(int deviceAddress, byte[] buffer)
205236
{
206-
lock (driverLock)
207-
{
208-
EnsureDeviceAddress(deviceAddress);
237+
this.EnsureDeviceAddress(deviceAddress);
209238

210-
var dlen = bscAddress + (int) Interop.BCM2835_BSC_DLEN;
211-
var fifo = bscAddress + (int) Interop.BCM2835_BSC_FIFO;
212-
var status = bscAddress + (int) Interop.BCM2835_BSC_S;
213-
var control = bscAddress + (int) Interop.BCM2835_BSC_C;
239+
var dlen = this.bscAddress + (int)Interop.BCM2835_BSC_DLEN;
240+
var fifo = this.bscAddress + (int)Interop.BCM2835_BSC_FIFO;
241+
var status = this.bscAddress + (int)Interop.BCM2835_BSC_S;
242+
var control = this.bscAddress + (int)Interop.BCM2835_BSC_C;
214243

215-
var remaining = (uint) byteCount;
216-
uint i = 0;
244+
var remaining = (uint)buffer.Length;
245+
uint i = 0;
217246

218-
// Clear FIFO
219-
WriteUInt32Mask(control, Interop.BCM2835_BSC_C_CLEAR_1, Interop.BCM2835_BSC_C_CLEAR_1);
247+
// Clear FIFO
248+
WriteUInt32Mask(control, Interop.BCM2835_BSC_C_CLEAR_1, Interop.BCM2835_BSC_C_CLEAR_1);
220249

221-
// Clear Status
222-
WriteUInt32(status, Interop.BCM2835_BSC_S_CLKT | Interop.BCM2835_BSC_S_ERR | Interop.BCM2835_BSC_S_DONE);
250+
// Clear Status
251+
WriteUInt32(status, Interop.BCM2835_BSC_S_CLKT | Interop.BCM2835_BSC_S_ERR | Interop.BCM2835_BSC_S_DONE);
223252

224-
// Set Data Length
225-
WriteUInt32(dlen, (uint) byteCount);
253+
// Set Data Length
254+
WriteUInt32(dlen, (uint)buffer.Length);
226255

227-
// Start read
228-
WriteUInt32(control, Interop.BCM2835_BSC_C_I2CEN | Interop.BCM2835_BSC_C_ST | Interop.BCM2835_BSC_C_READ);
256+
// Start read
257+
WriteUInt32(control, Interop.BCM2835_BSC_C_I2CEN | Interop.BCM2835_BSC_C_ST | Interop.BCM2835_BSC_C_READ);
229258

230-
var buffer = new byte[byteCount];
231-
while ((ReadUInt32(status) & Interop.BCM2835_BSC_S_DONE) == 0)
259+
while ((ReadUInt32(status) & Interop.BCM2835_BSC_S_DONE) == 0)
260+
{
261+
while ((ReadUInt32(status) & Interop.BCM2835_BSC_S_RXD) != 0)
232262
{
233-
while ((ReadUInt32(status) & Interop.BCM2835_BSC_S_RXD) != 0)
234-
{
235-
// Read from FIFO, no barrier
236-
buffer[i] = (byte) ReadUInt32(fifo);
263+
// Read from FIFO, no barrier
264+
buffer[i] = (byte)ReadUInt32(fifo);
237265

238-
i++;
239-
remaining--;
240-
}
241-
242-
Wait(remaining);
243-
}
244-
245-
while (remaining != 0 && (ReadUInt32(status) & Interop.BCM2835_BSC_S_RXD) != 0)
246-
{
247-
buffer[i] = (byte) ReadUInt32(fifo);
248266
i++;
249267
remaining--;
250268
}
251269

252-
if ((SafeReadUInt32(status) & Interop.BCM2835_BSC_S_ERR) != 0) // Received a NACK
253-
throw new InvalidOperationException("Read operation failed with BCM2835_I2C_REASON_ERROR_NACK status");
254-
if ((SafeReadUInt32(status) & Interop.BCM2835_BSC_S_CLKT) != 0) // Received Clock Stretch Timeout
255-
throw new InvalidOperationException("Read operation failed with BCM2835_I2C_REASON_ERROR_CLKT status");
256-
if (remaining != 0) // Not all data is received
257-
throw new InvalidOperationException(string.Format("Read operation failed with BCM2835_I2C_REASON_ERROR_DATA status, missing {0} bytes", remaining));
258-
259-
WriteUInt32Mask(control, Interop.BCM2835_BSC_S_DONE, Interop.BCM2835_BSC_S_DONE);
270+
this.Wait(remaining);
271+
}
260272

261-
return buffer;
273+
while (remaining != 0 && (ReadUInt32(status) & Interop.BCM2835_BSC_S_RXD) != 0)
274+
{
275+
buffer[i] = (byte)ReadUInt32(fifo);
276+
i++;
277+
remaining--;
262278
}
263-
}
264279

265-
#endregion
280+
if ((SafeReadUInt32(status) & Interop.BCM2835_BSC_S_ERR) != 0) // Received a NACK
281+
throw new InvalidOperationException("Read operation failed with BCM2835_I2C_REASON_ERROR_NACK status");
282+
if ((SafeReadUInt32(status) & Interop.BCM2835_BSC_S_CLKT) != 0) // Received Clock Stretch Timeout
283+
throw new InvalidOperationException("Read operation failed with BCM2835_I2C_REASON_ERROR_CLKT status");
284+
if (remaining != 0) // Not all data is received
285+
throw new InvalidOperationException(string.Format("Read operation failed with BCM2835_I2C_REASON_ERROR_DATA status, missing {0} bytes", remaining));
266286

267-
#region Private Helpers
287+
}
268288

269289
private static uint GetProcessorBscAddress(Processor processor)
270290
{
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
namespace Raspberry.IO.InterIntegratedCircuit
2+
{
3+
/// <summary>
4+
/// Defines an I2C read action.
5+
/// </summary>
6+
public class I2cReadAction : I2cAction
7+
{
8+
/// <summary>
9+
/// Initializes a new instance of the <see cref="I2cReadAction"/> class.
10+
/// </summary>
11+
/// <param name="buffer">The buffer which should be used to store the received data.</param>
12+
public I2cReadAction(params byte[] buffer)
13+
: base(buffer)
14+
{
15+
}
16+
}
17+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
namespace Raspberry.IO.InterIntegratedCircuit
2+
{
3+
using System;
4+
5+
/// <summary>
6+
/// Defines an I2C data transaction.
7+
/// </summary>
8+
public class I2cTransaction
9+
{
10+
/// <summary>
11+
/// Initializes a new instance of the <see cref="I2cTransaction"/> class.
12+
/// </summary>
13+
/// <param name="actions">The actions which should be performed within the transaction.</param>
14+
public I2cTransaction(params I2cAction[] actions)
15+
{
16+
if (actions == null)
17+
{
18+
throw new ArgumentNullException("actions");
19+
}
20+
21+
Actions = actions;
22+
}
23+
24+
/// <summary>
25+
/// Gets the actions.
26+
/// </summary>
27+
public I2cAction[] Actions { get; private set; }
28+
}
29+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
namespace Raspberry.IO.InterIntegratedCircuit
2+
{
3+
/// <summary>
4+
/// Defines an I2C write action.
5+
/// </summary>
6+
public class I2cWriteAction : I2cAction
7+
{
8+
/// <summary>
9+
/// Initializes a new instance of the <see cref="I2cWriteAction"/> class.
10+
/// </summary>
11+
/// <param name="buffer">The buffer with data which should be written.</param>
12+
public I2cWriteAction(params byte[] buffer)
13+
: base(buffer)
14+
{
15+
}
16+
}
17+
}

Raspberry.IO.InterIntegratedCircuit/Raspberry.IO.InterIntegratedCircuit.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,12 @@
5050
<Compile Include="..\SharedAssemblyInfo.cs">
5151
<Link>Properties\SharedAssemblyInfo.cs</Link>
5252
</Compile>
53+
<Compile Include="I2cAction.cs" />
5354
<Compile Include="I2cDeviceConnection.cs" />
5455
<Compile Include="I2cDriver.cs" />
56+
<Compile Include="I2cReadAction.cs" />
57+
<Compile Include="I2cTransaction.cs" />
58+
<Compile Include="I2cWriteAction.cs" />
5559
<Compile Include="Interop.cs" />
5660
<Compile Include="Properties\AssemblyInfo.cs" />
5761
</ItemGroup>

0 commit comments

Comments
 (0)