Pro Micro, AIN0/D7 OK but can't relate any other pin with the analog comparator (lib 1.2.4, Arduino IDE 1.8.9)
analogComp library ver 1.2.4 Arduino IDE ver 1.8.9
I can't have the library work on a Pro Micro which is apparently identical to this one (except it is blue/green): https://www.sparkfun.com/products/12640
The pinout scheme is among the links in the Documents tab: https://cdn.sparkfun.com/datasheets/Dev/Arduino/Boards/ProMicro16MHzv1.pdf
I can trigger the interrupt through pin AIN0, D7, but I haven't managed to get any reaction from any other pin with any combination of 0 / 3.3 / 5 Volt.
I've been going through web pages like the following ones
- https://arduino.stackexchange.com/questions/17480/using-analog-comparator-on-atmega32u4
- https://www.electronicwings.com/avr-atmega/atmega1632-analog-comparator (code for Atmel Studio not the Arduino IDE, I get an error - copied in the sketch below - and admittedly I haven't searched about it)
- https://forum.arduino.cc/index.php?topic=217702.0
but I haven't been able to figure out a successful tweak yet.
Basically, I have been using the sketch coming with the lib except trying the setOn method on different pins and using pin 17 for the builtin LED.
#define __ENABLE_SERIAL__ANALOG_COMP__
#define __CHECK_COMPILE_TIME_FLAGS__
// #define __TRY_THE_ATMEL_STUDIO_EXAMPLE__
/*
This is a simple sketch to demonstrate the use of analogComp, a
library to manage the analog comparator included in a wide
variety of Atmel microcontrollers
This sketch enables an interrupt to be raised when on the analog input 0
(pin AIN0) there is a voltage greater than the voltage on the
analog input 1 (pin AIN1). To test the sketch, build the following
circuit:
- connect pin AIN1 to pin 3V3
- connect pin AIN0 to GND using a pull-down resistor (10Kohm or greater)
- connect pin AIN0 to pin 5V to activate the interrupt
More info on the analog comparator can be found reading the datasheet.
Please read the README file to know how to use this library.
Written by Leonardo Miliani <leonardo AT leonardomiliani DOT com>
This code and the analogComp library are free software; you can redistribute
and/or modify them under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 3.0 of the License,
or (at your option) any later version.
This work 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.
*/
// #ifndef ARDUINO_AVR_PROMICRO
//include the library
#include "analogComp.h"
// #endif
//global variables
#ifdef __ENABLE_SERIAL__ANALOG_COMP__
long count, columnsCount;
#endif
#ifdef ARDUINO_AVR_PROMICRO
#define BUILTIN_LED_PIN 17 //set the output LED
#else
#define BUILTIN_LED_PIN 13 //set the output LED
#endif
volatile boolean enableLed = false; //used to check if the interrupt has raised
//let's set up the hardware
void setup() {
pinMode(BUILTIN_LED_PIN, OUTPUT); //LED pin as output
#ifdef ARDUINO_AVR_PROMICRO
#ifdef __TRY_THE_ATMEL_STUDIO_EXAMPLE__
// https://www.electronicwings.com/avr-atmega/atmega1632-analog-comparator
// DDRC |= 0x80; /* Make pin 7 of PORTC as output */
ADCSRA &= (1<<ADEN); /* Disable ADC */
ADMUX = 0x00; /* Select ADC0 as a -ve pin of comparator */
SFIOR |= (1<<ACME); /* Enable analog comparator */
// ^ error 'SFIOR' was not declared in this scope. That example is for Atmel Studio.
#else
analogComparator.setOn(7, A10); //we instruct the lib to use voltages on the pins
#endif
#else
analogComparator.setOn(AIN0, AIN1); //we instruct the lib to use voltages on the pins
#endif
analogComparator.enableInterrupt(changeStatus, CHANGE); //we set the interrupt and when it has to be raised
count = 0;
columnsCount = 0;
}
//main loop
void loop() {
if (enableLed) { //let's check if the analog comparator has raised the interrupt
//yes, so we do a little blink of the LED
digitalWrite(BUILTIN_LED_PIN, HIGH);
#ifdef __ENABLE_SERIAL__ANALOG_COMP__
Serial.println("*** IRQ TRIGGERED ***");
#endif
delay(200);
digitalWrite(BUILTIN_LED_PIN, LOW);
enableLed = false;
}
#ifdef __ENABLE_SERIAL__ANALOG_COMP__
else {
if (++count == 10000) {
count = 0;
Serial.print("-");
if (++columnsCount == 80) {
columnsCount = 0;
Serial.println("");
#ifdef __CHECK_COMPILE_TIME_FLAGS__
#ifdef __AVR_ATmega32U4__
Serial.println("__AVR_ATmega32U4__ is defined");
#endif
#ifdef ATMEGAxU
Serial.println("ATMEGAxU is defined (the analogComp lib does it, if __AVR_ATmega32U4__ is defined");
Serial.println("Notice that this info could be printed out at compile time with compiler directives.");
Serial.println("");
Serial.print("AIN0 == "); // result 0
Serial.print(AIN0);
Serial.print(" - AIN1 == "); // result 255
Serial.println(AIN1);
Serial.println("");
#endif
#endif
}
}
}
#endif
}
//interrupt to be raised by the analog comparator
void changeStatus() {
enableLed = true; //let's inform the main loop that the condition has been reached by the analog comparator
}
I'd be happy to test any suggested changes to the library (possibly subordinated to #ifdef ARDUINO_AVR_PROMICRO ... #endif if not of general validity).
Marginally, I get this warning (IDE 1.8.9):
/home/lemon/MANINST/arduino-1.8.9/portable/sketchbook/libraries/analogComp/analogComp.cpp: In member function 'uint8_t analogComp::setOn(uint8_t, uint8_t)':
/home/lemon/MANINST/arduino-1.8.9/portable/sketchbook/libraries/analogComp/analogComp.cpp:100:19: warning: comparison is always true due to limited range of data type [-Wtype-limits]
if ((tempAIN1 >= 0) && (tempAIN1 < NUM_ANALOG_INPUTS)) { //set the AC Multiplexed Input using an analog input pin
^
I went through the Datasheet, this is apparently working fine (I do have a Leonardo but I tested this sketch on Pro Micro only, and admittedly not very extensively).
The next step would be to compare with what the lib does in analogComp.cpp, step by step, but for the moment I need to move on, I won't be using the ATmega32U4 built-in analog comparator anyway because apparently that implies that the ADC would not be available.
/*
2019-08-29 Nicola Bernardelli. Going through the ATmega32U4 Datasheet and applying the steps
to set up the analog comparator on a Pro Micro board.
While doing this, I understand that the Analog to Digital Converter must be switched off.
So, if you are needing to stick with ATmega32U4 but also need the ADC (as I do in my current project), you might have to add a
circuit with a comparator, e.g. LM393 or LM339, instead of using the built-in Analog Comparator.
Disabling this interrupt and reactivating the ADC has not been added to this sketch.
Also, a "real" handling of the interrupt-triggered event has not been added and the sketch leaves the possibility of a very fast
succession of interrupt requests. You might want to check the (currently only one) answer given here:
https://arduino.stackexchange.com/questions/49195/using-int2-3-on-arduino-micro-atmega32u4
[I wanted to ask/contribute here https://arduino.stackexchange.com/questions/17480/using-analog-comparator-on-atmega32u4
(I see that it is 3 years 9 months old but it's still "searchable" on the Internet, which is how I went there. I think that keeping the
information under that pertinent title is a better option than opening a new thread.)
So I created an account, but it turns out that I don't have enough "reputation" there to comment, so I wrote into the edit field
available to give an answer, and that did not work out either:
"Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed,
posting an answer now requires 10 reputation on this site (the association bonus does not count)."
So... pretty much chessmate. Well... their board, their rules.]
*/
#include "Arduino.h"
#ifndef ARDUINO_AVR_PROMICRO
#error This sketch is meant for the Arduino Pro Micro, it is based on the ATmega32U4 Datasheet and the Pro Micro pinout. \
You might decide to try it on a different ATmega32U4-based board if the pins choice is OK (please check/change the LED pin number).
#endif
#define THIS_BOARD_LED_BUILTIN 17
#define LED_ON_DURATION 200
volatile bool analogCompInterruptToggled;
unsigned long millisLastTrigger;
void setup() {
Serial.begin(9600);
analogCompInterruptToggled = false;
millisLastTrigger = 0;
pinMode(THIS_BOARD_LED_BUILTIN, OUTPUT);
digitalWrite(THIS_BOARD_LED_BUILTIN, HIGH);
/* As per Atmega32U4 Datasheet starting pag 293 (and linked pages). */
PRR0 &= ~bit(PRADC); // Disables power reduction for the ADC in order to use the ADC input MUX.
/*
ACME in ADCSRB: When this bit is written logic one and the ADC is switched off (ADEN in ADCSRA is zero),
the ADC multiplexer is connected to the negative input to the Analog Comparator. When this bit is written
logic zero, the Bandgap reference is connected to the negative input of the Analog Comparator
*/
ADCSRA &= ~bit(ADEN); /* Switches off the ADC so we can use the Muxer with the Analog Comparator instead of the ADC. */
ADCSRB |= bit(ACME); /* With the line above => the ADC multiplexer is connected to the negative input of the Analog Comparator. */
/* See table at page 295: ACME 0 or (ACME 1 and ADEN 1) => bandgap ref as the Analog Comparator Negative Input. */
/* ******** A0 NEGATIVE INPUT ********
Let's select pin ADC7 = A0 as the negative input to the Analog Comparator, as per pag 295 of the ATmega32U4 DataSheet:
ACME to 1 done above, ADEN to 0 done above, MUX2..0 to 111.
*/
ADMUX |= 0b00000111;
/* ******** D7 POSITIVE INPUT ********
When this bit is set, a fixed bandgap reference voltage replaces the positive input to the Analog Comparator.
When this bit is cleared, AIN0 is applied to the positive input of the Analog Comparator.
*/
ACSR &= ~bit(ACBG); // AIN0 = D7 => positive input of the Analog Comparator
/* Pages 294-295 of the ATmega32U4 Datasheet. */
ACSR &= ~bit(ACIC); /* Analog Comparator Input Capture disabled. */
/* Comparator Interrupt trigger mode. 0-0 => TOGGLE, meaning any change; 1-0 => FALLING; 1-1 => RISING). */
// ACSR &= ~bit(ACIS1); ACSR &= ~bit(ACIS0); // TOGGLE
// ACSR |= bit(ACIS1); ACSR &= ~bit(ACIS0); // FALLING
ACSR |= bit(ACIS1); ACSR |= bit(ACIS0); // RISING
DIDR1 &= ~bit(AIN0D); /* It's actually the rightmost bit, we could write DIDR1 &= ~1 */
/*
When this bit is written logic one, the digital input buffer on the AIN0 pin is disabled. [...]
When an analog signal is applied to the AIN0 pin and the digital input from this pin is not needed,
this bit should be written logic one to reduce power consumption in the digital input buffer.
*/
ACSR |= bit(ACIE);
SREG |= bit(SREG_I);
/* When the ACIE bit is written logic one and the I-bit in the Status Register is set,
the Analog Comparator interrupt is activated. When written logic zero, the interrupt is disabled.
*/
}
ISR(ANALOG_COMP_vect) {
analogCompInterruptToggled = true;
}
void loop() {
// put your main code here, to run repeatedly:
if (analogCompInterruptToggled) {
analogCompInterruptToggled = false;
digitalWrite(THIS_BOARD_LED_BUILTIN, LOW);
millisLastTrigger = millis();
Serial.print("toggled - millis() == ");
Serial.println(millisLastTrigger);
}
else if (millis() > millisLastTrigger + LED_ON_DURATION) {
digitalWrite(THIS_BOARD_LED_BUILTIN, HIGH);
}
}
apparently that implies that the ADC would not be available.
@JazzTp , I managed to get comparator working on AIN0 and INTERNAL_REFERENCE together with ADC, by enabling ADC after Comparator setup, i.e. writing 1 to the ADEN bit of ADCSRA register: ADCSRA |= 1 << 7;
My test code looks like:
/*
This is a simple sketch to demonstrate the use of analogComp, a
library to manage the analog comparator included in a wide
variety of Atmel microcontrollers
This sketch enables an interrupt to be raised when on the analog input 0
(pin AIN0) there is a voltage greater than the voltage on the
analog input 1 (pin AIN1). To test the sketch, build the following
circuit:
- connect pin AIN1 to pin 3V3
- connect pin AIN0 to GND using a pull-down resistor (10Kohm or greater)
- connect pin AIN0 to pin 5V to activate the interrupt
More info on the analog comparator can be found reading the datasheet.
Please read the README file to know how to use this library.
Written by Leonardo Miliani <leonardo AT leonardomiliani DOT com>
This code and the analogComp library are free software; you can redistribute
and/or modify them under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 3.0 of the License,
or (at your option) any later version.
This work 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.
*/
//include the library
#include "analogComp.h"
//global variables
const byte LED13 = 13; //set the output LED
volatile boolean enableLed = false; //used to check if the interrupt has raised
//let's set up the hardware
void setup() {
Serial.begin( 19200 );
pinMode(LED13, OUTPUT); //LED pin as output
analogReference(INTERNAL);
//Turn on adc (needed to init internal analogReference)
analogRead(A0);
analogComparator.setOn(AIN0, INTERNAL_REFERENCE); //we instruct the lib to use voltages on the pins
analogComparator.enableInterrupt(changeStatus, CHANGE); //we set the interrupt and when it has to be raised
// Turn on ADC again after comparator setup
ADCSRA |= 1 << 7;
}
//main loop
void loop() {
Serial.print("ADMUX register:");
Serial.println(ADMUX, BIN);
Serial.print("ADCSRA register:");
Serial.println(ADCSRA, BIN);
Serial.print("ADCSRB register:");
Serial.println(ADCSRB, BIN);
if (enableLed) { //let's check if the analog comparator has raised the interrupt
//yes, so we do a little blink of the LED
digitalWrite(LED13, HIGH);
delay(200);
digitalWrite(LED13, LOW);
enableLed = false;
}
delay(1000);
Serial.println(analogRead(A1));
}
//interrupt to be raised by the analog comparator
void changeStatus() {
enableLed = true; //let's inform the main loop that the condition has been reached by the analog comparator
}
Seems like comparator setup turn off ADC somewhere...
Very interesting, thank you. Are you testing on Pro Micro, or Leonardo, or ...?
I'm testing on Micro from DeekRobot. Got it from aliexpress
Seems compliant with https://www.arduino.cc/en/uploads/Main/arduino-micro-schematic.pdf
@dsankouski
Seems like comparator setup turn off ADC somewhere...
The library might be going through the same steps I extrapolated from the datasheet (NOTICE: I didn't find in the datasheet a pre-made example, which is bad of a datasheet IMHO, a single piece of commented working code is the clear example that one would always want to find there... which doesn't exclude the possibility of also adding further information on what each step does).
Quoting from my post:
...
PRR0 &= ~bit(PRADC); // Disables power reduction for the ADC in order to use the ADC input MUX.
...
ADCSRA &= (1<<ADEN); /* Disable ADC */
...
What you found out suggests that disabling the ADC is not necessary, provided that you need to sample one of the two inputs which are being fed to the analog comparator itself, and not input from another pin, or other pins.
Am I getting it right?
That was actually my need at the beginning, so thank you again.
As I had to prepare a PCB anyway for other parts of that project, I was already deciding to switch to additional hardware and not use the MCU internal analog comparator, to avoid portability issues and to have responses to critical events redundantly handled both by the MCU and the additional hardware. It seemed to have become a must after I decided to monitor more values.
(((
Finally, I added window comparators, each one made of two comparators, each going to a flip-flop + logic gate + transistor. This is still rather simple and cheap and gives me the reactions I wanted, with a bit of noise reduction not requiring computation cycles, without resorting to additional IRQs and without portability issues, and passes the info to the MCU (which is also sampling a few values, in order to show them on the display and to react to another class of events). The software can later possibly reset the flip-flops.
But with simpler requirements, what you found out would probably do the job with the MCU alone.
)))
I guess you are submitting the thing to an extensive "torture" session to check for reliability and stability.
I'm testing on Micro from DeekRobot. Got it from aliexpress
Seems compliant with https://www.arduino.cc/en/uploads/Main/arduino-micro-schematic.pdf
It's not identical to the Pro Micro I have here, this board has the same size of a Pro Mini, it doesn't have a reset button, the pins distribution on the perimeter is also a bit different, but I guess the pinout from the ATmega32U4 is compatible and what we are dealing with here is internal stuff of the ATmega32U4 itself.
What I have here - bought from a local seller - seems to be a (blue) clone of this one:
https://www.sparkfun.com/products/12640
I was also having trouble with the 32U4.
Per the datasheet, ACME: Analog Comparator Multiplexer Enable should be set in ADC Control and Status Register B – ADCSRB, NOT ADCSRA.
This seemed to work...
#elif defined (__AVR_ATmega32U4__)
#define ATMEGAxU
#define AC_REGISTER ADCSRB
#define NUM_ANALOG_INPUTS 14