
Waterfall next, then speed up frequency changes with offsets and reduce delaytime. Sort out 1 pixel error at start/end
233 lines
6.6 KiB
C++
233 lines
6.6 KiB
C++
/*
|
|
* "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"
|
|
|
|
|
|
/*
|
|
* 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
|
|
}
|