Skip to content

Add wait for conversion #12

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jul 10, 2018
Merged
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 32 additions & 25 deletions adafruit_ads1x15/adafruit_ads1x15.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
__version__ = "0.0.0-auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_ADS1x15.git"

import time
from micropython import const
from adafruit_bus_device.i2c_device import I2CDevice

Expand Down Expand Up @@ -131,6 +130,23 @@ def __init__(self, i2c, address=ADS1X15_DEFAULT_ADDRESS):
ADC_Channel(self, 2),
ADC_Channel(self, 3)]

def _write_register(self, reg, value):
"""Write 16 bit value to register."""
self.buf[0] = reg
self.buf[1] = (value >> 8) & 0xFF
self.buf[2] = value & 0xFF
with self.i2c_device as i2c:
i2c.write(self.buf)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason for not using Adafruit_CircuitPython_Register?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just haven't used it yet. I'll take a look.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deferring this to a future PR.


def _read_register(self, reg):
"""Return 16 bit register value as tuple of (LSB, MSB)."""
self.buf[0] = reg
with self.i2c_device as i2c:
i2c.write(self.buf, end=1, stop=False)
i2c.readinto(self.buf, start=1)
# LSB MSB
return self.buf[2], self.buf[1]
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function is only used in one place, does it really make sense to have it?
Also, where it is used, we don't use the first byte of the result, does it really make sense to create a new tuple every time, especially since we do it in a tight loop?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yah, I was wondering about the tuple also. Basically it's just left over from first version of code. I was thinking of changing to just passing back an int. I'll take a look, I'm not sure why I can't just go ahead and do that.

I think having the function makes sense for any future expansion of functionality - it'll be the generic register read for whatever.


def _data_rate_default(self):
"""Retrieve the default data rate for this ADC (in samples per second).
Should be implemented by subclasses.
Expand Down Expand Up @@ -164,6 +180,13 @@ def _read_channel_volts(self, channel):
"""
raise NotImplementedError('Subclass must implement _read_channel_volts function!')

def _conversion_complete(self):
"""Return status of ADC conversion."""
# OS is bit 15
# OS = 0: Device is currently performing a conversion
# OS = 1: Device is not currently performing a conversion
return self._read_register(ADS1X15_POINTER_CONFIG)[1] & 0x80

def _read(self, mux, gain, data_rate, mode):
"""Perform an ADC read with the provided mux, gain, data_rate, and mode
values. Returns the signed integer result of the read.
Expand All @@ -186,40 +209,24 @@ def _read(self, mux, gain, data_rate, mode):
config |= self._data_rate_config(data_rate)
config |= ADS1X15_CONFIG_COMP_QUE_DISABLE # Disble comparator mode.
# Send the config value to start the ADC conversion.
# Explicitly break the 16-bit value down to a big endian pair of bytes.
self.buf[0] = ADS1X15_POINTER_CONFIG
self.buf[1] = (config >> 8) & 0xFF
self.buf[2] = config & 0xFF
with self.i2c_device as i2c:
i2c.write(self.buf)
# Wait for the ADC sample to finish based on the sample rate plus a
# small offset to be sure (0.1 millisecond).
time.sleep(1.0/data_rate+0.0001)
# Retrieve the result.
self.buf[0] = ADS1X15_POINTER_CONVERSION
i2c.write(self.buf, end=1, stop=False)
i2c.readinto(self.buf, start=1)
return self._conversion_value(self.buf[2], self.buf[1])
self._write_register(ADS1X15_POINTER_CONFIG, config)
# Wait for conversion to complete
while not self._conversion_complete():
pass
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wouldn't be better to have time.sleep() instead of pass?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the reason? Easy enough to do, just curious what the trade off is.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose it's a good practice from regular Python, where you want to give the control back to the operating system and other applications, instead of running it at 100%.
Perhaps it will also make a difference for SAMD at some point, when we get to the power management options.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gotcha. I figured pass took care of that. So is just a zero sleep good enough?

time.sleep(0)

# Return the result
return self.get_last_result()

def stop_adc(self):
"""Stop all continuous ADC conversions (either normal or difference mode).
"""
# Set the config register to its default value of 0x8583 to stop
# continuous conversions.
self.buf[0] = ADS1X15_POINTER_CONFIG
self.buf[1] = 0x85
self.buf[2] = 0x83
with self.i2c_device as i2c:
i2c.write(self.buf)
self._write_register(ADS1X15_POINTER_CONFIG, 0x8583)

def get_last_result(self):
"""Read the last conversion result when in continuous conversion mode.
Will return a signed integer value.
"""
# Retrieve the conversion register value, convert to a signed int, and
# return it.
self.buf[0] = ADS1X15_POINTER_CONVERSION
with self.i2c_device as i2c:
i2c.write(self.buf, end=1, stop=False)
i2c.readinto(self.buf, start=1)
return self._conversion_value(self.buf[2], self.buf[1])
return self._conversion_value(*self._read_register(ADS1X15_POINTER_CONVERSION))