diff --git a/micropython/drivers/sensor/pasco2/manifest.py b/micropython/drivers/sensor/pasco2/manifest.py new file mode 100644 index 00000000..8afa9bc3 --- /dev/null +++ b/micropython/drivers/sensor/pasco2/manifest.py @@ -0,0 +1,3 @@ +metadata(description="Driver for XENSIV PAS CO2 sensor.", version="0.1.0") + +module("pasco2.py", opt=3) diff --git a/micropython/drivers/sensor/pasco2/pasco2.py b/micropython/drivers/sensor/pasco2/pasco2.py new file mode 100644 index 00000000..4c80532d --- /dev/null +++ b/micropython/drivers/sensor/pasco2/pasco2.py @@ -0,0 +1,140 @@ +# Infineon XENSIV PAS CO2 sensor driver for MicroPython + +from machine import I2C +from utime import sleep, sleep_ms + +# Sensor Register Address Stack +_PASCO2_REG_SENS_STS = const(0x01) # Sensor status register address +_PASCO2_REG_MEAS_RATE_H = const(0x02) # Measurement period MSB configuration register address +_PASCO2_REG_MEAS_CFG = const(0x04) # Measurement mode configuration register address +_PASCO2_REG_CO2PPM_H = const(0x05) # CO2 concentration result MSB register address +_PASCO2_REG_MEAS_STS = const(0x07) # Measurement status register address +_PASCO2_REG_SENS_RST = const(0x10) # Soft reset register address +_PASCO2_REG_PROD_ID = const(0x00) # Product and revision ID register address + +# Error codes +_PASCO2_SUCCESS = 0 +_PASCO2_ERROR = -1 + +addr = 0 +mask = 1 + + +class PASCO2: + """IFX - XENSIV PAS CO2 sensor driver""" + + # RegAddr, Mask, + regMap = { + "REG_SENS_STS_BITF_SENS_RDY": [_PASCO2_REG_SENS_STS, 0x80], # Sensor status bit + "REG_MEAS_CFG_BITF_OP_MODE": [_PASCO2_REG_MEAS_CFG, 0x03], # Operation Mode type bit + "REG_MEAS_STS_BITF_DATA_RDY": [_PASCO2_REG_MEAS_STS, 0x10], # Data ready status bit + "REG_CO2PPM_H_BITF_CO2_PPM_H": [_PASCO2_REG_CO2PPM_H, 0xFF], # Stored CO2 value bit + "REG_PROD_ID_BITF_PROD": [_PASCO2_REG_PROD_ID, 0xE0], # Product id bit + "REG_PROD_ID_BITF_REV": [_PASCO2_REG_PROD_ID, 0x1F], # Revision id bit + } + + def __init__(self, bus, measInterval=10, sensorAddr=0x28): + """ " Intialize the sensor and required dependencies""" + self.bus = bus + self.sensorAddr = sensorAddr + self.measInterval = measInterval + self.softResetCode = b"\xa3" + + def _read_reg(self, regAddr, bytesToRead=1): + """Internal function to read data from the sensor register and returns it raw""" + readVal = self.bus.readfrom_mem(self.sensorAddr, regAddr, bytesToRead) + return readVal + + def _write_reg(self, regAddr, writeData): + """Internal function to write data to sensor register""" + self.bus.writeto_mem(self.sensorAddr, regAddr, writeData) + + def _is_sensor_ready(self): + """Helper function to check the sensor status""" + reg = self.regMap["REG_SENS_STS_BITF_SENS_RDY"] + return self._read_reg(reg[addr])[0] & reg[mask] + + def _soft_reset(self): + """Helper function to perform soft reset of the sensor""" + self._write_reg(_PASCO2_REG_SENS_RST, self.softResetCode) + + def _set_mode(self, mode): + """Helper function to set the mode of sensor. Currently supported modes: + 1. Idle + 2. Continuous + """ + if mode == "idle": + modeVal = 0x00 + if mode == "continuous": + modeVal = 0x02 + + reg = self.regMap["REG_MEAS_CFG_BITF_OP_MODE"] + readData = self._read_reg(reg[addr])[0] + writeData = bytes([(readData & ~(reg[mask])) | modeVal]) + self._write_reg(_PASCO2_REG_MEAS_CFG, writeData) + + def initialize(self): + """Public function to initialize the sensor""" + try: + # wait for sensor to be ready + sensor_ready = self._is_sensor_ready() + while not sensor_ready: + sleep(1) + sensor_ready = self._is_sensor_ready() + + # soft reset sensor register + self._soft_reset() + sleep_ms(800) + + # set measure rate + buf = bytes([(self.measInterval >> 8) & 0xFF, self.measInterval & 0xFF]) + self._write_reg(_PASCO2_REG_MEAS_RATE_H, buf) + + # reset operation mode to idle mode + self._set_mode("idle") + + # start continuous mode + self._set_mode("continuous") + + return _PASCO2_SUCCESS + + except: + return _PASCO2_ERROR + + def get_co2_value(self): + """Public function to get the CO2 value""" + while True: + try: + # get meas status + reg = self.regMap["REG_MEAS_STS_BITF_DATA_RDY"] + readStatus = self._read_reg(reg[addr]) + data_ready = readStatus[0] & reg[mask] + + if data_ready: + # get CO2 value + reg = self.regMap["REG_CO2PPM_H_BITF_CO2_PPM_H"] + readVal = self._read_reg(reg[addr], 2) + co2_value = (readVal[0] << 8) | readVal[1] + return co2_value + except: + return _PASCO2_ERROR + + def get_prod_id(self): + """Public function to get the sensor product id""" + try: + reg = self.regMap["REG_PROD_ID_BITF_PROD"] + readID = (self._read_reg(reg[addr])[0] & 0xE0) >> 5 + return readID + + except: + return _PASCO2_ERROR + + def get_rev_id(self): + """Public function to get the sensor revision id""" + try: + reg = self.regMap["REG_PROD_ID_BITF_REV"] + readID = (self._read_reg(reg[addr])[0] & 0x1F) >> 0 + return readID + + except: + return _PASCO2_ERROR diff --git a/micropython/drivers/sensor/pasco2/pasco2Test.py b/micropython/drivers/sensor/pasco2/pasco2Test.py new file mode 100644 index 00000000..e2016e4b --- /dev/null +++ b/micropython/drivers/sensor/pasco2/pasco2Test.py @@ -0,0 +1,45 @@ +# Tests for PASCO2 module +from machine import I2C +import time +import pasco2 as sensor + +i2c = I2C(0) +pasco2 = sensor.PASCO2(i2c) + + +def sensor_init(): + init_status = pasco2.initialize() + return init_status + + +def sensor_get_specs(): + # read product id + sensorID = pasco2.get_prod_id() + # read revision id + revID = pasco2.get_rev_id() + return [sensorID, revID] + + +def sensor_get_values(): + co2ppm = pasco2.get_co2_value() + return co2ppm + + +print("PASCO2 test module running") +print("\nTest 1: Sensor Init") +print("Status: Test", "passed" if sensor_init() == 0 else "failed") +print("\nTest 2: Get sensor specs") +specs = sensor_get_specs() +print("Status: Test", "passed" if (specs.count(-1) == 0) else "failed") +print("\nTest 3: Get sensor values for 100 cycles") +for i in range(0, 100): + time.sleep(1) + co2ppm = sensor_get_values() + if co2ppm != -1: + print( + "Status: Test", + "passed" if (co2ppm in range(0, 1000)) else "failed", + "[CO2 Value:", + co2ppm, + "]", + )