diff --git a/docs/differential-amplifier/readme.md b/docs/differential-amplifier/readme.md index fe7aba8..b2f789a 100644 --- a/docs/differential-amplifier/readme.md +++ b/docs/differential-amplifier/readme.md @@ -1,7 +1,83 @@ # Differential Amplifier -Boards Manager -Boards Manager -Boards Manager -Boards Manager -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)) + +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) + - 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 + 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. + - 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;` diff --git a/lgt8f/cores/lgt8f/main.cpp b/lgt8f/cores/lgt8f/main.cpp index 4a82e59..b1fb109 100755 --- a/lgt8f/cores/lgt8f/main.cpp +++ b/lgt8f/cores/lgt8f/main.cpp @@ -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 @@ -136,6 +136,7 @@ int main(void) #elif F_CPU == 1000000L CLKPR = 0x05; #endif +/* END CHANGE BY DBUEZAS */ setup(); for (;;) { diff --git a/lgt8f/libraries/differential_amplifier/differential_amplifier.cpp b/lgt8f/libraries/differential_amplifier/differential_amplifier.cpp new file mode 100644 index 0000000..9590c88 --- /dev/null +++ b/lgt8f/libraries/differential_amplifier/differential_amplifier.cpp @@ -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; +} diff --git a/lgt8f/libraries/differential_amplifier/differential_amplifier.h b/lgt8f/libraries/differential_amplifier/differential_amplifier.h new file mode 100644 index 0000000..5c77b63 --- /dev/null +++ b/lgt8f/libraries/differential_amplifier/differential_amplifier.h @@ -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 + +#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); diff --git a/lgt8f/libraries/differential_amplifier/examples/all_vs_all/all_vs_all.ino b/lgt8f/libraries/differential_amplifier/examples/all_vs_all/all_vs_all.ino new file mode 100755 index 0000000..9749258 --- /dev/null +++ b/lgt8f/libraries/differential_amplifier/examples/all_vs_all/all_vs_all.ino @@ -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); +} diff --git a/lgt8f/libraries/differential_amplifier/examples/voltage_follower/voltage_follower.ino b/lgt8f/libraries/differential_amplifier/examples/voltage_follower/voltage_follower.ino new file mode 100755 index 0000000..6d0cfc6 --- /dev/null +++ b/lgt8f/libraries/differential_amplifier/examples/voltage_follower/voltage_follower.ino @@ -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; +} \ No newline at end of file diff --git a/lgt8f/libraries/differential_amplifier/keywords.txt b/lgt8f/libraries/differential_amplifier/keywords.txt new file mode 100755 index 0000000..2607348 --- /dev/null +++ b/lgt8f/libraries/differential_amplifier/keywords.txt @@ -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 + diff --git a/readme.md b/readme.md index 3471693..b88b350 100644 --- a/readme.md +++ b/readme.md @@ -25,10 +25,17 @@ Now the boards appear in the IDE and you can also select the clock speed. - [x] Digital Analog Converter - [x] Voltage References INTERNAL1V024/INTERNAL2V048/INTERNAL4V096/DEFAULT/EXTERNAL (useful for example for analogRead or DAC analogWrite via analogReference(xxx)); - [ ] Analog Comparator -- [ ] [Differential Amplifier](./docs/differential-amplifier/readme.md) +- [x] [Differential Amplifier](./docs/differential-amplifier/readme.md) - [ ] Computation Accelerator -# Power consumption +# Differences to original core (https://github.com/LGTMCU/Larduino_HSP) + +- Support 32 Mhz and other clock speeds +- Differential Amplifier API +- Better Boards Menu +- Installation via Board Manager Urls + +# Power consumption @ 5v - 32Mhz 32.6mA - 16Mhz 27.8mA