Skip to content

Commit

Permalink
Added differential amplifier api as a library
Browse files Browse the repository at this point in the history
  • Loading branch information
dbuezas committed Sep 2, 2019
1 parent e499f4a commit 06e71d5
Show file tree
Hide file tree
Showing 8 changed files with 365 additions and 8 deletions.
86 changes: 81 additions & 5 deletions docs/differential-amplifier/readme.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,83 @@
# Differential Amplifier

<img src="ADC Control Reg C.png" alt="Boards Manager" />
<img src="ADC Multiplexer.png" alt="Boards Manager" />
<img src="ADC Register List.png" alt="Boards Manager" />
<img src="Diagram.png" alt="Boards Manager" />
<img src="Differential Amplifier.png" alt="Boards Manager" />
## Usage:

- See examples/differential_amplifier

```
int output = analogDiffRead(A0, A1, GAIN_8);
// output = (A1 - A0) * 8
int invalid_output = analogDiffRead(A0, A5, GAIN_8);
// invalid_output = -1
```

- Available pin combinations

| -\+ | A0 | A1 | A2 | A3 | A4 | A5 | A6 | A7 | A8 | A9 |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| A0 | || | | | | | | | |
| A1 || | | | | | | | | |
| A2 ||| ||||||||
| A3 |||| |||||||
| A4 ||| | | | | | | | |
| A5 ||| | | | | | | | |
| A6 ||| | | | | | | | |
| A7 ||| | | | | | | | |
| A8 ||||||||| ||
| A9 |||||||||| |

Also see the examples in the DAO library provided by this core.

## How does it work?

### Basics

The differential amplifier (DAP) has 2 inputs (`inverting`/minus and `non-inverting`/plus), a `gain` value and 1 `output`.

```
output = gain * (non-inverting - inverting)
```

And the output can be read through the ADC (like a normal analog read).

All information was extracted from this translation of the datasheet: [(English) LGT8FX8P_databook_V1.04](../LGT8FX8P_databook_v1.0.4.en.pdf) (thanks to [metallurge](https://github.com/metallurge) for the translated doc [here](https://github.com/RalphBacon/LGT8F328P-Arduino-Clone-Chip-ATMega328P/issues/2#issuecomment-517952757))

<img src="Diagram.png" alt="ADC Structure chart. Page 232" />

### Algorithm:

1. Setup the inputs and gain and turn DAO on through the DAPRC (Differential amplifier control register):

`DAPCR = DAPEN | gain | inverting | noninverting;`

- Enable: DAPEN
- Gain: GA[1:0]
- Inverting input: DNS[2:0]
- Non inverting input: DPS[1:0]
Important: Only one input can use the multiplexer. This means that not all combinations of pins can be compared (See table in the library source)
- <img src="Differential Amplifier.png" alt="DAPRC. Page 243" />

2. Configure the ADC input to use the Differential amplifier instead of reading directly from the analog pins

`ADCSRC |= DIFS_DIFFAMP;`

- ADC input switch: DIFS
<img src="ADC Control Reg C.png" alt="ADCSRC. Page 243 " />

3. Setup the multiplexer if necessary and make the reading

`int res = analogRead(inverting == INVERTING_MXER ? pin1 : pin2);`

- For this, I'm just reusing the standard `analogRead(pin)` function which also configures the multiplexer.
- Note: for some pin combinations it is not necessary to use the multiplexer, but for the sake of simplicity I still use the normal `analogRead(pin)` function. In this case it doesn't matter which pin is passed to the function, as the DAO won't use the output of the multiplexer.
- <img src="ADC Multiplexer.png" alt="DAPRC. Page 243" />

4. Cleanup:

- Turn DAO off:

`DAPCR &= ~DAPEN;`

- Undo step (3) (reconnect ADC to multiplexer for future normal analogRead calls)

`ADCSRC &= ~DIFS_DIFFAMP;`
3 changes: 2 additions & 1 deletion lgt8f/cores/lgt8f/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ int main(void)
#if defined(USBCON)
USBDevice.attach();
#endif

/* START CHANGE BY DBUEZAS */
// set clock prescaler
CLKPR = 0x80;
#if F_CPU == 32000000L
Expand All @@ -136,6 +136,7 @@ int main(void)
#elif F_CPU == 1000000L
CLKPR = 0x05;
#endif
/* END CHANGE BY DBUEZAS */
setup();

for (;;) {
Expand Down
111 changes: 111 additions & 0 deletions lgt8f/libraries/differential_amplifier/differential_amplifier.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*
DAP.cpp - Differential Amplifier library
Copyright (c) 2019 David Buezas. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include "differential_amplifier.h"
#include "wiring_analog.c"
/** DAPCR Differential Ampliifier Control Register **/
// enable DAP | gain | inverting | non-inverting
// DAPEN | GA1 GA0 | DNS2 DNS1 DNS0 | DPS1 DPS0

#define DAPEN 0b1 << 7

#define INVERTING_ADC2 0b000 << 2
#define INVERTING_ADC3 0b001 << 2
#if defined(__LGT8FX8P48__)
#define INVERTING_ADC8 0b010 << 2
#define INVERTING_ADC9 0b011 << 2
#endif
#define INVERTING_APN4 0b100 << 2 // PE0/APN4/SCWD, not normally exposed
#define INVERTING_MXER 0b101 << 2
#define INVERTING_GRND 0b110 << 2
#define INVERTING_CLOSE 0b111 << 2

#define NONINVERTING_MXER 0b00 << 0
#define NONINVERTING_ADC0 0b01 << 0
#define NONINVERTING_ADC1 0b10 << 0
#define NONINVERTING_GRND 0b11 << 0

/** ADCSRC ADC Control Status Register C **/
/*
| offset compensation | n/a | calibration | auto monitoring |
| OFEN | x | SPN | AMEN |
...
| x | SPD | DIFS | ADTM |
| n/a | fast | 0=MXER 1=DIFF-AMP | test mode |
*/

#define ADTM 0b1 << 0
#define DIFS_MXER 0b0 << 1
#define DIFS_DIFFAMP 0b1 << 1
#define SPD_FAST 0b1 << 2
#define AMEN 0b1 << 4
#define SPN 0b1 << 5
#define OFEN 0b1 << 7

int analogDiffRead(uint8_t negativePin, uint8_t positivePin, uint8_t gain) {
uint8_t inverting;
uint8_t muxedPin = A0;
switch (negativePin) {
case A2:
inverting = INVERTING_ADC2;
break;
case A3:
inverting = INVERTING_ADC3;
break;
#if defined(__LGT8FX8P48__)
case A8:
inverting = INVERTING_ADC8;
break;
case A9:
inverting = INVERTING_ADC9;
break;
#endif
default:
inverting = INVERTING_MXER;
muxedPin = negativePin;
}
uint8_t noninverting;
switch (positivePin) {
case A0:
noninverting = NONINVERTING_ADC0;
break;
case A1:
noninverting = NONINVERTING_ADC1;
break;
default:
noninverting = NONINVERTING_MXER;
muxedPin = positivePin;
}
if (negativePin == positivePin ||
inverting == INVERTING_MXER && noninverting == NONINVERTING_MXER) {
// combination not allowed
return -1;
}
// enable | gain | inverting | non-inverting
// DAPEN | GA1 GA0 | DNS2 DNS1 DNS0 | DPS1 DPS0
DAPCR = DAPEN | gain | inverting | noninverting; // get right side
ADCSRC |= DIFS_DIFFAMP; // set Diff. Amp. as source for the ADC
// Note: analogRead() will configure the muxer even if the multiplexer is not
// used by neither the inverting nor the noninverting pin, but that's fine
// because the ADC won't read it
int res = analogRead(muxedPin);
DAPCR &= ~DAPEN; // disable Diff. Amp.
ADCSRC &= ~DIFS_DIFFAMP; // set back the Muxer as source for the ADC
return res;
}
50 changes: 50 additions & 0 deletions lgt8f/libraries/differential_amplifier/differential_amplifier.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
DAP.h - Differential Amplifier library
Copyright (c) 2019 David Buezas. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include <inttypes.h>

#define GAIN_1 0b00 << 5
#define GAIN_8 0b01 << 5
#define GAIN_16 0b10 << 5
#define GAIN_32 0b11 << 5

/*
Reads the amplified difference between two pins.
\param negativePin The pin (A0-A9) with the lowest voltage.
\param positiveePin The pin (A0-A9) with the highest voltage.
\param gain The gain. Use constants GAIN_1, GAIN_8, GAIN_16, GAIN_32
\returns int: (positivePin - negativePin) * gain if combination is available
\returns -1 if combination is NOT available
Available combinations:
| -\+ | A0 | A1 | A2 | A3 | A4 | A5 | A6 | A7 | A8 | A9 |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| A0 | | ✓ | | | | | | | | |
| A1 | ✓ | | | | | | | | | |
| A2 | ✓ | ✓ | | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| A3 | ✓ | ✓ | ✓ | | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| A4 | ✓ | ✓ | | | | | | | | |
| A5 | ✓ | ✓ | | | | | | | | |
| A6 | ✓ | ✓ | | | | | | | | |
| A7 | ✓ | ✓ | | | | | | | | |
| A8 | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | ✓ |
| A9 | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | |
*/
int analogDiffRead(uint8_t negativePin, uint8_t positivePin, uint8_t gain);
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
//============================================
// Differential Amplifier demo for LGT8F328x
// by dbuezas
// Using new differential_amplifier library.
// Differential read from all analog pin combinations
//============================================
#include "differential_amplifier.h"

#define GAIN GAIN_1
// #define GAIN GAIN_8
// #define GAIN GAIN_16
// #define GAIN GAIN_32

void setup() {
Serial.begin(230400);
Serial.println("start");
// analogReference(DEFAULT); // 5v
}
void loop() {
static byte list[] = {A0, A1, A2, A3, A4, A5, A6, A7};
static const byte list_length(sizeof(list) / sizeof(list[0]));
Serial.print("-\\+\t");
for (int pos = 0; pos < list_length; pos++) {
Serial.print("A");
Serial.print(pos);
Serial.print("\t");
}
Serial.println();
for (int neg = 0; neg < list_length; neg++) {
Serial.print("A");
Serial.print(neg);
Serial.print("\t");
for (int pos = 0; pos < list_length; pos++) {
int value = analogDiffRead(list[neg], list[pos], GAIN);
if (neg == pos) {
Serial.print("x");
} else if (value == -1) {
Serial.print("."); // -1 means pin combination not available
} else {
Serial.print(value);
}
Serial.print("\t");
}
Serial.println();
}
Serial.println("--------");
delay(100);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//============================================
// Differential Amplifier demo for LGT8F328x
// by dbuezas
// Using new differential_amplifier library.
// Connect A1 to the voltage source (0..5v) and D4 to A0 with a jumper wire
// Open the Serial Plotter and you'll see how the DAC in D4 will follow the
// voltage read by A1
//============================================
#include "differential_amplifier.h"

#define INPUT_VOLTAGE_PIN A1
#define DAC_PIN DAC0 // D4 in the silk screen
#define DAC_READER_PIN A0

void setup() {
Serial.begin(230400);
Serial.println("start");
analogReference(DEFAULT); // 5v. If not set, the DAC only gets to 1v
pinMode(DAC0, ANALOG); // DAC0 = D4
}

float dac_value = 0;
void loop() {
if (dac_value < 0) dac_value = 0;
if (dac_value > 255) dac_value = 255;
analogWrite(DAC_PIN, (int)dac_value);

int minus = analogDiffRead(INPUT_VOLTAGE_PIN, DAC_READER_PIN, GAIN_1);
int plus = analogDiffRead(DAC_READER_PIN, INPUT_VOLTAGE_PIN, GAIN_1);

float error = minus > plus ? minus : -plus;
int actual = analogRead(INPUT_VOLTAGE_PIN);
int followed = analogRead(DAC_READER_PIN);
Serial.print("\tactual: ");
Serial.print(actual);
Serial.print("\tfollowed: ");
Serial.print(followed);
Serial.println();

dac_value -= error / 1000;
delay(10);
return;
}
21 changes: 21 additions & 0 deletions lgt8f/libraries/differential_amplifier/keywords.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#######################################
# Syntax Coloring Map For Ultrasound
#######################################

#######################################
# Datatypes (KEYWORD1)
#######################################


#######################################
# Methods and Functions (KEYWORD2)
#######################################

#######################################
# Constants (LITERAL1)
#######################################
GAIN_1 LITERAL1
GAIN_8 LITERAL1
GAIN_16 LITERAL1
GAIN_32 LITERAL1

Loading

0 comments on commit 06e71d5

Please sign in to comment.