#include<Wire.h>
#define AD7991REF 2.60
int8_t ad7991_addr = 0; // Address of AD7991 I2C connected A/D, 0 if none detected
#define AD7991_0 0x28 // I2C Address of AD7991-0
#define AD7991_1 0x29 // I2C Address of AD7991-1
#define I2C Wire
double adc_ref; // ADC reference (Teensy or external AD7991)
int16_t fwd; // AD input - 12 bit value, v-forward
int16_t rev; // AD input - 12 bit value, v-reverse
typedef struct {
int16_t fwd[256]; // Circular buffer of Forward measurement values
int16_t rev[256]; // Circular buffer of Reverse measurement values
uint8_t incount; // Pointer to most recent input value of circular buffer
uint8_t outcount; // Pointer to most recent output value of circular buffer
} adbuffer_t;
volatile adbuffer_t measure;
void setup()
{
// Initialise I2C communication as MASTER
Wire.begin();
Wire.setClock(2000000);
Serial.begin(115200);
I2C_Init();
}
void loop()
{
adc_ref = 2.60;
double output_voltage;
output_voltage = fwd * adc_ref / 2048;
Serial.println(output_voltage,4);
adc_poll_and_feed_circular();
pswr_sync_from_interrupt();
}
uint8_t I2C_Init(void)
{
uint8_t found; // Returns status of I2C bus scan
// Scan for AD7991-0 or AD7991-1
ad7991_addr = AD7991_1; // We start testing for an AD7991-1
found = 2; // Assume it will be found
I2C.beginTransmission(ad7991_addr);
if(I2C.endTransmission() != 0) // If error
{
ad7991_addr = AD7991_0; // AD7991-0 was not detected
found = 1; // We may have an AD7991-0
}
I2C.beginTransmission(ad7991_addr);
if(I2C.endTransmission() != 0) // If error
{
ad7991_addr = 0; // AD7991-1 was not detected
found = 0; // No I2C capable device was detected
}
// If Power & SWR Code and AD7991 12 bit ADC, the program it to use a 2.6V reference connected
// to ADC channel 4 and only read ADC channels 1 and 2 consecutively.
//
if (found) // If AD7991 ADC was found, then configure it...
{
I2C.beginTransmission(ad7991_addr);
I2C.write(0x38); // Set ADCs 1 and 2 for consecutive reads and REF_SEL = external
I2C.endTransmission();
adc_ref = 2.600; // Readjust the ADC reference to the external REF voltage
}
return found;
}
//-----------------------------------------------------------------------------------------
// Poll the AD7991 2 x ADC chip
// or alternately
// use built-in 12 bit A/D converters if I2C device not present
// This function is called from the Interrupt function, and
// reads the A/D inputs and transfers them to two circular buffers
//-----------------------------------------------------------------------------------------
void adc_poll_and_feed_circular(void)
{
uint16_t adc_in[4];
uint8_t read_B[4];
uint8_t i=0;
// use I2C connected AD7991 12-bit AD converter, if it was detected during init
// Each I2C poll of the AD7991 is measured to take 140us
if (ad7991_addr)
{
I2C.requestFrom(ad7991_addr, 4);
while (I2C.available()) read_B[i++] = I2C.read();
// The output of the 12bit ADCs is contained in two consecutive byte pairs
// read from the AD7991. In theory, the second could be read before the first.
// Each of the AD7991 four builtin ADCs has an address identifier (0 to 3)
// in the uppermost 4 bits of the first byte. The lowermost 4 bits of the first
// byte are bits 8-12 of the A/D output.
// In this routine we only read the two first ADCs, as set up in the I2C_Init()
//
adc_in[(read_B[0] >> 4) & 0x03] = (read_B[0] & 0x0f) * 0x100 + read_B[1];
adc_in[(read_B[2] >> 4) & 0x03] = (read_B[2] & 0x0f) * 0x100 + read_B[3];
measure.fwd[measure.incount] = adc_in[0]; // Input from AD7991 is 12 bit resolution
measure.rev[measure.incount] = adc_in[1]; // contained in bit positions 0 to 11.
measure.incount++; // 8 bit value, rolls over at 256
}
}
//---------------------------------------------------------------------------------
// Process circular buffers being fed by the Interrupt function
//---------------------------------------------------------------------------------
void pswr_sync_from_interrupt(void)
{
uint8_t in;
noInterrupts();
in = measure.incount;
interrupts();
while (measure.outcount != in) // Read from circular buffer, while new input available
{
noInterrupts();
fwd = measure.fwd[measure.outcount]; // Transfer data from circular buffers
rev = measure.rev[measure.outcount];
interrupts();
measure.outcount++; // 8 bit value, rolls over at 256
noInterrupts(); // Perhaps a bit redundant - squeeze every last drop while we're at it
in = measure.incount;
interrupts();
}
}