Soil Measurements for pH and moisture

Dependencies:   AD7124

Dependents:   cn0398-helloworld

Fork of CN0398 by Analog Devices

For additional information check out the mbed page of the Analog Devices wiki: https://wiki.analog.com/resources/tools-software/mbed-drivers-all

CN0398.cpp

Committer:
adisuciu
Date:
2016-10-26
Revision:
3:7072863079d5
Parent:
2:f1b9c875e725

File content as of revision 3:7072863079d5:

#include "CN0398.h"
#include "AD7124.h"
#include <mbed.h>

#define RREF (5000.0)
#define TEMP_GAIN (16.0)
#define PT100_RESISTANCE_TO_TEMP(x) ((x-100.0)/(0.385))
#define _2_23 (1<<23)

#define CALIBRATION_NR_OF_SAMPLES (5)

extern Serial pc;

#define ms_delay (1)

CN0398::CN0398(PinName cs, PinName adp7118enable) : ad7124(cs), ADP7118Enable(adp7118enable), offset_voltage(default_offset_voltage)
{
    use_nernst = false;
    calibration_ph[0][0] = 4;//default_calibration_ph[0][0];
    calibration_ph[0][1] = 0.169534;//default_calibration_ph[0][1];
    calibration_ph[1][0] = 10;//default_calibration_ph[1][0];
    calibration_ph[1][1] = -0.134135;//default_calibration_ph[1][1];
    solution0 = 0;
    solution1 = 0;
}

void CN0398::calibrate_ph_pt0(float temperature)
{
    float volt = 0;
    for(int i = 0; i < CALIBRATION_NR_OF_SAMPLES; i++) {
        set_digital_output(P2, true);
        int32_t data = read_channel(0);
        set_digital_output(P2, false);
        volt += data_to_voltage_bipolar(data >> 8, 1, 3.3);
    }
    volt = volt / CALIBRATION_NR_OF_SAMPLES;
    if(temperature < 0) {
        calibration_ph[0][0] = ph_temp_lut[solution0][0];
    } else {
        for(uint8_t i = 1; i < NUMBER_OF_TEMPERATURE_ENTRIES; i++) {
            if(temperature > ph_temperatures[i - 1] && temperature <= ph_temperatures[i]) {
                calibration_ph[0][0] = ph_temp_lut[solution0][i];
                break;
            }
        }
    }
    calibration_ph[0][1] = volt;
    pc.printf("Calibration solution 1 ph: %f with sensor voltage of %f\r\n", calibration_ph[0][0], volt);
}
void CN0398::calibrate_ph_pt1(float temperature)
{
    float volt = 0;
    for(int i = 0; i < CALIBRATION_NR_OF_SAMPLES; i++) {
        set_digital_output(P2, true);
        int32_t data = read_channel(0);
        set_digital_output(P2, false);
        volt += data_to_voltage_bipolar(data >> 8, 1, 3.3);
    }

    volt = volt / CALIBRATION_NR_OF_SAMPLES;
    if(temperature < 0) {
        calibration_ph[1][0] = ph_temp_lut[solution1][0];
    } else {
        for(uint8_t i = 1; i < NUMBER_OF_TEMPERATURE_ENTRIES; i++) {
            if(temperature > ph_temperatures[i - 1] && temperature <= ph_temperatures[i]) {
                calibration_ph[1][0] = ph_temp_lut[solution1][i];
                break;
            }
        }
    }
    calibration_ph[1][1] = volt;
    pc.printf("Calibration solution 2 ph: %f with sensor voltage of %f\r\n", calibration_ph[1][0], volt);
}

void CN0398::calibrate_ph_offset()
{
    float volt = 0;
    for(int i = 0; i < CALIBRATION_NR_OF_SAMPLES; i++) {
        set_digital_output(P2, true);
        int32_t data = read_channel(0);
        set_digital_output(P2, false);
        volt += data_to_voltage_bipolar(data >> 8, 1, 3.3);
    }
    offset_voltage = volt / CALIBRATION_NR_OF_SAMPLES;
    pc.printf("Offset voltage is: %f \r\n", volt);
}


float CN0398::read_rtd()
{
    float temperature = 25.0;
#ifdef TEMPERATURE_SENSOR_PRESENT
    int32_t data = read_channel(2);
    data = (data >> 8) & 0x00ffffff;
    float resistance = ((static_cast<float>(data) - _2_23) * RREF) / (TEMP_GAIN * _2_23);
#ifdef USE_LINEAR_TEMP_EQ
    temperature = PT100_RESISTANCE_TO_TEMP(resistance);
#else

#define A (3.9083*pow(10.0,-3.0))
#define B (-5.775*pow(10.0,-7.0))
    /*if(resistance < 100.0)
        temperature = -242.02 + 2.228 * resistance + (2.5859 * pow(10, -3)) * pow(resistance, 2) - (48260 * pow(10, -6)) * pow(resistance, 3) - (2.8183 * pow(10, -3)) * pow(resistance, 4) + (1.5243 * pow(10, -10)) * pow(resistance, 5);
    else*/
    temperature = ((-A + sqrt(double(pow(A, 2.0) - 4 * B * (1 - resistance / 100.0))) ) / (2 * B));
#endif
#endif
    return temperature;

}

int32_t CN0398::read_channel(uint8_t ch)
{
    int32_t data;
    enable_channel(ch);
    start_single_conversion();

    if (ad7124.WaitForConvReady(10000) == -3) {
        pc.printf("TIMEOUT");
        return -1;
    }
    ad7124.ReadData(&data);
    disable_channel(ch);
    return data;

}
float CN0398::read_ph(float temperature)
{
    float ph = 0;
#ifdef PH_SENSOR_PRESENT
    set_digital_output(P2, true);
    int32_t data = read_channel(0);
    set_digital_output(P2, false);
    float volt = data_to_voltage_bipolar(data >> 8, 1, 3.3);
#ifdef DEBUG_MODE
    pc.printf("pH sensor voltage - %f\n", volt);
#endif

    if(use_nernst) {
        ph  = -((volt - ZERO_POINT_TOLERANCE) / ((2.303 * AVOGADRO * (temperature + KELVIN_OFFSET)) / FARADAY_CONSTANT) ) + PH_ISO;
    } else {
        float m =  (calibration_ph[1][0] - calibration_ph[0][0]) / (calibration_ph[1][1] - calibration_ph[0][1]);
        ph = m * (volt - calibration_ph[1][1] + offset_voltage) + calibration_ph[1][0];
    }
#endif
    return ph;
}
float CN0398::read_moist()
{
    float moisture = 0;
#ifdef MOISTURE_SENSOR_PRESENT
    ADP7118Enable = true;
    set_digital_output(P3, true);
    wait_ms(SENSOR_SETTLING_TIME);
    int32_t data = read_channel(1);
    ADP7118Enable = false;
    set_digital_output(P3, false);

    data = (data >> 8) & 0x00ffffff;
    float volt = data_to_voltage(data, 1, 3.3);
#ifdef USE_MANUFACTURER_MOISTURE_EQ
    if(volt <= 1.1) {
        moisture = 10 * volt - 1;
    } else if(volt > 1.1 && volt <= 1.3) {
        moisture = 25 * volt - 17.5;
    } else if(volt > 1.3 && volt <= 1.82) {
        moisture = 48.08 * volt - 47.5;
    } else if(volt > 1.82) {
        moisture = 26.32 * volt - 7.89;
    }
#else
    moisture = -1.18467 + 21.5371 * volt - 110.996 * (pow(volt, 2)) + 397.025 * (pow(volt, 3)) - 666.986 * (pow(volt, 4)) + 569.236 * (pow(volt, 5)) - 246.005 * (pow(volt, 6)) + 49.4867 * (pow(volt, 7)) - 3.37077 * (pow(volt, 8));
#endif
    if(moisture > 100) moisture = 100;
    if(moisture < 0 ) moisture = 0;
#endif
    return moisture;
}

float CN0398::data_to_voltage_bipolar(uint32_t data, uint8_t gain, float VREF)
{
    data = data & 0xFFFFFF;
    return ((data / static_cast<float>(0xFFFFFF / 2)) - 1) * (VREF / gain);
}

float CN0398::data_to_voltage(uint32_t data, uint8_t gain, float VREF)
{
    data = data & 0xFFFFFF;
    return (data / static_cast<float>(0xFFFFFF)) * (VREF / gain);
}

void CN0398::enable_channel(int channel)
{
    AD7124::ad7124_registers regNr = static_cast<AD7124::ad7124_registers> (AD7124::AD7124_Channel_0 + channel); //Select ADC_Control register
    uint32_t setValue = ad7124.ReadDeviceRegister(regNr);
    setValue |= (uint32_t) AD7124_CH_MAP_REG_CH_ENABLE;  //Enable channel0
    setValue &= 0xFFFF;
    ad7124.WriteDeviceRegister(regNr, setValue);    // Write data to ADC
    wait_ms(ms_delay);
}

void CN0398::disable_channel(int channel)
{
    AD7124::ad7124_registers regNr = static_cast<AD7124::ad7124_registers> (AD7124::AD7124_Channel_0 + channel); //Select ADC_Control register
    uint32_t setValue = ad7124.ReadDeviceRegister(regNr);
    setValue &= (~(uint32_t) AD7124_CH_MAP_REG_CH_ENABLE);  //Enable channel0
    setValue &= 0xFFFF;
    ad7124.WriteDeviceRegister(regNr, setValue);    // Write data to ADC
    wait_ms(ms_delay);
}

/*
void CN0398::enable_current_source0(int current_source_channel)
{
    AD7124::ad7124_registers regNr = AD7124::AD7124_IOCon1; //Select ADC_Control register
    uint32_t setValue = ad7124.ReadDeviceRegister(regNr);
    setValue &= ~(AD7124_IO_CTRL1_REG_IOUT_CH0(0xF));
    setValue |= AD7124_IO_CTRL1_REG_IOUT_CH0(current_source_channel);// set IOUT0 current to 500uA
    setValue &= 0xFFFFFF;
    ad7124.WriteDeviceRegister(regNr, setValue);    // Write data to ADC
    wait_ms(ms_delay);
}

void CN0398::enable_current_source1(int current_source_channel)
{
    AD7124::ad7124_registers regNr = AD7124::AD7124_IOCon1; //Select ADC_Control register
    uint32_t setValue = ad7124.ReadDeviceRegister(regNr);
    setValue &= ~(AD7124_IO_CTRL1_REG_IOUT_CH1(0xF));
    setValue |= AD7124_IO_CTRL1_REG_IOUT_CH1(current_source_channel);// set IOUT0 current to 500uA
    setValue &= 0xFFFFFF;
    ad7124.WriteDeviceRegister(regNr, setValue);    // Write data to ADC
    wait_ms(ms_delay);
}*/

void CN0398::set_digital_output(ad_digital_output_t p, bool state)
{
    AD7124::ad7124_registers regNr = AD7124::AD7124_IOCon1; //Select ADC_Control register
    uint32_t setValue = ad7124.ReadDeviceRegister(regNr);
    if(state)
        setValue |= ((AD7124_8_IO_CTRL1_REG_GPIO_DAT1) << p);
    else
        setValue &= (~((AD7124_8_IO_CTRL1_REG_GPIO_DAT1) << p));
    ad7124.WriteDeviceRegister(regNr, setValue);    // Write data to ADC
    wait_ms(ms_delay);
}


void CN0398::start_single_conversion()
{
    AD7124::ad7124_registers regNr = AD7124::AD7124_ADC_Control; //Select ADC_Control register
    uint32_t setValue = ad7124.ReadDeviceRegister(regNr);
    setValue &= 0xFFC3;
    setValue |= 0x04;               //single conversion;
    setValue |= AD7124_ADC_CTRL_REG_DATA_STATUS;
    setValue &= 0xFFFF;
    ad7124.WriteDeviceRegister(regNr, setValue);    // Write data to ADC*/
    wait_ms(ms_delay * 10);
}

void CN0398::reset()
{
    ad7124.frequency(500000);
    ad7124.Reset();
    pc.printf("Reseted AD7124\r\n");
    wait_ms(1000);
}

void CN0398::setup()
{
    ad7124.Setup();
}

void CN0398::init()
{
    uint32_t setValue;
    enum AD7124::ad7124_registers regNr;

    /* Set Config_0 0x19*/
    regNr = AD7124::AD7124_Config_0;               //Select Config_0 register - pH
    setValue = 0;//ad7124.ReadDeviceRegister(regNr);
    setValue |= AD7124_CFG_REG_BIPOLAR;     //Select bipolar operation
    setValue |= AD7124_CFG_REG_BURNOUT(0);  //Burnout current source off
    setValue |= AD7124_CFG_REG_REF_BUFP;
    setValue |= AD7124_CFG_REG_REF_BUFM;
    setValue |= AD7124_CFG_REG_AIN_BUFP;    //Buffer AIN5
    setValue |= AD7124_CFG_REG_AINN_BUFM;   //Buffer AIN4
    setValue |= AD7124_CFG_REG_REF_SEL(0); //REFIN1(+)/REFIN1(−).
    setValue |= AD7124_CFG_REG_PGA(0);
    setValue &= 0xFFFF;
    ad7124.WriteDeviceRegister(regNr, setValue);   // Write data to ADC

    /* Set Config_0 0x1A*/
    regNr = AD7124::AD7124_Config_1;               //Select Config_1 register - Moisture
    setValue = 0;//ad7124.ReadDeviceRegister(regNr);
    setValue &= ~AD7124_CFG_REG_BIPOLAR;     //Select bipolar operation
    setValue |= AD7124_CFG_REG_BURNOUT(0);  //Burnout current source off
    setValue |= AD7124_CFG_REG_REF_BUFP;
    setValue |= AD7124_CFG_REG_REF_BUFM;
    setValue |= AD7124_CFG_REG_AIN_BUFP;    //Buffer AIN5
    setValue |= AD7124_CFG_REG_AINN_BUFM;   //Buffer AIN4*/
    setValue |= AD7124_CFG_REG_REF_SEL(0); // REFIN1(+)/REFIN1(−).
    setValue |= AD7124_CFG_REG_PGA(0);
    setValue &= 0xFFFF;
    ad7124.WriteDeviceRegister(regNr, setValue);   // Write data to ADC

    /* Set Config_0 0x1B*/
    regNr = AD7124::AD7124_Config_2;               //Select Config_2 register - temp
    setValue = 0;//ad7124.ReadDeviceRegister(regNr);
    setValue |= AD7124_CFG_REG_BIPOLAR;     //Select bipolar operation
    setValue |= AD7124_CFG_REG_BURNOUT(0);  //Burnout current source off
    setValue |= AD7124_CFG_REG_REF_BUFP;
    setValue |= AD7124_CFG_REG_REF_BUFM;
    setValue |= AD7124_CFG_REG_AIN_BUFP;    //Buffer AIN5
    setValue |= AD7124_CFG_REG_AINN_BUFM;   //Buffer AIN4
    setValue |= AD7124_CFG_REG_REF_SEL(1); //REFIN2(+)/REFIN2(-).
    setValue |= AD7124_CFG_REG_PGA(4); // gain 16
    setValue &= 0xFFFF;
    ad7124.WriteDeviceRegister(regNr, setValue);   // Write data to ADC

    /* Set Channel_0 register 0x09*/
    regNr = AD7124::AD7124_Channel_0;  // pH reading
    setValue = 0;
    setValue |= AD7124_CH_MAP_REG_SETUP(0);             // Select setup0
    setValue |= AD7124_CH_MAP_REG_AINP(6);         // Set AIN4 as positive input
    setValue |= AD7124_CH_MAP_REG_AINM(7);         // Set AIN5 as negative input
    setValue &= 0xFFFF;
    ad7124.WriteDeviceRegister(regNr, setValue);   // Write data to ADC

    regNr = AD7124::AD7124_Channel_1; // Moisture
    setValue = 0;
    setValue |= AD7124_CH_MAP_REG_SETUP(1);             // Select setup0
    setValue |= AD7124_CH_MAP_REG_AINP(8);         // Set AIN4 as positive input
    setValue |= AD7124_CH_MAP_REG_AINM(19);         // Set AIN5 as negative input
    setValue &= 0xFFFF;
    ad7124.WriteDeviceRegister(regNr, setValue);   // Write data to ADC

    regNr = AD7124::AD7124_Channel_2; // RTD - gain 16
    setValue = 0;
    setValue |= AD7124_CH_MAP_REG_SETUP(2);             // Select setup0
    setValue |= AD7124_CH_MAP_REG_AINP(9);         // Set AIN4 as positive input
    setValue |= AD7124_CH_MAP_REG_AINM(10);         // Set AIN5 as negative input
    setValue &= 0xFFFF;
    ad7124.WriteDeviceRegister(regNr, setValue);   // Write data to ADC

    /* Set IO_Control_1 0x03 */
    regNr = AD7124::AD7124_IOCon1;               //Select IO_Control_1 register
    //setValue = ad7124.ReadDeviceRegister(regNr);
    setValue = 0;
    setValue |= AD7124_8_IO_CTRL1_REG_GPIO_CTRL2; // enable AIN3 as digital output
    setValue |= AD7124_8_IO_CTRL1_REG_GPIO_CTRL3; // enable AIN4 as digital output
    setValue |= AD7124_IO_CTRL1_REG_IOUT_CH0(11); // source ain11
    setValue |= AD7124_IO_CTRL1_REG_IOUT_CH1(12); // source ain12
    setValue |= AD7124_IO_CTRL1_REG_IOUT0(0x4);// set IOUT0 current to 500uA
    setValue |= AD7124_IO_CTRL1_REG_IOUT1(0x4);// set IOUT0 current to 500uA*/
    setValue &= 0xFFFFFF;
    ad7124.WriteDeviceRegister(regNr, setValue);// Write data to ADC

    // Set IO_Control_2
    regNr = AD7124::AD7124_IOCon2;               //Select IO_Control_2 register
    setValue = 0;
    setValue |= AD7124_8_IO_CTRL2_REG_GPIO_VBIAS7; // enable AIN3 as digital output
    setValue &= 0xFFFFFF;
    ad7124.WriteDeviceRegister(regNr, setValue);// Write data to ADC


    /* Set ADC_Control 0x01 */
    regNr = AD7124::AD7124_ADC_Control;            //Select ADC_Control register
    setValue = ad7124.ReadDeviceRegister(regNr);
    setValue |= AD7124_ADC_CTRL_REG_DATA_STATUS; // set data status bit in order to check on which channel the conversion is
    setValue &= 0xFFC3; // remove prev mode bits
    setValue |= AD7124_ADC_CTRL_REG_MODE(2);
    setValue &= 0xFFFF;
    ad7124.WriteDeviceRegister(regNr, setValue);    // Write data to ADC
    wait_ms(ms_delay);
}