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