I am trying to use the ALRT pin to trigger an interrupt, so that I don't have to poll the value in my main loop. However, the interrupt only occurs when I poll the value. Am I doing something wrong?
_status will not increment unless I uncomment the second line of the main loop to read the value of ADC pin 0. When it is uncommented, status only increments once every 2 seconds when the value is read.
Is this how it is supposed to work? I could setup a second thread to poll the value, but at that point, I don't feel like I would need the interrupt. Am I missing something?
Oh, I should probably mention I am using an ESP32-WROOM (the 38 pin version).
Do you have an external pull-up resistor on your interrupt pin? You will need one. The ALRT/RDY pin pulls LOW to assert. You can also make the pin INPUT_PULLUP to skip the external resistor.
That's interesting, I am glad you said something. So, yes I did have a pull-DOWN resistor, because the readme for the library says the signal goes high when triggered. I didn't fully appreciate the section of the readme that discusses the configuration options for it. There is a config register on the ADC with a "COMP_POL" option to set whether or not it goes high or goes low when triggered.
So, I hooked the ALRT pin directly to my scope and I can confirm that the default (for this library) has it configured so the alert pin goes high when triggered.
I also reconfigured it to work with a pull-up instead, just in case, but the results are the same.
Since I have it hooked to the scope, I can eliminate the ESP interrupt as a potential failure. The ADC simply does not change state unless I explicitly request a value using "ADS.readADC()" or "ADS.getValue()".
That is how it behaves, and digging through the code in the library, I don't believe the continuous register bit is being set correctly. It looks to me like that bit is 1 by default, but the library is trying to clear it using a binary or with a value of 0, which won't work.
FWIW - When I've used the ADS115, I found it convenient to poeriodically kick off a conversion, and on a subsequent pass of loop(), read the result, based on a millis() timer. No interrupt needed, and very low overhead.
Yeah, so I was wrong. I'm going to chalk it up to it being late (early? 2am). The binary "or" ("|") works fine because all of the settings are being "ored" together and then the entire registry is written to at once. So, the bit never actually needs cleared, it is simply either set or not set.
This is not quite right either. There was indeed a bug in the library that was inverting the polarity (this should be fixed in v0.5.0). So, when I was setting the polarity to 1, it would actually be set to 0 and vice versa.
However, after further testing, regardless of the value for the polarity bit ("COMP_POL") you absolutely want to use a pull-up resistor on the ALRT pin. If you leave it floating, you'll get ghosts, and if you pull it down, you will cut your peak-to-peak voltage in half and cause signal drifting. I only tested this with a 10k resistor, different values might have a more profound effect.
With the library fixed and the polarity bit correctly set to 1, the pulses will go high. With the polarity bit set to 0, the pulses will go low. According to Figure 29 of the data sheet (https://www.ti.com/lit/ds/symlink/ads1115.pdf), the conversion is only ready at the trailing edge of the pulse. Which means in order to guarantee the conversion is ready, you need to adjust which edge your interrupt is looking for to match your polarity. With the polarity bit set to 1, you'll want to watch for the falling edge, but with the polarity bit set to 0, you will want to watch for the rising edge.
Also, if that wasn't confusing enough, the polarity in continuous mode vs single mode are opposites. With the polarity bit set set to 1, the pulses go low in single mode, but go high in continuous mode. Likewise, with the polarity bit set to 0, the pulses go high in single mode, but go low in continuous mode.
Which is a great way to do it, however, I'm using this to trigger an event as soon as the single dips below or above a certain threshold. The ADS115 is capable of doing a conversion once every ~1.2ms. Simply reading the value once every loop in single mode limits me to ~2.7ms. But that was tested with a near empty loop with no delay, which means my reaction time, in the best case scenario is about double (not accounting for the time it take the interrupt to be triggered).
Even without an interrupt though, continuous mode should still be faster because when you call read in single mode, you have to wait for the ADC to take a sample and do the conversion. In continuous mode, you can simply grab the last value directly from the register without waiting. I don't know if there are interlocks on the chip that would prevent you from reading a partially written to register though...
The rate of continuous conversion is equal to the programmed data rate. Data can be read at any time and always reflect the most recent completed conversion.