forked from dotnet/iot
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMcp3008.cs
155 lines (131 loc) · 4.82 KB
/
Mcp3008.cs
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
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Device.Gpio;
using System.Device.Spi;
namespace Iot.Device.Mcp3008
{
public class Mcp3008 : IDisposable
{
private readonly SpiDevice _spiDevice;
private GpioController _controller;
private readonly CommunicationProtocol _protocol;
private readonly int _clk;
private readonly int _miso;
private readonly int _mosi;
private readonly int _cs;
private enum CommunicationProtocol
{
Gpio,
Spi
}
public enum InputConfiguration
{
Differential = 0,
SingleEnded = 1
}
public Mcp3008(SpiDevice spiDevice)
{
_spiDevice = spiDevice;
_protocol = CommunicationProtocol.Spi;
}
public Mcp3008(int clk, int miso, int mosi, int cs)
{
_controller = new GpioController();
_clk = clk;
_miso = miso;
_mosi = mosi;
_cs = cs;
_controller.OpenPin(_clk, PinMode.Output);
_controller.OpenPin(_miso, PinMode.Input);
_controller.OpenPin(_mosi, PinMode.Output);
_controller.OpenPin(_cs, PinMode.Output);
_protocol = CommunicationProtocol.Gpio;
}
public void Dispose()
{
if (_controller != null)
{
_controller.Dispose();
_controller = null;
}
}
public int Read(int channel, InputConfiguration inputConfiguration = InputConfiguration.SingleEnded)
{
if (channel < 0 || channel > 7)
{
throw new ArgumentException("ADC channel must be within 0-7 range.");
}
if (_protocol == CommunicationProtocol.Spi)
{
return ReadSpi(channel, inputConfiguration);
}
else
{
return ReadGpio(channel, inputConfiguration);
}
}
private static byte GetConfigurationBits(int channel, InputConfiguration inputConfiguration)
{
int configurationBits = (0b0001_1000 | channel) << 3;
if (inputConfiguration == InputConfiguration.Differential)
{
configurationBits &= 0b1011_1111; // Clear mode bit.
}
return (byte)configurationBits;
}
// Ported: https://gist.github.com/ladyada/3151375
private int ReadGpio(int channel, InputConfiguration inputConfiguration)
{
while (true)
{
int result = 0;
byte command = GetConfigurationBits(channel, inputConfiguration);
_controller.Write(_cs, PinValue.High);
_controller.Write(_clk, PinValue.Low);
_controller.Write(_cs, PinValue.Low);
for (int cnt = 0; cnt < 5; cnt++)
{
if ((command & 0b1000_0000) > 0)
{
_controller.Write(_mosi, PinValue.High);
}
else
{
_controller.Write(_mosi, PinValue.Low);
}
command <<= 1;
_controller.Write(_clk, PinValue.High);
_controller.Write(_clk, PinValue.Low);
}
for (int cnt = 0; cnt < 12; cnt++)
{
_controller.Write(_clk, PinValue.High);
_controller.Write(_clk, PinValue.Low);
result <<= 1;
if (_controller.Read(_miso) == PinValue.High)
{
result |= 0b0000_0001;
}
}
_controller.Write(_cs, PinValue.High);
result >>= 1;
return result;
}
}
// Ported: https://github.com/adafruit/Adafruit_Python_MCP3008/blob/master/Adafruit_MCP3008/MCP3008.py
private int ReadSpi(int channel, InputConfiguration inputConfiguration)
{
byte configurationBits = GetConfigurationBits(channel, inputConfiguration);
byte[] writeBuffer = new byte[] { configurationBits, 0, 0 };
byte[] readBuffer = new byte[3];
_spiDevice.TransferFullDuplex(writeBuffer, readBuffer);
int result = (readBuffer[0] & 0b0000_0001) << 9;
result |= (readBuffer[1] & 0b1111_1111) << 1;
result |= (readBuffer[2] & 0b1000_0000) >> 7;
result = result & 0b0011_1111_1111;
return result;
}
}
}