Custom front end configuration
What this example shows
The module's electrochemical-customConfig.py example builds its own SensorConfig instead of using a preset, and sends those settings to the LMP91000 analog front end and the ADC. Use it when you want to tune the gain, the internal zero or the zero offset yourself.
The example creates the sensor with its own SENSOR_CUSTOM and no adc_addr, so the module's default address is used. The example's values are the ozone cell's. For this board's cell, the SENSOR_NH3 preset's values below are a starting point. Three of them (ADS_GAIN_4_096V, INTERNAL_ZERO_20_PERCENT and BIAS_SIGN_POSITIVE) are not in the example's imports, so add them: ADS_GAIN_4_096V comes from ads1115, the other two from ElectrochemicalGasSensor.
The module talks to the board's ATtiny404 bridge only when adc_addr is from 0x30 to 0x37. Any other value, such as the default 0x49 this example uses, is taken as the I2C address of an ADS1115 that the module talks to directly. On this board the ADS1115 sits on the header's SDA2/SCL2 pins, which the Qwiic connectors do not reach, so this example does not run over the Qwiic cable. Wire the controller to the header instead: 3.3 V to 3V3, GND to GND, the example's SDA pin (21) to SDA2 and its SCL pin (22) to SCL2. The example then runs as written, with no change to the address.
The connecting diagram in the example's comments wires LMPEN to a GPIO pin. On this board, leave LMPEN unconnected: a 10 kΩ resistor already pulls it to GND, and the ATtiny404 is connected to it too.
| Argument | SENSOR_NH3 value |
|---|---|
nano_amperes_per_ppm | 40.0 |
internal_zero_calibration | 0 |
ads_gain | ADS_GAIN_4_096V |
tia_gain | TIA_GAIN_35_KOHM |
rload | RLOAD_10_OHM |
ref_source | REF_EXTERNAL |
internal_zero | INTERNAL_ZERO_20_PERCENT |
bias_sign | BIAS_SIGN_POSITIVE |
bias | BIAS_0_PERCENT |
fet_short | FET_SHORT_DISABLED |
op_mode | OP_MODE_3LEAD_AMP_CELL |
The example code
# FILE: electrochemical-customConfig.py
# AUTHOR: Fran Fodor @ Soldered
# BRIEF: Custom LMP91000 configuration example for any electrochemical sensor.
# LAST UPDATED: 2026-05-21
# Connecting diagram:
#
# Qwiic------------------------>Qwiic
# LMPEN------------------------>GPIO pin (see config_pin parameter below)
from machine import I2C, Pin
import time
from ElectrochemicalGasSensor import (
ElectrochemicalGasSensor, SensorConfig,
TIA_GAIN_35_KOHM, RLOAD_10_OHM, REF_EXTERNAL,
INTERNAL_ZERO_67_PERCENT, BIAS_SIGN_NEGATIVE, BIAS_0_PERCENT,
FET_SHORT_DISABLED, OP_MODE_3LEAD_AMP_CELL,
)
from ads1115 import ADS_GAIN_2_048V
# Custom sensor configuration — edit these values to match your sensor's datasheet.
#
# nanoAmperesPerPPM: Sensitivity from the sensor datasheet (nA/PPM)
# internalZeroCalibration: Voltage offset added to zero the reading in clean air
# adsGain: ADS1115 full-scale range (ADS_GAIN_6_144V .. ADS_GAIN_0_256V)
# tia_gain: TIA feedback resistor (TIA_GAIN_2_75_KOHM .. TIA_GAIN_350_KOHM)
# rload: Load resistor (RLOAD_10_OHM .. RLOAD_100_OHM)
# ref_source: Reference voltage source (REF_INTERNAL / REF_EXTERNAL)
# internal_zero: Internal zero percentage (INTERNAL_ZERO_20/50/67_PERCENT or _BYPASSED)
# bias_sign: Bias polarity (BIAS_SIGN_NEGATIVE / BIAS_SIGN_POSITIVE)
# bias: Bias percentage of Vref (BIAS_0_PERCENT .. BIAS_24_PERCENT)
# fet_short: FET short (FET_SHORT_DISABLED / FET_SHORT_ENABLED)
# op_mode: Operating mode (OP_MODE_3LEAD_AMP_CELL for normal operation)
SENSOR_CUSTOM = SensorConfig(
nano_amperes_per_ppm=-1000.0,
internal_zero_calibration=-0.0012,
ads_gain=ADS_GAIN_2_048V,
tia_gain=TIA_GAIN_35_KOHM,
rload=RLOAD_10_OHM,
ref_source=REF_EXTERNAL,
internal_zero=INTERNAL_ZERO_67_PERCENT,
bias_sign=BIAS_SIGN_NEGATIVE,
bias=BIAS_0_PERCENT,
fet_short=FET_SHORT_DISABLED,
op_mode=OP_MODE_3LEAD_AMP_CELL,
)
# Initialize I2C
i2c = I2C(0, scl=Pin(22), sda=Pin(21))
sensor = ElectrochemicalGasSensor(SENSOR_CUSTOM, i2c)
# -------------------------------------------------------------------------
# Setup
# -------------------------------------------------------------------------
print("Electrochemical Gas Sensor - Custom Config Example")
if not sensor.begin():
print("ERROR: Can't init the sensor! Check connections!")
while True:
time.sleep_ms(100)
print("Sensor initialized successfully!")
# -------------------------------------------------------------------------
# Main loop
# -------------------------------------------------------------------------
while True:
reading = sensor.getPPB()
print("Sensor reading: {:.5f} PPB".format(reading))
time.sleep_ms(2500)
🔗Open the complete example
electrochemical-customConfig.py at commit 623e1e6
The Thonny shell shows:
Electrochemical Gas Sensor - Custom Config Example
Sensor initialized successfully!
Then a line starting with Sensor reading: follows every 2.5 seconds, in ppb to five decimals.
If begin() returns False, the example prints ERROR: Can't init the sensor! Check connections! instead and stops.
Functions used
SensorConfig(nano_amperes_per_ppm, internal_zero_calibration, ads_gain, tia_gain, rload, ref_source, internal_zero, bias_sign, bias, fet_short, op_mode)returns SensorConfigHolds one cell's settings: its sensitivity and zero offset for the ppm conversion, the ADC range, and the LMP91000 gain, load, reference, internal zero, bias, FET short and operating mode.
ReturnsThe configuration object to pass to ElectrochemicalGasSensor.
Parameters
| Parameter | Description |
|---|---|
nano_amperes_per_ppm | Cell sensitivity in nA per ppm, from the cell's datasheet. |
internal_zero_calibration | Voltage offset added to zero the reading in clean air. |
ads_gain | ADC full-scale range, ADS_GAIN_6_144V to ADS_GAIN_0_256V. |
tia_gain | Amplifier feedback resistor, TIA_GAIN_2_75_KOHM to TIA_GAIN_350_KOHM, or TIA_GAIN_EXTERNAL. |
rload | Load resistor, RLOAD_10_OHM to RLOAD_100_OHM. |
ref_source | REF_INTERNAL or REF_EXTERNAL. The ppm conversion assumes the board's 2.5 V reference. |
internal_zero | INTERNAL_ZERO_20_PERCENT, _50_PERCENT, _67_PERCENT or INTERNAL_ZERO_BYPASSED. |
bias_sign | BIAS_SIGN_NEGATIVE or BIAS_SIGN_POSITIVE. |
bias | Bias as a percentage of the reference, BIAS_0_PERCENT to BIAS_24_PERCENT. |
fet_short | FET_SHORT_DISABLED for normal operation, or FET_SHORT_ENABLED. |
op_mode | OP_MODE_3LEAD_AMP_CELL for normal operation; deep sleep, standby, 2-lead and temperature modes also exist. |
ElectrochemicalGasSensor(sensor_type, i2c=None, adc_addr=0x49, config_pin=None)returns ElectrochemicalGasSensorCreates the sensor object with any SensorConfig, a preset or your own. adc_addr decides how begin() talks to the board: from 0x30 to 0x37 it uses the ATtiny bridge protocol; any other value is used as the ADC's own I2C address.
ReturnsThe sensor object.
Parameters
| Parameter | Type | Description |
|---|---|---|
sensor_type | SensorConfig | Your configuration, here SENSOR_CUSTOM. |
i2c | I2C | Your I2C object. |
adc_addr | int | The address the module talks to. Default 0x49, which this example uses. On this board the ADDRESS switch sets the bridge's address from 0x30 to 0x37. |
config_pin | int or None | A GPIO pin number the module sets low while it configures the LMP91000 and high afterwards, when adc_addr is outside 0x30 to 0x37. Default None. Not used from 0x30 to 0x37. |
begin()returns boolConfigures the ADC gain and writes the three LMP91000 register values built from your SensorConfig: through the board's bridge when the address is 0x30 to 0x37, or to the ADS1115 and the LMP91000 directly for any other address.
ReturnsTrue when every step succeeded. False when the bridge did not answer OK within 500 ms or reported an error, when starting the ADS1115 failed, or when configuring the analog front end failed.
getPPB()returns floatTakes one reading and converts it with your configuration's gain, internal zero, offset and sensitivity. A result below zero is returned as 0.
ReturnsThe concentration in ppb.
Putting it together
begin() packs your SensorConfig into the LMP91000's three settings registers and writes them, and every reading uses the same fields for the conversion. Change one argument at a time and compare with the SENSOR_NH3 values above.