line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# You may distribute under the terms of either the GNU General Public License |
2
|
|
|
|
|
|
|
# or the Artistic License (the same terms as Perl itself) |
3
|
|
|
|
|
|
|
# |
4
|
|
|
|
|
|
|
# (C) Paul Evans, 2017-2022 -- leonerd@leonerd.org.uk |
5
|
|
|
|
|
|
|
|
6
|
2
|
|
|
2
|
|
111747
|
use v5.26; |
|
2
|
|
|
|
|
16
|
|
7
|
2
|
|
|
2
|
|
10
|
use Object::Pad 0.57; |
|
2
|
|
|
|
|
22
|
|
|
2
|
|
|
|
|
10
|
|
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
package Device::Chip::MAX11200 0.13; |
10
|
|
|
|
|
|
|
class Device::Chip::MAX11200 |
11
|
|
|
|
|
|
|
:isa(Device::Chip); |
12
|
|
|
|
|
|
|
|
13
|
2
|
|
|
2
|
|
558
|
use Carp; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
139
|
|
14
|
2
|
|
|
2
|
|
13
|
use Future::AsyncAwait; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
10
|
|
15
|
2
|
|
|
2
|
|
1004
|
use Future::IO; |
|
2
|
|
|
|
|
20243
|
|
|
2
|
|
|
|
|
160
|
|
16
|
2
|
|
|
2
|
|
559
|
use Data::Bitfield 0.02 qw( bitfield boolfield enumfield ); |
|
2
|
|
|
|
|
2045
|
|
|
2
|
|
|
|
|
139
|
|
17
|
2
|
|
|
2
|
|
17
|
use List::Util qw( first ); |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
165
|
|
18
|
|
|
|
|
|
|
|
19
|
2
|
|
|
2
|
|
13
|
use constant PROTOCOL => "SPI"; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
645
|
|
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
=head1 NAME |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
C - chip driver for F |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
=head1 SYNOPSIS |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
use Device::Chip::MAX11200; |
28
|
|
|
|
|
|
|
use Future::AsyncAwait; |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
my $chip = Device::Chip::MAX11200->new; |
31
|
|
|
|
|
|
|
await $chip->mount( Device::Chip::Adapter::...->new ); |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
await $chip->trigger; |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
printf "The reading is %d\n", await $chip->read_adc; |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
=head1 DESCRIPTION |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
This L subclass provides specific communications to a F |
40
|
|
|
|
|
|
|
F or F chip. |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
The reader is presumed to be familiar with the general operation of this chip; |
43
|
|
|
|
|
|
|
the documentation here will not attempt to explain or define chip-specific |
44
|
|
|
|
|
|
|
concepts or features, only the use of this module to access them. |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
=cut |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
sub SPI_options |
49
|
|
|
|
|
|
|
{ |
50
|
|
|
|
|
|
|
return ( |
51
|
1
|
|
|
1
|
0
|
305
|
mode => 0, |
52
|
|
|
|
|
|
|
max_bitrate => 2E6, |
53
|
|
|
|
|
|
|
); |
54
|
|
|
|
|
|
|
} |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
=head1 METHODS |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
The following methods documented in an C expression return L |
59
|
|
|
|
|
|
|
instances. |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
=cut |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
=head2 init |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
await $chip->init; |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
Performs startup self-calibration by setting C and C to zero |
68
|
|
|
|
|
|
|
then requesting a calibration cycle. |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
=cut |
71
|
|
|
|
|
|
|
|
72
|
0
|
|
|
|
|
0
|
async method init () |
|
0
|
|
|
|
|
0
|
|
73
|
0
|
|
|
|
|
0
|
{ |
74
|
0
|
|
|
|
|
0
|
await $self->change_config( |
75
|
|
|
|
|
|
|
NOSCG => 0, |
76
|
|
|
|
|
|
|
NOSCO => 0, |
77
|
|
|
|
|
|
|
); |
78
|
|
|
|
|
|
|
|
79
|
0
|
|
|
|
|
0
|
await $self->selfcal; |
80
|
|
|
|
|
|
|
|
81
|
0
|
|
|
|
|
0
|
await Future::IO->sleep( 0.25 ); # selfcal takes 200msec (longer at LINEF=50Hz) |
82
|
0
|
|
|
0
|
1
|
0
|
} |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
use constant { |
85
|
2
|
|
|
|
|
882
|
REG_STAT => 0, |
86
|
|
|
|
|
|
|
REG_CTRL1 => 1, |
87
|
|
|
|
|
|
|
REG_CTRL2 => 2, |
88
|
|
|
|
|
|
|
REG_CTRL3 => 3, |
89
|
|
|
|
|
|
|
REG_DATA => 4, |
90
|
|
|
|
|
|
|
REG_SOC => 5, |
91
|
|
|
|
|
|
|
REG_SGC => 6, |
92
|
|
|
|
|
|
|
REG_SCOC => 7, |
93
|
|
|
|
|
|
|
REG_SCGC => 8, |
94
|
2
|
|
|
2
|
|
22
|
}; |
|
2
|
|
|
|
|
4
|
|
95
|
|
|
|
|
|
|
|
96
|
11
|
|
|
|
|
20
|
async method read_register ( $reg, $len = 1 ) |
|
11
|
|
|
|
|
20
|
|
|
11
|
|
|
|
|
19
|
|
|
11
|
|
|
|
|
18
|
|
97
|
11
|
|
|
|
|
23
|
{ |
98
|
11
|
|
|
|
|
42
|
my $bytes = await $self->protocol->readwrite( |
99
|
|
|
|
|
|
|
pack "C a*", 0xC1 | ( $reg << 1 ), "\0" x $len |
100
|
|
|
|
|
|
|
); |
101
|
|
|
|
|
|
|
|
102
|
11
|
|
|
|
|
17863
|
return substr $bytes, 1; |
103
|
11
|
|
|
11
|
0
|
1259
|
} |
104
|
|
|
|
|
|
|
|
105
|
6
|
|
|
|
|
9
|
async method write_register ( $reg, $val ) |
|
6
|
|
|
|
|
10
|
|
|
6
|
|
|
|
|
13
|
|
|
6
|
|
|
|
|
10
|
|
106
|
6
|
|
|
|
|
14
|
{ |
107
|
6
|
|
|
|
|
25
|
await $self->protocol->write( |
108
|
|
|
|
|
|
|
pack "C a*", 0xC0 | ( $reg << 1 ), $val |
109
|
|
|
|
|
|
|
); |
110
|
6
|
|
|
6
|
0
|
1132
|
} |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
my @RATES = qw( 1 2.5 5 10 15 30 60 120 ); |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
use constant { |
115
|
2
|
|
|
|
|
4075
|
CMD_SELFCAL => 0x10, |
116
|
|
|
|
|
|
|
CMD_SYSOCAL => 0x20, |
117
|
|
|
|
|
|
|
CMD_SYSGCAL => 0x30, |
118
|
|
|
|
|
|
|
CMD_POWERDOWN => 0x08, |
119
|
|
|
|
|
|
|
CMD_CONV => 0, |
120
|
2
|
|
|
2
|
|
13
|
}; |
|
2
|
|
|
|
|
4
|
|
121
|
|
|
|
|
|
|
|
122
|
3
|
|
|
|
|
5
|
async method command ( $cmd ) |
|
3
|
|
|
|
|
5
|
|
|
3
|
|
|
|
|
4
|
|
123
|
3
|
|
|
|
|
8
|
{ |
124
|
3
|
|
|
|
|
16
|
await $self->protocol->write( pack "C", 0x80 | $cmd ); |
125
|
3
|
|
|
3
|
0
|
6
|
} |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
=head2 read_status |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
$status = await $chip->read_status; |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
Returns a C reference containing the chip's current status. |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
RDY => 0 | 1 |
134
|
|
|
|
|
|
|
MSTAT => 0 | 1 |
135
|
|
|
|
|
|
|
UR => 0 | 1 |
136
|
|
|
|
|
|
|
OR => 0 | 1 |
137
|
|
|
|
|
|
|
RATE => 1 | 2.5 | 5 | 10 | 15 | 30 | 60 | 120 |
138
|
|
|
|
|
|
|
SYSOR => 0 | 1 |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
=cut |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
bitfield { format => "bytes-LE" }, STAT => |
143
|
|
|
|
|
|
|
RDY => boolfield(0), |
144
|
|
|
|
|
|
|
MSTAT => boolfield(1), |
145
|
|
|
|
|
|
|
UR => boolfield(2), |
146
|
|
|
|
|
|
|
OR => boolfield(3), |
147
|
|
|
|
|
|
|
RATE => enumfield(4, @RATES), |
148
|
|
|
|
|
|
|
SYSOR => boolfield(7); |
149
|
|
|
|
|
|
|
|
150
|
1
|
|
|
|
|
2
|
async method read_status () |
|
1
|
|
|
|
|
1
|
|
151
|
1
|
|
|
|
|
3
|
{ |
152
|
1
|
|
|
|
|
4
|
my $bytes = await $self->read_register( REG_STAT ); |
153
|
|
|
|
|
|
|
|
154
|
1
|
|
|
|
|
57
|
return unpack_STAT( $bytes ); |
155
|
1
|
|
|
1
|
1
|
228
|
} |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
=head2 read_config |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
$config = await $chip->read_config; |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
Returns a C reference containing the chip's current configuration. |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
SCYCLE => 0 | 1 |
164
|
|
|
|
|
|
|
FORMAT => "TWOS_COMP" | "OFFSET" |
165
|
|
|
|
|
|
|
SIGBUF => 0 | 1 |
166
|
|
|
|
|
|
|
REFBUF => 0 | 1 |
167
|
|
|
|
|
|
|
EXTCLK => 0 | 1 |
168
|
|
|
|
|
|
|
UB => "UNIPOLAR" | "BIPOLAR" |
169
|
|
|
|
|
|
|
LINEF => "60Hz" | "50Hz" |
170
|
|
|
|
|
|
|
NOSCO => 0 | 1 |
171
|
|
|
|
|
|
|
NOSCG => 0 | 1 |
172
|
|
|
|
|
|
|
NOSYSO => 0 | 1 |
173
|
|
|
|
|
|
|
NOSYSG => 0 | 1 |
174
|
|
|
|
|
|
|
DGAIN => 1 2 4 8 16 # only valid for the MAX11210 |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
=cut |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
bitfield { format => "bytes-LE" }, CONFIG => |
179
|
|
|
|
|
|
|
# CTRL1 |
180
|
|
|
|
|
|
|
SCYCLE => boolfield(1), |
181
|
|
|
|
|
|
|
FORMAT => enumfield(2, qw( TWOS_COMP OFFSET )), |
182
|
|
|
|
|
|
|
SIGBUF => boolfield(3), |
183
|
|
|
|
|
|
|
REFBUF => boolfield(4), |
184
|
|
|
|
|
|
|
EXTCLK => boolfield(5), |
185
|
|
|
|
|
|
|
UB => enumfield(6, qw( BIPOLAR UNIPOLAR )), |
186
|
|
|
|
|
|
|
LINEF => enumfield(7, qw( 60Hz 50Hz )), |
187
|
|
|
|
|
|
|
# CTRL2 is all GPIO control; we'll do that elsewhere |
188
|
|
|
|
|
|
|
# CTRL3 |
189
|
|
|
|
|
|
|
NOSCO => boolfield(8+1), |
190
|
|
|
|
|
|
|
NOSCG => boolfield(8+2), |
191
|
|
|
|
|
|
|
NOSYSO => boolfield(8+3), |
192
|
|
|
|
|
|
|
NOSYSG => boolfield(8+4), |
193
|
|
|
|
|
|
|
DGAIN => enumfield(8+5, qw( 1 2 4 8 16 )); |
194
|
|
|
|
|
|
|
|
195
|
1
|
|
|
|
|
2
|
async method read_config () |
|
1
|
|
|
|
|
2
|
|
196
|
1
|
|
|
|
|
6
|
{ |
197
|
1
|
|
|
|
|
4
|
my ( $ctrl1, $ctrl3 ) = await Future->needs_all( |
198
|
|
|
|
|
|
|
$self->read_register( REG_CTRL1 ), $self->read_register( REG_CTRL3 ) |
199
|
|
|
|
|
|
|
); |
200
|
|
|
|
|
|
|
|
201
|
1
|
|
|
|
|
133
|
return $self->{config} = { unpack_CONFIG( $ctrl1 . $ctrl3 ) }; |
202
|
1
|
|
|
1
|
1
|
3326
|
} |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
=head2 change_config |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
await $chip->change_config( %changes ); |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
Changes the configuration. Any field names not mentioned will be preserved at |
209
|
|
|
|
|
|
|
their existing values. |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
=cut |
212
|
|
|
|
|
|
|
|
213
|
1
|
|
|
|
|
3
|
async method change_config ( %changes ) |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
2
|
|
214
|
1
|
|
|
|
|
4
|
{ |
215
|
1
|
|
33
|
|
|
4
|
my $config = $self->{config} // await $self->read_config; |
216
|
|
|
|
|
|
|
|
217
|
1
|
|
|
|
|
13
|
$self->{config} = { %$config, %changes }; |
218
|
1
|
|
|
|
|
2
|
my $ctrlb = pack_CONFIG( %{ $self->{config} } ); |
|
1
|
|
|
|
|
9
|
|
219
|
|
|
|
|
|
|
|
220
|
1
|
|
|
|
|
228
|
await Future->needs_all( |
221
|
|
|
|
|
|
|
$self->write_register( REG_CTRL1, substr $ctrlb, 0, 1 ), |
222
|
|
|
|
|
|
|
$self->write_register( REG_CTRL3, substr $ctrlb, 1, 1 ), |
223
|
|
|
|
|
|
|
); |
224
|
1
|
|
|
1
|
1
|
3537
|
} |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
=head2 selfcal |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
await $chip->selfcal; |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
Requests the chip perform a self-calibration. |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
=cut |
233
|
|
|
|
|
|
|
|
234
|
1
|
|
|
|
|
2
|
async method selfcal () |
|
1
|
|
|
|
|
44
|
|
235
|
1
|
|
|
|
|
6
|
{ |
236
|
1
|
|
|
|
|
6
|
await $self->command( CMD_SELFCAL ); |
237
|
1
|
|
|
1
|
1
|
3248
|
} |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
=head2 syscal_offset |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
await $chip->syscal_offset; |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
Requests the chip perform the offset part of system calibration. |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
=cut |
246
|
|
|
|
|
|
|
|
247
|
0
|
|
|
|
|
0
|
async method syscal_offset () |
|
0
|
|
|
|
|
0
|
|
248
|
0
|
|
|
|
|
0
|
{ |
249
|
0
|
|
|
|
|
0
|
await $self->command( CMD_SYSOCAL ); |
250
|
0
|
|
|
0
|
1
|
0
|
} |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
=head2 syscal_gain |
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
await $chip->syscal_gain; |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
Requests the chip perform the gain part of system calibration. |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
=cut |
259
|
|
|
|
|
|
|
|
260
|
0
|
|
|
|
|
0
|
async method syscal_gain () |
|
0
|
|
|
|
|
0
|
|
261
|
0
|
|
|
|
|
0
|
{ |
262
|
0
|
|
|
|
|
0
|
await $self->command( CMD_SYSGCAL ); |
263
|
0
|
|
|
0
|
1
|
0
|
} |
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
=head2 trigger |
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
await $chip->trigger( $rate ); |
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
Requests the chip perform a conversion of the input level, at the given |
270
|
|
|
|
|
|
|
rate (which must be one of the values specified for the C configuration |
271
|
|
|
|
|
|
|
option); defaulting to the value of L if not defined. |
272
|
|
|
|
|
|
|
Once the conversion is complete it can be read using the C method. |
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
=head2 default_trigger_rate |
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
$rate = $chip->default_trigger_rate |
277
|
|
|
|
|
|
|
$chip->default_trigger_rate = $new_rate |
278
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
Lvalue accessor for the default trigger rate if L is invoked without |
280
|
|
|
|
|
|
|
one. Initialised to 120. |
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
=cut |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
has $_default_trigger_rate = 120; |
285
|
1
|
|
|
1
|
1
|
3311
|
method default_trigger_rate :lvalue { $_default_trigger_rate } |
|
1
|
|
|
|
|
3
|
|
286
|
|
|
|
|
|
|
|
287
|
2
|
|
|
|
|
5
|
async method trigger ( $rate = $_default_trigger_rate ) |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
4
|
|
288
|
2
|
|
|
|
|
7
|
{ |
289
|
14
|
50
|
|
14
|
|
30
|
defined( my $rateidx = first { $RATES[$_] == $rate } 0 .. $#RATES ) |
|
2
|
|
|
|
|
18
|
|
290
|
|
|
|
|
|
|
or croak "Unrecognised conversion rate $rate"; |
291
|
|
|
|
|
|
|
|
292
|
2
|
|
|
|
|
14
|
await $self->command( CMD_CONV | $rateidx ); |
293
|
2
|
|
|
2
|
1
|
4107
|
} |
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
=head2 read_adc |
296
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
$value = await $chip->read_adc; |
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
Reads the most recent reading from the result register on the tip. This method |
300
|
|
|
|
|
|
|
should be called after a suitable delay after the L method when in |
301
|
|
|
|
|
|
|
single cycle mode, or at any time when in continuous mode. |
302
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
The reading is returned directly from the chip as a plain 24-bit integer, |
304
|
|
|
|
|
|
|
either signed or unsigned as per the C configuration. |
305
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
=cut |
307
|
|
|
|
|
|
|
|
308
|
4
|
|
|
|
|
9
|
async method read_adc () |
|
4
|
|
|
|
|
4
|
|
309
|
4
|
|
|
|
|
13
|
{ |
310
|
4
|
|
|
|
|
15
|
my $bytes = await $self->read_register( REG_DATA, 3 ); |
311
|
|
|
|
|
|
|
|
312
|
4
|
|
|
|
|
219
|
return unpack "L>", "\0$bytes"; |
313
|
4
|
|
|
4
|
1
|
6900
|
} |
314
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
=head2 read_adc_ratio |
316
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
$ratio = await $chip->read_adc_ratio; |
318
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
Converts a reading obtained by L into a ratio between -1 and 1, |
320
|
|
|
|
|
|
|
taking into account the current mode setting of the chip. |
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
=cut |
323
|
|
|
|
|
|
|
|
324
|
1
|
|
|
|
|
2
|
async method read_adc_ratio () |
|
1
|
|
|
|
|
2
|
|
325
|
1
|
|
|
|
|
5
|
{ |
326
|
|
|
|
|
|
|
my ( $value, $config ) = await Future->needs_all( |
327
|
|
|
|
|
|
|
$self->read_adc, |
328
|
1
|
|
|
|
|
4
|
( $self->{config} ? Future->done( $self->{config} ) : $self->read_config ) |
329
|
|
|
|
|
|
|
); |
330
|
|
|
|
|
|
|
|
331
|
1
|
50
|
|
|
|
98
|
if( $config->{UB} eq "UNIPOLAR" ) { |
332
|
|
|
|
|
|
|
# Raw 24bit integer |
333
|
0
|
|
|
|
|
0
|
return $value / 2**24; |
334
|
|
|
|
|
|
|
} |
335
|
|
|
|
|
|
|
else { |
336
|
1
|
50
|
|
|
|
4
|
if( $config->{FORMAT} eq "TWOS_COMP" ) { |
337
|
|
|
|
|
|
|
# Signed integer in twos-complement form |
338
|
1
|
50
|
|
|
|
5
|
$value -= 2**24 if $value >= 2**23; |
339
|
|
|
|
|
|
|
} |
340
|
|
|
|
|
|
|
else { |
341
|
|
|
|
|
|
|
# Signed-integer in offset form |
342
|
0
|
|
|
|
|
0
|
$value -= 2**23; |
343
|
|
|
|
|
|
|
} |
344
|
1
|
|
|
|
|
6
|
return $value / 2**23; |
345
|
|
|
|
|
|
|
} |
346
|
1
|
|
|
1
|
1
|
3205
|
} |
347
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
=head2 write_gpios |
349
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
await $chip->write_gpios( $values, $direction ); |
351
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
=head2 read_gpios |
353
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
$values = await $chip->read_gpios; |
355
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
Sets or reads the values of the GPIO pins as a 4-bit integer. Bits in the |
357
|
|
|
|
|
|
|
C<$direction> should be high to put the corresponding pin into output mode, or |
358
|
|
|
|
|
|
|
low to put it into input mode. |
359
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
As an alternative to these methods, see instead L. |
361
|
|
|
|
|
|
|
|
362
|
|
|
|
|
|
|
=cut |
363
|
|
|
|
|
|
|
|
364
|
3
|
|
|
|
|
7
|
async method write_gpios ( $values, $dir ) |
|
3
|
|
|
|
|
5
|
|
|
3
|
|
|
|
|
5
|
|
|
3
|
|
|
|
|
6
|
|
365
|
3
|
|
|
|
|
10
|
{ |
366
|
3
|
|
|
|
|
23
|
await $self->write_register( REG_CTRL2, pack "C", ( $dir << 4 ) | $values ); |
367
|
3
|
|
|
3
|
1
|
2846
|
} |
368
|
|
|
|
|
|
|
|
369
|
3
|
|
|
|
|
6
|
async method read_gpios () |
|
3
|
|
|
|
|
6
|
|
370
|
3
|
|
|
|
|
11
|
{ |
371
|
3
|
|
|
|
|
10
|
my $bytes = await $self->read_register( REG_CTRL2 ); |
372
|
|
|
|
|
|
|
|
373
|
3
|
|
|
|
|
158
|
return 0x0F & unpack "C", $bytes; |
374
|
3
|
|
|
3
|
1
|
2507
|
} |
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
=head2 Calibration Registers |
377
|
|
|
|
|
|
|
|
378
|
|
|
|
|
|
|
$value = await $chip->read_selfcal_offset; |
379
|
|
|
|
|
|
|
$value = await $chip->read_selfcal_gain; |
380
|
|
|
|
|
|
|
$value = await $chip->read_syscal_offset; |
381
|
|
|
|
|
|
|
$value = await $chip->read_syscal_gain; |
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
await $chip->write_selfcal_offset( $value ); |
384
|
|
|
|
|
|
|
await $chip->write_selfcal_gain( $value ); |
385
|
|
|
|
|
|
|
await $chip->write_syscal_offset( $value ); |
386
|
|
|
|
|
|
|
await $chip->write_syscal_gain( $value ); |
387
|
|
|
|
|
|
|
|
388
|
|
|
|
|
|
|
Reads or writes the values of the calibration registers, as plain 24-bit |
389
|
|
|
|
|
|
|
integers. |
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
=cut |
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
foreach ( |
394
|
|
|
|
|
|
|
[ "selfcal_offset", REG_SCOC ], |
395
|
|
|
|
|
|
|
[ "selfcal_gain", REG_SCGC ], |
396
|
|
|
|
|
|
|
[ "syscal_offset", REG_SOC ], |
397
|
|
|
|
|
|
|
[ "syscal_gain", REG_SGC ], |
398
|
|
|
|
|
|
|
) { |
399
|
|
|
|
|
|
|
my ( $name, $reg ) = @$_; |
400
|
|
|
|
|
|
|
|
401
|
2
|
|
|
2
|
|
17
|
no strict 'refs'; |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
855
|
|
402
|
|
|
|
|
|
|
|
403
|
1
|
|
|
|
|
7
|
*{"read_$name"} = async method () { |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
2
|
|
404
|
1
|
|
|
|
|
5
|
my $bytes = await $self->read_register( $reg, 3 ); |
405
|
1
|
|
|
|
|
56
|
return unpack "I>", "\0" . $bytes; |
406
|
1
|
|
|
1
|
|
1388
|
}; |
407
|
|
|
|
|
|
|
|
408
|
1
|
|
|
|
|
3
|
*{"write_$name"} = async method ( $value ) { |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
2
|
|
409
|
1
|
|
|
|
|
8
|
await $self->write_register( $reg, |
410
|
|
|
|
|
|
|
substr( pack( "I>", $value ), 1 ) |
411
|
|
|
|
|
|
|
); |
412
|
1
|
|
|
1
|
|
734
|
}; |
413
|
|
|
|
|
|
|
} |
414
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
=head2 as_gpio_adapter |
416
|
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
$adapter = $chip->as_gpio_adapter |
418
|
|
|
|
|
|
|
|
419
|
|
|
|
|
|
|
Returns an instance implementing the L interface, |
420
|
|
|
|
|
|
|
allowing access to the four GPIO pins via the standard adapter API. |
421
|
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
=cut |
423
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
method as_gpio_adapter |
425
|
1
|
|
|
1
|
1
|
721
|
{ |
426
|
1
|
|
|
|
|
51
|
return Device::Chip::MAX11200::_GPIOAdapter->new( chip => $self ); |
427
|
|
|
|
|
|
|
} |
428
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
class Device::Chip::MAX11200::_GPIOAdapter { |
430
|
2
|
|
|
2
|
|
260
|
use Carp; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
2436
|
|
431
|
|
|
|
|
|
|
|
432
|
|
|
|
|
|
|
has $_chip :param; |
433
|
|
|
|
|
|
|
|
434
|
1
|
|
|
|
|
2
|
async method make_protocol ( $pname ) |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
2
|
|
435
|
1
|
|
|
|
|
2
|
{ |
436
|
1
|
50
|
|
|
|
5
|
$pname eq "GPIO" or |
437
|
|
|
|
|
|
|
croak "Unrecognised protocol name $pname"; |
438
|
|
|
|
|
|
|
|
439
|
1
|
|
|
|
|
12
|
return $self; |
440
|
1
|
|
|
1
|
|
3
|
} |
441
|
|
|
|
|
|
|
|
442
|
1
|
|
|
1
|
|
37
|
method list_gpios { qw( GPIO1 GPIO2 GPIO3 GPIO4 ) } |
|
1
|
|
|
|
|
7
|
|
443
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
method meta_gpios |
445
|
0
|
|
|
0
|
|
0
|
{ |
446
|
|
|
|
|
|
|
return map { |
447
|
0
|
|
|
|
|
0
|
Device::Chip::Adapter::GPIODefinition( $_, "rw", 0 ) |
|
0
|
|
|
|
|
0
|
|
448
|
|
|
|
|
|
|
} $self->list_gpios; |
449
|
|
|
|
|
|
|
} |
450
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
has $_dir = ""; |
452
|
|
|
|
|
|
|
has $_val = ""; |
453
|
|
|
|
|
|
|
|
454
|
2
|
|
|
|
|
4
|
async method write_gpios ( $values ) |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
4
|
|
455
|
2
|
|
|
|
|
7
|
{ |
456
|
2
|
|
|
|
|
5
|
foreach my $n ( 1 .. 4 ) { |
457
|
8
|
100
|
|
|
|
26
|
defined( my $v = $values->{"GPIO$n"} ) or next; |
458
|
|
|
|
|
|
|
|
459
|
2
|
|
|
|
|
9
|
vec( $_dir, $n-1, 1 ) = 1; |
460
|
2
|
|
|
|
|
7
|
vec( $_val, $n-1, 1 ) = $v; |
461
|
|
|
|
|
|
|
} |
462
|
|
|
|
|
|
|
|
463
|
2
|
|
|
|
|
9
|
await $_chip->write_gpios( ord $_val, ord $_dir ); |
464
|
2
|
|
|
2
|
|
4363
|
} |
465
|
|
|
|
|
|
|
|
466
|
1
|
|
|
|
|
2
|
async method tris_gpios ( $pins ) |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
2
|
|
467
|
1
|
|
|
|
|
2
|
{ |
468
|
1
|
|
|
|
|
2
|
my $newdir = $_dir; |
469
|
1
|
|
|
|
|
3
|
foreach my $pin ( @$pins ) { |
470
|
1
|
50
|
33
|
|
|
16
|
$pin =~ m/^GPIO(\d)/ and $1 >= 1 and $1 <= 4 or |
|
|
|
33
|
|
|
|
|
471
|
|
|
|
|
|
|
croak "Unrecognised GPIO pin name $pin"; |
472
|
1
|
|
|
|
|
3
|
my $n = $1; |
473
|
|
|
|
|
|
|
|
474
|
1
|
|
|
|
|
5
|
vec( $newdir, $n-1, 1 ) = 0; |
475
|
|
|
|
|
|
|
} |
476
|
|
|
|
|
|
|
|
477
|
1
|
50
|
|
|
|
17
|
if( $newdir ne $_dir ) { |
478
|
0
|
|
|
|
|
0
|
$_dir = $newdir; |
479
|
0
|
|
|
|
|
0
|
await $_chip->write_gpios( ord $_val, ord $_dir ); |
480
|
|
|
|
|
|
|
} |
481
|
1
|
|
|
1
|
|
3
|
} |
482
|
|
|
|
|
|
|
|
483
|
1
|
|
|
|
|
3
|
async method read_gpios ( $pins ) |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
2
|
|
484
|
1
|
|
|
|
|
4
|
{ |
485
|
1
|
|
|
|
|
4
|
await $self->tris_gpios( $pins ); |
486
|
|
|
|
|
|
|
|
487
|
1
|
|
|
|
|
48
|
my $read = chr await $_chip->read_gpios; |
488
|
|
|
|
|
|
|
|
489
|
1
|
|
|
|
|
52
|
my %ret; |
490
|
1
|
|
|
|
|
3
|
foreach my $pin ( @$pins ) { |
491
|
1
|
50
|
|
|
|
8
|
$pin =~ m/^GPIO(\d)/ and my $n = $1; |
492
|
1
|
|
|
|
|
6
|
$ret{$pin} = vec( $read, $n-1, 1 ); |
493
|
|
|
|
|
|
|
} |
494
|
|
|
|
|
|
|
|
495
|
1
|
|
|
|
|
5
|
return \%ret; |
496
|
1
|
|
|
1
|
|
3627
|
} |
497
|
|
|
|
|
|
|
} |
498
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
=head1 AUTHOR |
500
|
|
|
|
|
|
|
|
501
|
|
|
|
|
|
|
Paul Evans |
502
|
|
|
|
|
|
|
|
503
|
|
|
|
|
|
|
=cut |
504
|
|
|
|
|
|
|
|
505
|
|
|
|
|
|
|
0x55AA; |