File Coverage

blib/lib/PINE64/MCP300x.pm
Criterion Covered Total %
statement 9 59 15.2
branch 0 12 0.0
condition 0 9 0.0
subroutine 3 5 60.0
pod 2 2 100.0
total 14 87 16.0


line stmt bran cond sub pod time code
1             #!/usr/bin/perl
2 1     1   69811 use strict;
  1         3  
  1         33  
3 1     1   566 use Time::HiRes qw(usleep);
  1         1479  
  1         5  
4 1     1   701 use PINE64::GPIO;
  1         619  
  1         544  
5              
6             package PINE64::MCP300x;
7              
8             our $VERSION = '0.91';
9              
10             =pod
11             bit-banged SPI driver implementing
12             routines for MCP300x 4 or 8-channel
13             10-bit analog to digital converter
14             =cut
15              
16             #SPI / bitbang varables
17             my ($clk, $din, $dout, $chpsel);
18              
19             #channels: first bit is set to single, not differential
20             #5 bits because the first is the start bit
21             my @ch0 = (1,1,0,0,0);
22             my @ch1 = (1,1,0,0,1);
23             my @ch2 = (1,1,0,1,0);
24             my @ch3 = (1,1,0,1,1);
25             my @ch4 = (1,1,1,0,0);
26             my @ch5 = (1,1,1,0,1);
27             my @ch6 = (1,1,1,1,0);
28             my @ch7 = (1,1,1,1,1);
29              
30             #instantiate PINE64 gpio device
31             my $p64 = PINE64::GPIO->new();
32              
33             sub new{
34 0     0 1   my $class = shift;
35 0           my $self = bless {}, $class;
36              
37             #
38 0           $clk = $_[0]; #clock
39 0           $din = $_[1]; #instructions to adc
40 0           $dout = $_[2]; #10-bit output from adc
41 0           $chpsel = $_[3]; #latch / load to init comm to adc
42              
43             #init gpio lines
44 0           $p64->gpio_enable($clk, 'out');
45 0           $p64->gpio_enable($din, 'out');
46 0           $p64->gpio_enable($dout, 'in');
47 0           $p64->gpio_enable($chpsel, 'out');
48            
49             #init chpsel high, comm begins when
50             #chipsel goes from high to low
51 0           $p64->gpio_write($chpsel, 1);
52              
53 0           return $self;
54              
55             }#end new
56              
57             sub read300x{
58             #init empty array that will
59             #contain 10-bit reading from ADC
60 0     0 1   my @reading = ();
61             #get reading from the MCP3004 ADC
62             #starts comm when cs goes from high to low
63            
64             #ADC channel number
65             #channel is an array reference
66 0           my $channel = $_[1];
67              
68             #delay between clock pulses
69             #needs to operate at 10KHz so
70             #sample is accurate, so min usleep(100)
71 0           my $delay = $_[2];
72              
73             #reference voltate, used only for calculations
74             #can be omitted
75 0           my $vref = $_[3];
76              
77             #main clock variable
78 0           my $i=0;
79            
80             #high flag for data gpio line
81 0           my $hf = 0;
82              
83             #number of clock pulses,
84 0           my $ncp = 34; #for 18 clock pulses
85              
86             #high or low state of clock pulse
87 0           my $state = 0;
88 0           my $seed = 3; #seed used to determine high or low, start 3 so first pulse is high
89            
90             #toggles CS line to init communication with the adc
91             #start low, go high, then low. comm begins when CS
92             #brought from high to low
93 0           $p64->gpio_write($chpsel, 0);
94 0           Time::HiRes::usleep($delay);
95            
96             #main loop
97 0           while($i<$ncp){
98 0           $state = $seed%2;#toggles between 1 and 0
99 0           $seed++;
100              
101             #clock pulse high
102 0 0         if(($i%2) eq 0){
103             #print "i: $i\tcp high\tstate: $state\n";
104              
105 0 0 0       if($channel->[$i/2] eq 1 && $i <=8){
106 0           $p64->gpio_write($din, 1);
107 0           $hf = 1;#set high flag
108             #print "ch[".($i/2)."]: ".$channel->[$i/2]."\n";
109             }#end if
110 0 0 0       if($channel->[$i/2] eq 0 && $i <=8){
111 0           $p64->gpio_write($din,0);
112             }#end if zero on data line
113             }#end if high
114              
115             #if($i>8){#data line
116             #everything after D0 bit is don't care,
117             #set to state
118             #gpio_write($din, $state);
119             #}#end else
120              
121             #clock pulse
122 0           $p64->gpio_write($clk, $state);
123              
124             #read data out
125             #data clocked out on falling
126             #edge of clk
127 0 0 0       if(($i%2) == 1 && $i >12){
128             #read state of gpio pin connected
129             #to data out of ADC
130 0           push @reading, $p64->gpio_read($dout);
131             #print "i[$i]: ".$reading[($i-14)/2]."\n"
132             }#end read data out
133              
134             #lower data if high flag set
135 0 0         if($hf eq 1){
136             #gpio_write($din,0);
137 0           $hf = 0;#reset high flag
138             }#end if
139            
140             #pause between clk pls
141 0           Time::HiRes::usleep($delay);
142              
143             #increment counter
144 0           $i++;
145             }#end while
146            
147             #make din low
148 0           $p64->gpio_write($din, 0);
149              
150             #make chip select high
151 0           $p64->gpio_write($chpsel, 1);
152              
153             #perform calcuations, return a voltage
154             #based of 10-bit reading, and vref val
155 0           my $bindig = 512;
156 0           my $rdgval = 0;
157 0           my $voltage = 0;
158 0           for(my $x; $x<10;$x++){
159 0 0         if($reading[$x] == 1){
160 0           $rdgval = $rdgval + $bindig;
161             }#end if
162 0           $bindig = $bindig / 2;
163             }#end for
164              
165             #voltage calculation
166 0           $voltage = ($rdgval*$vref)/1024;
167              
168 0           return (\@reading, $rdgval, $voltage);
169             }#end read3004
170              
171             1;
172             __END__