/*
* pga23xx.cpp: burr brown volume control chip (spi based)
*
*
* (part of the "VoluMaster(tm)" system)
*
* An open-source arduino controller-based digital volume control and input/output selector
*
*
* LICENSE
* -------
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "pga23xx.h"
#include
#include //not needed yet
#include //needed for strlen()
#include
#include "WConstants.h" //all things wiring / arduino
#include "config.h"
// ctor
PGA23XX::PGA23XX( void )
{
}
// dtor
//
//PGA23XX::~PGA23XX( void )
//{
//}
void
PGA23XX::init( void )
{
#ifdef USE_PGA_SPI
pinMode(PGA_CS_PIN, OUTPUT); // pga-chipselect pin
pinMode(PGA_SDATA_PIN, OUTPUT); // pga-data-out (our data out to it) pin
pinMode(PGA_SCK_PIN, OUTPUT); // pga-clock pin
#endif
#ifdef USE_PGA_I2C
PCF8574_PE_write(0x00);
#endif
}
#ifdef SINGLE_DB_STEPS
void
PGA23XX::map_pga_value_to_db( uint8_t pga_int_value, uint8_t *db_value, uint8_t *negative_db, uint8_t *half_db_flag )
{
int db = (pga_int_value - 96);
*half_db_flag = 0;
if (db < 0) {
*negative_db = 1; // true
*db_value = (byte)(-db); // make it positive (abs value)
}
else {
*negative_db = 0; // false
*db_value = (byte)db;
}
}
#endif
#ifdef HALF_DB_STEPS
void
PGA23XX::map_pga_value_to_db( uint8_t pga_int_value, uint8_t *db_value, uint8_t *negative_db, uint8_t *half_db_flag )
{
float db = 31.5 - (255.0 - (float)pga_int_value) / 2.0;
// odd numbers in the 0..255 range mean half-db values
if ( (pga_int_value & 0x01) == 1) {
*half_db_flag = 1;
} else {
*half_db_flag = 0;
}
if (db < 0) {
*negative_db = 1; // true
*db_value = (byte)(-db); // make it positive (abs value)
}
else {
*negative_db = 0; // false
*db_value = (byte)db;
}
}
#endif
/*
* philips (like) i2c to parallel 8bit port expander chip
*/
#ifdef USE_PGA_I2C
void
PGA23XX::PCF8574_PE_write( uint8_t _data )
{
Wire.beginTransmission(I2C_PGA_PE_ADDR);
Wire.send(_data);
Wire.endTransmission();
}
#endif // USE_PGA_I2C
#ifdef USE_PGA_I2C
uint8_t
PGA23XX::PCF8574_PE_read( void )
{
uint8_t _data;
Wire.requestFrom(I2C_PGA_PE_ADDR, 1);
if (Wire.available()) {
_data = Wire.receive();
}
return _data;
}
#endif // USE_PGA_I2C
#ifdef USE_PGA_SPI
void
PGA23XX::SPI_write( uint8_t out_spi_byte )
{
uint8_t i;
#ifdef DEBUG_PGA
Serial.print("PGA:");
Serial.println((int)out_spi_byte);
#endif
// loop thru each of the 8-bits in the byte
for (i=0; i < 8; i++) {
// strobe clock
//PCF8574_PE_write(PGA_I2C_CS_LOW | PGA_I2C_SCK_LOW | PGA_I2C_SDATA_LOW);
digitalWrite(PGA_SCK_PIN, LOW);
// send the bit (we look at the high order bit and 'print' that to the remote device)
if (0x80 & out_spi_byte) { // MSB is set
//PCF8574_PE_write(PGA_I2C_CS_LOW | PGA_I2C_SCK_LOW | PGA_I2C_SDATA_HI);
digitalWrite(PGA_SDATA_PIN, HIGH);
} else {
//PCF8574_PE_write(PGA_I2C_CS_LOW | PGA_I2C_SCK_LOW | PGA_I2C_SDATA_LOW);
digitalWrite(PGA_SDATA_PIN, LOW);
}
// unstrobe the clock via local SPI
digitalWrite(PGA_SCK_PIN, HIGH);
// unstrobe via i2c
if (0x80 & out_spi_byte) { // MSB is set
//PCF8574_PE_write(PGA_I2C_CS_LOW | PGA_I2C_SCK_HI | PGA_I2C_SDATA_HI);
} else {
//PCF8574_PE_write(PGA_I2C_CS_LOW | PGA_I2C_SCK_HI | PGA_I2C_SDATA_LOW);
}
// get the next bit
out_spi_byte <<= 1; // left-shift the byte by 1 bit
}
}
#endif
#ifdef USE_PGA_I2C
void
PGA23XX::SPI_write( uint8_t out_spi_byte )
{
uint8_t i;
#ifdef DEBUG_PGA
Serial.print("PGA:");
Serial.println((int)out_spi_byte);
#endif
// loop thru each of the 8-bits in the byte
for (i=0; i < 8; i++) {
// strobe clock
PCF8574_PE_write(PGA_I2C_CS_LOW | PGA_I2C_SCK_LOW | PGA_I2C_SDATA_LOW);
//digitalWrite(PGA_SCK_PIN, LOW);
// send the bit (we look at the high order bit and 'print' that to the remote device)
if (0x80 & out_spi_byte) { // MSB is set
PCF8574_PE_write(PGA_I2C_CS_LOW | PGA_I2C_SCK_LOW | PGA_I2C_SDATA_HI);
//digitalWrite(PGA_SDATA_PIN, HIGH);
} else {
PCF8574_PE_write(PGA_I2C_CS_LOW | PGA_I2C_SCK_LOW | PGA_I2C_SDATA_LOW);
//digitalWrite(PGA_SDATA_PIN, LOW);
}
// unstrobe the clock via local SPI
//digitalWrite(PGA_SCK_PIN, HIGH);
// unstrobe via i2c
if (0x80 & out_spi_byte) { // MSB is set
PCF8574_PE_write(PGA_I2C_CS_LOW | PGA_I2C_SCK_HI | PGA_I2C_SDATA_HI);
} else {
PCF8574_PE_write(PGA_I2C_CS_LOW | PGA_I2C_SCK_HI | PGA_I2C_SDATA_LOW);
}
// get the next bit
out_spi_byte <<= 1; // left-shift the byte by 1 bit
}
}
#endif
#ifdef USE_PGA_SPI
// note, for typical use, we assume left==right
void
PGA23XX::PGA_set_volume( uint8_t left, uint8_t right )
{
digitalWrite(PGA_CS_PIN, LOW); // assert CS
SPI_write(left /*<< 1*/); // left value (0..255)
SPI_write(right /*<< 1*/); // right value (0..255)
digitalWrite(PGA_CS_PIN, HIGH); // deassert CS
}
#endif
#ifdef USE_PGA_I2C
// note, for typical use, we assume left==right
void
PGA23XX::set_volume( uint8_t left, uint8_t right )
{
PCF8574_PE_write(PGA_I2C_CS_HI); // start from high (logical-NOT on chip-select)
//delayMicroseconds(5);
PCF8574_PE_write(PGA_I2C_CS_LOW); // begin getting the chip's attention
SPI_write(left /*<< 1*/); // left value (0..255)
SPI_write(right /*<< 1*/); // right value (0..255)
PCF8574_PE_write(PGA_I2C_CS_HI);
//delayMicroseconds(5);
}
#endif