Having Issues with ADS1115 and Timer

RP2040 based microcontroller boards running MicroPython.
Target audience: MicroPython users with an RP2040 boards.
This does not include conventional Linux-based Raspberry Pi boards.
Post Reply
Andromeda247
Posts: 2
Joined: Wed Mar 16, 2022 7:46 am

Having Issues with ADS1115 and Timer

Post by Andromeda247 » Wed Mar 16, 2022 7:52 am

Hello everyone I have been working on this library I found over github to use an ADS1115 at 860s/s to sample a 140Hz data.

ADS1115 Library: https://github.com/robert-hh/ads1x15

In the timmer part I need to use a timer with the period of 0.01ms to get an accurate sample. With 1ms timer I am only able to sample a 50Hz signal at 860s/s. Here is the part for the timer:

ads.set_conv(7,0)
ads.read_rev()
sleep_ms(5)
tim = Timer(-1)
tim.init(period=1, mode=Timer.PERIODIC, callback=sample) ------> 1 corresponds to 1ms the lowest this function can take!

User avatar
Roberthh
Posts: 3667
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: Having Issues with ADS1115 and Timer

Post by Roberthh » Wed Mar 16, 2022 8:12 am

The time for two way communication has to be added to the total cycle time. You can save some time by using the adc.set_conv() and adc.read_rev() methods, which starts a new cycle when reading the actual value. Or you use continuous reading with a trigger on the alert/Rdy pin to a Pin IRQ. Examples are provided in the readme.md of the ADS1115 repo. The RPI should be fast enough to cope with the data rate.

Andromeda247
Posts: 2
Joined: Wed Mar 16, 2022 7:46 am

Re: Having Issues with ADS1115 and Timer

Post by Andromeda247 » Thu Mar 17, 2022 5:17 am

Thank you so much for your fast reply!

Here is my adjusted code:

def sample(adc = ads.read_rev, data=data, timestamp = timestamp, voltage=ads.raw_to_v):
global index_put, irq_busy
for i in range(860):
if irq_busy:
return
irq_busy = True
ads.set_conv(7, 0)
if index_put < _BUFFERSIZE:
data[index_put] = ads.read_rev()
index_put += 1
i +=1
irq_busy = False

irq_busy = False
index_put = 0

I am using a 40Hz Sine with the amplitude of 2V and here is what I get:
Image
2015 cla 250 0 60

It is surprising since I have the sampling rate set to 860s/s.

Any idea?

Thanks again,
Andromeda

User avatar
Roberthh
Posts: 3667
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: Having Issues with ADS1115 and Timer

Post by Roberthh » Thu Mar 17, 2022 8:32 am

What is surprising? I did a similar set-up. Results below. The actual sampling rate is 835 sample/sec. The sampling rates you get are not precise, since they are define by the internal oscillator of the ADS1115, which is about 1 MHz, but varies with temperature and device.
sine.jpg
sine.jpg (42.48 KiB) Viewed 1893 times
timing.jpg
timing.jpg (103.33 KiB) Viewed 1893 times

User avatar
Roberthh
Posts: 3667
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: Having Issues with ADS1115 and Timer

Post by Roberthh » Thu Mar 17, 2022 12:07 pm

Another snapshot, using the timer variant of the sampling, at 500samples/sec. Code and 40Hz sample below. To get a faster sampling, like 750 samples/sec. You would have to use PWM to create a 750 Hz pulse and a IRQ interrupt to do the sampling. With Timer/PWM controlled sampling, the rate is pretty precise.

Code: Select all

from machine import I2C, Pin, Timer
import ads1x15
from time import sleep_ms, ticks_ms, ticks_us
from array import array

addr = 72
gain = 1

_BUFFERSIZE = const(512)
#
# Interrupt service routine zum messen
# diese wird vom Timer-interrupt aktiviert
#


def sample(x):
    global index_put, ads, irq_busy, data, timestamp
    if irq_busy:
        return
    irq_busy = True
    if index_put < _BUFFERSIZE:
        timestamp[index_put] = ticks_us()
        data[index_put] = ads.read_rev()
        index_put += 1
    irq_busy = False

data = array("h", [0] * _BUFFERSIZE)
timestamp = array("L", [0] * _BUFFERSIZE)
irq_busy = False

index_put = 0
ADC_RATE = 2

i2c = I2C(0, freq=400000)
ads = ads1x15.ADS1115(i2c, addr, gain)
# set the conversion rate tp 860 SPS = 1.16 ms; that leaves about
# 800µs time for processing the data with a 2 ms timer
ads.set_conv(7, 0)  # start the first conversion
ads.read_rev()
sleep_ms(ADC_RATE)
tim = Timer(-1)
tim.init(period=ADC_RATE, mode=Timer.PERIODIC, callback=sample)

while index_put < _BUFFERSIZE:
    pass

tim.deinit()

for _ in range(1, _BUFFERSIZE):
    print(timestamp[_], timestamp[_] - timestamp[_-1],
          data[_], data[_] - data[_ - 1])

# at that point data contains the sampled values, and
# timestamp the timer ticks which correlate to the conversion time
#

sine.jpg
sine.jpg (66.24 KiB) Viewed 1876 times

User avatar
Roberthh
Posts: 3667
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: Having Issues with ADS1115 and Timer

Post by Roberthh » Thu Mar 17, 2022 12:24 pm

Another picture, this time of a 140 Hz signal, sampled at 500Hz, interpolation with cubic spline. The dots show the actually sampled values. The fastest conversion time of the ADC is about 1/860 second. That's the limit. The other limit would be the communication time ar read_rev(), which is about 400 µs. The latter could be shortened by setting the CPU freq to 250Mhz and the I2C freq to 2 Mhz to about 130 µs. But the conversion time of the ADC stays. If that is too slow, you have to use a differerent ADC.
sine.jpg
sine.jpg (49.42 KiB) Viewed 1872 times

Post Reply