Library to communicate with LDC1614
Dependents: Inductive_Sensor_3
Fork of LDC1101 by
Diff: LDC1614.cpp
- 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