Library to communicate with LDC1614
Dependents: Inductive_Sensor_3
Fork of LDC1101 by
LDC1614.cpp
- Committer:
- bobgiesberts
- Date:
- 2016-08-24
- Revision:
- 30:95c53d244f91
- Parent:
- 29:41815fd13822
- Child:
- 31:ab4354a71996
File content as of revision 30:95c53d244f91:
/** LDC1614 library * @file LDC1614.cpp * @brief this C++ file contains all required * functions to interface with Texas * Instruments' LDC1614. * * @author Bob Giesberts * * @date 2016-08-09 * * @code * 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) ); * } * } * @endcode */ #include "LDC1614.h" #include "mbed_debug.h" LDC1614::LDC1614(PinName sda, PinName scl, PinName sd, PinName os, float f_CLKIN, int channels, float capacitor) : _i2c(sda, scl), _shutdown_pin(sd), _oscillator(os) { // 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??? // start communication _i2c.frequency(400000); // 400 kHz (p.6) // Initilialize the LDC1614 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) ************************************/ // Configuring setup, set LDC in configuration modus sleep(); 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, ( ( _channels - 2 > 0 ) ? _channels - 2 : 0 ) ); 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: // turn on oscillator _oscillator.write( 1 ); wait_ms(3); // datasheet oscillator says 3 ms max // turn on LDC _shutdown_pin.write( 0 ); set( CONFIG, SLEEP_MODE_EN, mode ); wait_us(400); // Wait 16384 f_INT clock cycles (0.377 ms) (p.16) break; case LDC_MODE_SHUTDOWN: _shutdown_pin.write( 1 ); _oscillator.write( 0 ); break; } } void LDC1614::sleep( void ) { func_mode( LDC_MODE_SLEEP ); } void LDC1614::wakeup( void ) { func_mode( LDC_MODE_ACTIVE ); } void LDC1614::shutdown( void ) { func_mode( LDC_MODE_SHUTDOWN ); } 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 = (( divIN < 15) ? (( divIN > 1) ? divIN : 1) : 15 ); // 4 bit _dividerIN = ((divREF < 255) ? ((divREF > 1) ? 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 = ((idrive < 31) ? 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 ); } uint8_t LDC1614::get( ADDR addr, SETTING setting, uint8_t mask ) { 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 } } uint16_t data[1]; readI2C( data, addr ); return ( data[0]>>setting ) & 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( uint8_t status ) { if( status == 17 ) { status = get_status(); } return ( status>>DRDY ) & 1; } bool LDC1614::is_error( uint8_t status ) { if( status == 17 ) { status = get_status(); } return ((( status>>ERR_ZC ) & 6) == 0); } 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 ); if( ((data[0]>>CHx_ERR_UR) & 1) == 1 ) { debug( "Under-range Error" ); } if( ((data[0]>>CHx_ERR_OR) & 1) == 1 ) { debug( "Over-range Error" ); } if( ((data[0]>>CHx_ERR_WD) & 1) == 1 ) { debug( "Watchdog Timeout Error" ); } if( ((data[0]>>CHx_ERR_AE) & 1) == 1 ) { debug( "Amplitude Error" ); } return ( (data[0] & 0x0fff)<<16 ) | data[1]; // MSB + LSB } /* REGISTER FUNCTIONS (READ / WRITE) */ 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 ***********************************************************