simpleSA/pE4302.cpp

233 lines
6.6 KiB
C++
Raw Normal View History

2020-08-16 02:03:43 +08:00
/*
* "PE4302.cpp"
*
* Added to the "TinySA" program in Version 1.1 by John Price (WA2FZW):
* Updated in V2.5 by M0WID
*
* Functions to handle the PE4302 attenuator and support for using the PCF8574
* I2C GPIO expander to drive a parallel version of the PE4302 module.
*/
#include "pE4302.h"
2020-08-16 02:03:43 +08:00
/*
* Create a "PCF8574" object with the default I2C address
* for the basic PCF8574 (if using a PCF8574A, the default address would be
* 0x38).
*
* Please note, we also assume that the PCF8574 is on the standard I2C bus
* pins for the processor being used (21 & 22 for the ESP32; different for
* Arduinos).
*
* The address is updated by the PCF8574 constructor.
*/
PCF8574 _pcf ( 0x28 ); // Create the PCF8574 object
/*
* The PE4302 chip can be operated in either a serial or parallel mode.
* Most pre-built modules are set for parallel but by changing some jumpers
* can be used in serial mode.
*/
/*
* Serial interface constructor:
*
* The arguments are a pointer to the SPI class used and pin definition
* for Latch Enable "LE" pin. When "LE" is HIGH the data in the serial
* buffer is latched. "LE" must be LOW when the SPI bus is used for other
* objects (which it is).
*
* The SPI object can be shared with other objects, so is declared in the main sketch
*
* SPIClass* vspi = new SPIClass ( VSPI );
* or SPIClass* hspi = new SPIClass ( HSPI );
*
* The SPI object is initialized once in the main sketch setup, along with the
* relevant pins, e.g.:
*
* pinMode ( V_SCLK, OUTPUT ); // SPI Clock pin
* pinMode ( V_SDO, INPUT ); // SDO (MISO) pin
* pinMode ( V_SDI, OUTPUT ); // SDI (MOSI) pin
*
* digitalWrite ( V_SCLK, LOW ); // Make SPI clock LOW
* digitalWrite ( V_SDI, LOW ); // Along with MOSI
*
* vspi->begin ( V_SCLK, V_SDO, V_SDI ); // Start the VSPI: SCLK, MISO, MOSI
*/
PE4302::PE4302 ( SPIClass* spi, int le ) // Constructor for serial interface
{
_interface = S; // SPI (serial)interface
_le_Pin = le; // Enable (LE) pin number
pinMode ( _le_Pin, OUTPUT ); // Chip select pin is an output
digitalWrite ( _le_Pin, LOW ); // Deselect the module
_spi = spi; // Save SPI object pointer
}
/*
* Parallel GPIO interface constructor:
* arguments are the GPIO pin assignments that correspond to the "C16" to
* "C0.5" pins of the chip.
*/
PE4302::PE4302 ( int c16, int c8, int c4,
int c2, int c1, int c0 )
{
_interface = P; // Parallel interface
_parallel_Pins[0] = c0; // The actual GPIO pin numbers
_parallel_Pins[1] = c1; // can be random as opposed
_parallel_Pins[2] = c2; // to David's requirement that
_parallel_Pins[3] = c4; // they had to be consecutive.
_parallel_Pins[4] = c8; // The array order is LSB to MSB.
_parallel_Pins[5] = c16;
}
/*
* PCF8574 (I2C IO expander interface) constructor:
* The default address set at the beginning of the module assumes that the
* chip in use is a PCF8574. The PCF8574A may also be used, however its
* default address is 0x38, so you might need to provide a different address
* here.
*/
PE4302::PE4302 ( int address ) // Constructor for PCF8574 interface
{
_interface = PCF; // PCF8574 interface
_pcf_I2C = address; // I2C bus address of the PCF8574
_pcf = PCF8574 ( address ); // Update the object with the address
}
/*
* "PE4302_init" - Initialize the attenuator module.
*/
void PE4302::Init ()
{
if ( _interface == S ) // If using the serial mode
{
// nothing to do!
}
else if ( _interface == P ) // If using the parallel mode
{
for ( int i = 0; i < 6; i++ )
pinMode ( _parallel_Pins[i], OUTPUT ); // All 6 pins are outputs
}
else if ( _interface == PCF ) // If using the PCF8574
{
_pcf.begin ( _pcf_I2C, 0 ); // Initialize the chip
}
}
/*
* "SetAtten" - Set the attenuation.
*
* The parameter is the required attenuation in dB.
* The PE4302 allows attenuation to be set in 0.5dB increments, but not here!
* If the requested attenuation is out of limits the function will return "false".
*/
bool PE4302::SetAtten ( int8_t atten )
{
bool retCode = true; // Assume good number
if ( atten > PE4302_MAX ) // Maximum is defined in "My_SA.h"
{
atten = PE4302_MAX;
retCode = false; // Indicate bad number
}
if ( atten < 0 ) // Can't be less than zero
{
atten = 0;
retCode = false; // Indicate bad number
}
_atten = atten << 1; // Double the number and save it
if ( _interface == S ) // If using the serial mode
{
// Serial.printf ( "SetAtten %i - clk:%i data:%i LE:%i \n",
// _atten, _clock_Pin, _data_Pin, _le_Pin);
uint32_t oldDivider = _spi->getClockDivider(); // run at 1MHz
_spi->setFrequency(1000000); // run at 1MHz
digitalWrite ( _le_Pin, LOW ); // Make the sure the attenuator is not using the shifted in data
_spi->transfer ( _atten ); // Send the attenution value bit pattern
digitalWrite ( _le_Pin, HIGH ); // Latch Enable pin HIGH
digitalWrite ( _le_Pin, LOW ); // Then immediately LOW
_spi->setClockDivider(oldDivider); // back to whatever speed it was running before
}
else if ( _interface == P ) // If using the parallel mode
{
for ( int i = 0; i < 6; i++ )
digitalWrite ( _parallel_Pins[i], _atten & ( 1 << i ));
}
else if ( _interface == PCF ) // If using the PCF8574
{
_pcf.write8 ( _atten );
}
return retCode; // Send back good/bad indication
}
/*
* Return current attenuation value.
* Bit pattern has to be divided by two to return dB
*/
int PE4302::GetAtten () // Send back stored attenuation
{
return _atten >> 1;
}
/*
* These functions implement the stripped down PCF8574 library:
*/
PCF8574::PCF8574 ( const uint8_t deviceAddress )
{
_address = deviceAddress;
_dataOut = 0;
}
/*
* The "begin" function is modified from the original to allow us to change the
* I2C address as well as set an inital output value:
*/
void PCF8574::begin ( const uint8_t deviceAddress, uint8_t val )
{
_address = deviceAddress; // Save address
Wire.begin (); // Initialize the I2C interface
PCF8574::write8 ( val ); // Output the initial value
}
void PCF8574::write8 ( const uint8_t value )
{
_dataOut = value; // Save value to be output
Wire.beginTransmission ( _address ); // Start the transmission process
Wire.write ( _dataOut ); // Send the data
Wire.endTransmission (); // Wasn't in original library
}