http://qs1969.pair.com?node_id=1180361

Well, all of the learning and testing I've done with C, XS, managing bits, reading and understanding hardware datatsheets etc in the last few months is really starting to pay off, with a lot of kudos going out to many Monks here for providing guidance and help with my questions.

We now have reliable, working Perl code to output and receive input analog signals on the Raspberry Pi. This example uses an MCP41010 digital potentiometer for the analog out, and an ADC1015 analog to digital converter for analog in. I still have two different ADCs to write code for, two more models of digital pots, and later this week I should be receiving my DACs (digital to analog converter), my GPS receiver chip, and my MCP3004/8 ADCs.

This doesn't do much, but it's the base of what will eventually allow me to have a Pi in the corner that all it does is pull from github and continuously (and automatically!) run unit tests for the Pi software. However, with true analog output/inputs, there's a lot more a Pi can do.

The schematic and the breadboard layout for the setup.

Note that the digital pot operates over the SPI bus, which uses RPi::SPI, which is the software I wrote that allows an aref to be sent into a C function (I haven't changed it to use one of the other methods yet) as discussed in this node. The fun aref part is here, in the base WiringPi::API.

update: the SPI RW functionality now not only allows an aref to be sent in, but will very soon return a proper Perl array, so that you'll always get the read bytes back on every transaction, in the proper order and count. See here if you're interested in what I call Perl Awesomeness./update

Code:

use warnings; use strict; use RPi::WiringPi; my $pi = RPi::WiringPi->new; my $adc = $pi->adc; my $cs = $pi->pin(18); my $dpot = $pi->dpot($cs->num, 0); $dpot->set(0); print "\nValue, Output %\n\n"; for (0..255){ if (($_ % 10) != 0 && $_ != 255){ next; } $dpot->set($_); my $p = $adc->percent(0); print "$_/255: $p %\n"; select(undef, undef, undef, 0.3); } print "\n\nOutput % at 127/255\n\n"; $dpot->set(127); for (0..10){ print $adc->percent(0) . " %\n"; select(undef, undef, undef, 0.2); } $pi->cleanup;

All it does is switch to different taps (resistor level) on the digital pot which increases/decreases output voltage. The ADC's input pin (A0) is connected directly to the output of the pot, as is the LED, just so I can see visually the changes as well as receive them digitally via the software.

Output:

Value, Output % 0/255: 0.36 % 10/255: 4.24 % 20/255: 8.12 % 30/255: 12.00 % 40/255: 15.88 % 50/255: 19.76 % 60/255: 23.70 % 70/255: 27.58 % 80/255: 31.45 % 90/255: 35.33 % 100/255: 39.21 % 110/255: 43.09 % 120/255: 46.97 % 130/255: 50.85 % 140/255: 54.79 % 150/255: 58.61 % 160/255: 62.48 % 170/255: 66.42 % 180/255: 70.24 % 190/255: 74.12 % 200/255: 77.70 % 210/255: 81.21 % 220/255: 84.91 % 230/255: 88.67 % 240/255: 92.67 % 250/255: 96.97 % 255/255: 99.21 % Output % at 127/255 49.70 % 49.70 % 49.70 % 49.70 % 49.70 % 49.70 % 49.70 % 49.70 % 49.76 % 49.76 % 49.70 %