Library to communicate with LDC1614

Dependencies:   SHTx

Dependents:   Inductive_Sensor_3

Fork of LDC1101 by Bob Giesberts

Revision:
28:76a2fc42f888
Parent:
27:05dd145c7997
Child:
29:41815fd13822
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LDC1614.cpp	Tue Aug 23 08:25:40 2016 +0000
@@ -0,0 +1,271 @@
+/**
+* @file LDC1614.cpp
+* @brief this C++ file contains all required
+* functions to interface with Texas
+* Instruments' LDC1614.
+*
+* @author Bob Giesberts
+*
+* @date 2016-08-09
+*
+* @example
+* Serial pc(USBTX, USBRX);
+* LDC1614 ldc(PTC6, PTC7, PTC5, 16E6, 2, 120E-12);
+* int main(){
+*    while(1) {
+*       while( !ldc.is_ready() ) {}
+*    
+*       pc.printf("sensor 1: %d | sensor 2: %d\r\n", ldc.get_Data(0), ldc.get_Data(1) );
+*    }
+* }
+*/
+
+#include "LDC1614.h"
+
+
+LDC1614::LDC1614(PinName sda, PinName scl, PinName sd, float f_CLKIN, int channels, float capacitor) : _i2c(sda, scl), _shutdown_pin(sd)
+{
+    // settings
+    _channels = channels;   // number of sensors
+    _cap      = capacitor;
+    _fCLKIN  = f_CLKIN;
+
+    _Offset = 0;            // no offset needed
+    _Rcount = 0xffff;       // maximum for greatest precision
+    _SettleCount = 50;      // CHx_SETTLECOUNT = t_settle * f_REFx/16 = 50 (p.12)
+    _DriveCurrent = 31;     // max???
+       
+    _i2c.frequency(400000); // 400 kHz (p.6)
+    
+    // Turn the LDC1614 on (exit shutdown)
+    _shutdown_pin.write(0);
+    wait_us(100);
+    
+    init();
+}
+
+LDC1614::~LDC1614()
+{
+
+}
+
+void LDC1614::init()
+{
+    /********* SETTINGS *****************
+    ** C_sensor     =   120 pF
+    ** L_sensor     =     5 uH
+    ** Rp_min       =  1500 Ohm
+    **
+    ** RCount       = 65535     (max)
+    ** Settlecount  =    50
+    ** Samplerate   =    15.3 Hz
+    ** t_conv       =    65.5 ms
+    **
+    ** f_sensor_min =     6.4 MHz (d = inf)
+    ** f_sensor_max =    10   MHz (d = 0)
+    ** 
+    ** CHx_FIN_DIVIDER  =     2       (6.4/2 = 3.2 < 16.0/4 = 4)
+    ** CHx_FREF_DIVIDER =     1       (16.0 MHz)    
+    ************************************/
+    
+    for(int i = 0; i < _channels; i++)
+    {
+        // set Reference Count to highest resolution
+        setReferenceCount( i, _Rcount );
+
+        // set the settling time
+        // t_settle = (settlecount * 16) /f_REF
+        setSettlecount( i, _SettleCount );
+        
+        // set Divider to 1 (for large range / ENOB / resolution)
+        setDivider( i, 1, 2 ); // IN = 2 | REF = 1
+        
+        // set the drive current during sampling 
+        setDriveCurrent( i, _DriveCurrent );   // (p. 15 | Figure 14)
+        
+        // shift the signal down a bit
+        setOffset( i, _Offset );
+    }
+
+    // error_config (all  is standard)
+    
+    // mux_config    
+    set( MUX_CONFIG, AUTOSCAN_EN,    _channels > 1 );
+    set( MUX_CONFIG, RR_SEQUENCE,    max(0, _channels - 2) );
+    set( MUX_CONFIG, DEGLITCH,       DEGLITCH_10M );
+    
+    // override Rp and use own Drive Current to reduce power consumption
+    set( CONFIG, RP_OVERRIDE_EN,      1 );
+    set( CONFIG, SENSOR_ACTIVATE_SEL, 1 );
+    set( CONFIG, AUTO_AMP_DIS,        1 );
+    set( CONFIG, REF_CLK_SRC,         1 ); // external f_CLKIN
+    set( CONFIG, INTB_DIS,            1 );
+    set( CONFIG, HIGH_CURRENT_DRV,    0 );
+    
+    // Done configuring settings, set LDC1614 in measuring modus
+    wakeup();
+}
+
+
+void LDC1614::func_mode(LDC_MODE mode)
+{ 
+    switch (mode)
+    {
+        case LDC_MODE_ACTIVE:
+        case LDC_MODE_SLEEP:
+            _shutdown_pin.write( 0 );
+            set( CONFIG, SLEEP_MODE_EN, LDC_MODE_ACTIVE );
+            break;
+        
+        case LDC_MODE_SHUTDOWN:
+            _shutdown_pin.write( 1 );
+            break;
+    }
+}
+void LDC1614::sleep( void )  { func_mode( LDC_MODE_SLEEP );  }
+void LDC1614::wakeup( void ) { func_mode( LDC_MODE_ACTIVE ); }
+
+void LDC1614::setReferenceCount( uint8_t channel, uint16_t rcount )
+{
+    writeI2Cregister( RCOUNT_CH0 + channel, rcount );
+}
+
+void LDC1614::setOffset( uint8_t channel, uint32_t offset )
+{
+    _Offset = offset;
+    writeI2Cregister( OFFSET_CH0 + channel, uint16_t (offset >> 16) );
+}
+
+void LDC1614::setSettlecount( uint8_t channel, uint16_t settlecount )
+{
+    // _t_settle = (settlecount * 16) / (_f_CLKIN / dividerREF[channel])
+    writeI2Cregister( SETTLECOUNT_CH0 + channel, settlecount );    
+}
+
+void LDC1614::setDivider( uint8_t channel, uint8_t divIN, uint8_t divREF )
+{
+    // make sure the values fit
+    _dividerIN  = min(max(divIN,  1), 15);  // 4 bit
+    _dividerREF = min(max(divREF, 1), 255); // 8 bit    
+    writeI2Cregister( CLOCK_DIVIDERS_CH0 + channel, uint16_t ((_dividerIN << 12) + _dividerREF) );
+} 
+
+void LDC1614::setDriveCurrent( uint8_t channel, uint8_t idrive )
+{   
+    _DriveCurrent = min( idrive, 31 ); // 5-bit (b1 1111)
+    // todo: read initial idrive [10:6]
+
+    writeI2Cregister(DRIVE_CURRENT_CH0 + channel, uint16_t (_DriveCurrent<<10) );
+}
+
+void LDC1614::set( ADDR addr, SETTING setting, uint8_t value )
+{
+    uint8_t mask = 1;
+    if ( addr == MUX_CONFIG )
+    {
+        switch (setting){
+            case AUTOSCAN_EN: mask = 1; break;  // 1
+            case RR_SEQUENCE: mask = 3; break;  // 11
+            case DEGLITCH:    mask = 7; break;  // 111
+        }    
+    }
+    regchange( addr, setting, value, mask );
+}
+
+
+
+
+
+
+/* GETTING DATA FROM SENSOR */
+
+uint16_t LDC1614::get_status( void )
+{
+    uint16_t status[1]; 
+    readI2C( status, STATUS );  
+    return status[0];
+}
+bool LDC1614::is_ready( void )            { return ( get_status() & 0x0080 ); }
+
+
+uint16_t LDC1614::get_Rcount( uint8_t channel )
+{
+    uint16_t rcount[1]; 
+    readI2C( rcount, RCOUNT_CH0 + channel ); 
+    return rcount[0];
+}
+
+uint32_t LDC1614::get_Data( uint8_t channel )
+{
+    uint16_t data[2];
+    readI2C(data, DATA_MSB_CH0 + channel, 2);
+    return ( (data[0] & 0x0fff)<<16) | data[1]; // MSB + LSB
+}
+
+
+
+
+
+void LDC1614::readI2C( uint16_t *data, uint8_t address, uint8_t length )
+{
+    // I2C reads per 8-bits, char is 8-bit, combine 8-bit in 16-bit sets
+    char temp[length*2];
+    _i2c.read( address, temp, length*2 );
+    
+    for ( int i = 0; i < length; i++ ) 
+        data[i] = (uint16_t) (temp[2*i+1]<<8) | temp[2*i];
+}
+
+void LDC1614::writeI2C( uint16_t *data, uint8_t address, uint8_t length )
+{
+    // I2C reads per 8-bits, char is 8-bit, split 16-bit data up in sets of 8-bit
+    char temp[length*2];
+    for ( int i = 0; i < length; i++ )
+    {
+        temp[2*i]   = (data[i] & 0x00ff) >> 0; // 0, 2, 4 ...
+        temp[2*i+1] = (data[i] & 0xff00) >> 8; // 1, 3, 5 ...
+    }
+    _i2c.write( address, temp, length*2 );
+}
+
+void LDC1614::writeI2Cregister(uint8_t reg, uint16_t value)
+{
+    writeI2C( &value, reg ); 
+}
+
+void LDC1614::regchange( uint8_t addr, uint8_t setting, uint8_t value, uint8_t mask )
+{
+    uint16_t config[1];
+    readI2C( config, addr );
+    writeI2Cregister( addr, uint16_t ( (config[0] & !(mask<<setting)) | (value<<setting)) ); // replace bits with number SETTING
+}
+
+
+
+/* CALCULATE STUFF WITH SENSOR DATA */
+
+float LDC1614::get_fsensor( uint32_t LData )
+{    
+    _fsensor = _dividerIN * (_fCLKIN/_dividerREF) * ((LData / 268435456) + (_Offset / 65536)); // (p.14)
+       
+    return _fsensor;
+}   
+
+float LDC1614::get_Inductance( uint32_t Ldata )
+{  
+    float fsensor = get_fsensor( Ldata );
+    _inductance = 1.0 / (_cap * 4 * PI*PI * fsensor*fsensor ); // ???
+    return _inductance;
+}
+
+
+
+// EXTRA test: Get&print values of all variables to verify (to calculate the induction)
+// The data will be printed on the screen using RealTerm: baud 9600.
+// Begin ***********************************************************
+    float LDC1614::get_fCLKIN()             {return _fCLKIN;}    
+    uint8_t LDC1614::get_dividerIN()        {return _dividerIN;}
+    uint8_t LDC1614::get_dividerREF()       {return _dividerREF;}
+    uint32_t LDC1614::get_Offset()          {return _Offset;}
+    float LDC1614::get_cap()                {return _cap;}
+// END ***********************************************************
\ No newline at end of file