mcp3551.py
5.03 KB
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
# -*- coding: utf-8 -*-
"""
author Benoit Dubois
licence GPL v3+
brief STM32 driver for MCP3551 ADC device
"""
import pyb
class Mcp3551(object):
"""Handle communication with ADC MCP3551 through SPI bus on STM32F4.
Note: baudrate_max = MHz
"""
NUM_BITS = 22
MAX_VALUE = (1 << (NUM_BITS-1)) - 1
MIN_VALUE = -(1 << (NUM_BITS-1))
def __init__(self, bus, baudrate, rdy_b_pin, cs_pin, v_ref):
"""
:param bus: SPI bus number (int)
:param baudrate: SPI bus (data) baudrate (int)
:param rdy_b_pin: Pin in use for rdy_b (SDO/MISO) signal (str)
:param cs_pin: Pin in use for cs signal (str)
:param v_ref: Reference voltage value of ADC (float)
"""
self.baudrate = baudrate
self.v_ref = v_ref
self.rdy_b = pyb.Pin(rdy_b_pin, pyb.Pin.IN)
self.cs_b = pyb.Pin(cs_pin, pyb.Pin.OUT_PP)
self.spi = pyb.SPI(bus)
self.cs_b.high()
self.cs_b.low()
def single_read(self):
"""Read one value then stop acquisition.
"""
self.cs_b.low()
data = self.read()
self.cs_b.high()
return data
def _bin2volt(self, value):
"""Note: does not check sign of data, so negative value are
affected of a small error due to normalisation with MAX_VALUE
instead of MIN_VALUE.
"""
return value * self.v_ref / self.MAX_VALUE
def volt(self):
"""Note: does not check sign of data, so negative value are
affected of a small error due to normalisation with MAX_VALUE
instead of MIN_VALUE.
"""
return self._bin2volt(self.single_read(), self.v_ref, self.MAX_VALUE)
def continous_mode(self, value=True):
"""Set/Deset continous acquisition mode.
"""
if value is False:
self.cs_b.high()
else:
self.cs_b.low()
def read(self):
"""Note1: The ADC allows operation over [-Vref; +Vref] range.
This capability is not implemented.
Note2: If ADC does not respond (i.e. /RDY does not falling), return 0.
"""
wd = 0
buf = bytearray(3)
while self.rdy_b.value() == 1:
if wd > 100: # Watchdog on MCP response
return 0
else:
wd += 1
pyb.delay(1)
self.spi.init(pyb.SPI.MASTER, baudrate=self.baudrate,
polarity=1, phase=1)
self.spi.recv(buf, timeout=500)
self.spi.deinit()
if buf[0] & 256 == 1: # Overflow high
return self.MAX_VALUE
if buf[0] & 128 == 1: # Overflow low
return self.MIN_VALUE
data = (buf[0] << 16) + (buf[1] << 8) + buf[2]
return self.twos_comp(data, self.NUM_BITS)
@staticmethod
def twos_comp(val, bits):
"""compute the 2's complement of int value val of lenght bits.
"""
if (val & (1 << (bits - 1))) != 0: # if sign bit is set
val = val - (1 << bits) # compute negative value
return val # return positive value as is
class Mcp3551Temp(Mcp3551):
"""Handle "slow_adc_shield" of Cyrus Rocher ie a board including
conditionning of a RTD and the A to D conversion with a MCP3551 device.
"""
def __init__(self, bus, baudrate, rdy_b_pin, cs_pin, v_ref=2.5,
r_0=100, alpha=0.00385, r_ref=2.5e3):
"""
:param r_0: resistance of RTD @ 0°C (int)
:param alpha: 1st order sensitivity of RTD (ohm/ohm/°C) (float)
:param r_ref: resistance defining current through RTD (int)
"""
super().__init__(bus, baudrate, rdy_b_pin, cs_pin, v_ref)
self.r_0 = r_0
self.r_ref = r_ref
self.k = 1 / alpha / r_0
@staticmethod
def bin2resistance(bin_value, r_ref, bin_max):
"""Convert binary value to resistance value.
"""
return bin_value * r_ref / bin_max
@staticmethod
def bin2temperature(bin_value, k, r_0, r_ref, bin_max):
"""Convert binary value to temperature value.
"""
return k * (bin_value * r_ref / bin_max - r_0)
def resistance(self):
"""Convert binary value to resistance value.
"""
return self.bin2resistance(self.single_read(),
self.r_ref,
self.MAX_VALUE)
def temperature(self):
"""Convert binary value to temperature value.
"""
return self.bin2temperature(self.single_read(),
self.k, self.r_0,
self.r_ref, self.MAX_VALUE)
if __name__ == '__main__':
ADC_SPI_CH = 1
ADC_V_REF = 2.5
ADC_SPI_BAUDRATE = 1000000
ADC_PIN_CS = 'PA4'
ADC_PIN_RDY_B = 'PA6'
ADC = Mcp3551(bus=ADC_SPI_CH, baudrate=ADC_SPI_BAUDRATE,
rdy_b_pin=ADC_PIN_RDY_B, cs_pin=ADC_PIN_CS,
v_ref=ADC_V_REF)
ADC.continous_mode(True)
ACQ_NB = 0
while True:
pyb.delay(10) # in ms
print(ACQ_NB, ADC.read())
ACQ_NB += 1