#########################################################################################
# Package HiPi::Interface::MCP4DAC
# Description : Control MCP4xxx Digital 2 Analog ICs
# Copyright : Copyright (c) 2013-2017 Mark Dootson
# License : This is free software; you can redistribute it and/or modify it under
# the same terms as the Perl 5 programming language system itself.
#########################################################################################
package HiPi::Interface::MCP4DAC;
#########################################################################################
use strict;
use warnings;
use parent qw( HiPi::Interface );
use Carp;
use HiPi qw( :spi :mcp4dac );
use HiPi::Device::SPI;
our $VERSION ='0.67';
__PACKAGE__->create_accessors( qw( bitsperword minvar ic devicename
dualchannel canbuffer buffer gain
writemask shiftvalue shiftbits ) );
sub new {
my( $class, %userparams ) = @_;
my %params = (
devicename => '/dev/spidev0.0',
speed => SPI_SPEED_MHZ_1,
bitsperword => 8,
delay => 0,
device => undef,
ic => MCP4902,
buffer => 0,
gain => 0,
shiftvalue => 0,
);
foreach my $key (sort keys(%userparams)) {
$params{$key} = $userparams{$key};
}
{
my $ic = $params{ic};
if( $ic & MCP_DAC_RESOLUTION_12 ) {
$params{minvar} = 0;
$params{shiftbits} = 0;
$params{writemask} = 0b1111111111111111;
} elsif( $ic & MCP_DAC_RESOLUTION_10 ) {
$params{minvar} = 4;
$params{shiftbits} = 2;
$params{writemask} = 0b1111111111111100;
} else {
$params{minvar} = 16;
$params{shiftbits} = 4;
$params{writemask} = 0b1111111111110000;
}
if( $ic & MCP_DAC_CAN_BUFFER ) {
$params{canbuffer} = 1;
} else {
$params{canbuffer} = 0;
}
if( $ic & MCP_DAC_DUAL_CHANNEL ) {
$params{dualchannel} = 1;
} else {
$params{dualchannel} = 0;
}
}
unless( defined($params{device}) ) {
my $dev = HiPi::Device::SPI->new(
speed => $params{speed},
bitsperword => $params{bitsperword},
delay => $params{delay},
devicename => $params{devicename},
);
$params{device} = $dev;
}
my $self = $class->SUPER::new(%params);
return $self;
}
sub write {
my($self, $value, $channelb) = @_;
$channelb ||= 0;
$channelb = 0 if !$self->dualchannel;
my $output = ( $channelb ) ? MCP_DAC_CHANNEL_B : MCP_DAC_CHANNEL_A;
$output += MCP_DAC_BUFFER if($self->canbuffer && $self->buffer);
$output += ( $self->gain ) ? MCP_DAC_GAIN : MCP_DAC_NO_GAIN;
$output += MCP_DAC_LIVE;
# allow user to specify values 1-255 for 8 bit device etc
if( $self->shiftvalue ) {
$value <<= $self->shiftbits;
}
# mask the $value. If user specifies shiftvalue == true
# and gives a value over 255 for an 8 bit device
# confusing things will happen. We only want
# 12 bits. If user gets it wrong then at least
# all that happens is they get wrong voltage -
# instead of potentially writing to wrong channel
# or shutting the channel down if we shift a high value
$value &= 0b111111111111;
$value = $self->minvar if( $value > 0 && $value < $self->minvar );
$value = 0 if $value < 0;
$output += $value;
$output &= $self->writemask;
$self->device->transfer( $self->_fmt_val( $output ) );
}
sub _fmt_val {
my($self, $val) = @_;
pack('n', $val);
}
sub shutdown {
my($self, $channelb) = @_;
$channelb ||= 0;
$channelb = 0 if !$self->dualchannel;
my $output = ( $channelb ) ? MCP_DAC_CHANNEL_B : MCP_DAC_CHANNEL_A;
$output += MCP_DAC_SHUTDOWN;
$self->device->transfer( $self->_fmt_val( $output ) );
}
1;
__END__