├── .gitattributes ├── extras ├── fdc2214.pdf └── images │ ├── fdc-on-serialplot-noise.PNG │ ├── fdc-on-serialplot-port.PNG │ ├── fdc-on-serialplot-signal.PNG │ └── fdc-on-serialplot-dataformat.PNG ├── library.properties ├── .gitignore ├── keywords.txt ├── LICENSE ├── readme.md ├── examples ├── testFDC-Serial │ └── testFDC-Serial.ino └── testFDC-Serial-OLED │ └── testFDC-Serial-OLED.ino └── src ├── FDC2214.h └── FDC2214.cpp /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /extras/fdc2214.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zharijs/FDC2214/HEAD/extras/fdc2214.pdf -------------------------------------------------------------------------------- /extras/images/fdc-on-serialplot-noise.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zharijs/FDC2214/HEAD/extras/images/fdc-on-serialplot-noise.PNG -------------------------------------------------------------------------------- /extras/images/fdc-on-serialplot-port.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zharijs/FDC2214/HEAD/extras/images/fdc-on-serialplot-port.PNG -------------------------------------------------------------------------------- /extras/images/fdc-on-serialplot-signal.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zharijs/FDC2214/HEAD/extras/images/fdc-on-serialplot-signal.PNG -------------------------------------------------------------------------------- /extras/images/fdc-on-serialplot-dataformat.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zharijs/FDC2214/HEAD/extras/images/fdc-on-serialplot-dataformat.PNG -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=FDC2214 2 | version=1.1 3 | author=Harijs Zablockis 4 | maintainer=Harijs Zablockis 5 | sentence=TI FDC2214 capacitative sensor library 6 | paragraph=Library to support Texas instruments capacitative sensors. Supports FDC2112, FDC2114, FSC2212 and FDC2214 chips. 7 | category=Sensors 8 | url=https://github.com/zharijs/FDC2214 9 | architectures=avr,esp8266 10 | includes=FDC2214.h -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map For ExampleLibrary 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | 9 | FDC2214 KEYWORD1 10 | 11 | ####################################### 12 | # Methods and Functions (KEYWORD2) 13 | ####################################### 14 | 15 | begin KEYWORD2 16 | getReading16 KEYWORD2 17 | getReading28 KEYWORD2 18 | 19 | ####################################### 20 | # Instances (KEYWORD2) 21 | ####################################### 22 | 23 | ####################################### 24 | # Constants (LITERAL1) 25 | ####################################### 26 | 27 | FDC2214_I2C_ADDR_0 LITERAL1 28 | FDC2214_I2C_ADDR_1 LITERAL1 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # FDC2214 Arduino Library 2 | Library for Texas Instruments FDC2xxx family capacitative sensor front-ends. 3 | 4 | # Supported devices 5 | >* FDC2112 6 | >* FDC2114 7 | >* FDC2212 8 | >* FDC2214 9 | 10 | # Revision 11 | >* 1.0 - 1 - Initial release 12 | >* 1.1 - 1 - Fixed channel 2 and 3 support. 13 | >* 1.1 - 2 - Added support for internal oscillator. Not reccomended for any fairly precise aplication. 14 | >* 1.2 - 1 - RJH - Removed redundent code and applied one recommended update 15 | 16 | # Usage 17 | Include header, Make instance, Init and acquire data. 18 | 19 | ```cpp 20 | #include "FDC2214.h" 21 | FDC2214 capsense(FDC2214_I2C_ADDR_0); // Use FDC2214_I2C_ADDR_1 for ADDR = VCC 22 | ... 23 | void setup() { 24 | ... 25 | Wire.begin(); 26 | bool capOk = capsense.begin(0x3, 0x4, 0x5, false); //setup first two channels, autoscan with 2 channels, deglitch at 10MHz, use external oscillator 27 | ... 28 | } 29 | void loop(){ 30 | ... 31 | unsigned long capa[i] = capsense.getReading28(i); 32 | ... 33 | } 34 | ``` 35 | 36 | # Hardware 37 | FDC2xxx family is 3.3V powered, unlike most of Arduinos, that are powered form 5V. 38 | **To use this chip with Arduino, you will have to either:** 39 | > 1. use 3.3V version of Arduino, like Arduino Pro Mini 8MHz 3.3V 40 | > 2. use I2C level shifter to interface the FDC chip with arduino. 41 | 42 | **To run examples, connect FDC with arduino as follows:** 43 | >* ARDUINO <--> FDC 44 | >* A4 <-------> SDA 45 | >* A5 --------> SCL 46 | >* GND -------> ADR 47 | >* GND -------> SD 48 | 49 | # Tools 50 | To view nice real-time graph of the sensor output, it is highly recommended to use tool like SerialPlot. 51 | https://github.com/hyOzd/serialplot 52 | 53 | **Setting up port:** 54 | ![Port](https://github.com/zharijs/FDC2214/blob/master/extras/images/fdc-on-serialplot-port.PNG?raw=true "Port") 55 | 56 | **Setting up data format:** 57 | ![Data Format](https://github.com/zharijs/FDC2214/blob/master/extras/images/fdc-on-serialplot-dataformat.PNG?raw=true "Data Format") 58 | 59 | **Proximity sensing waveform:** 60 | ![Signal](https://github.com/zharijs/FDC2214/blob/master/extras/images/fdc-on-serialplot-signal.PNG?raw=true "Signal") 61 | 62 | **Noise waveform:** 63 | ![Noise](https://github.com/zharijs/FDC2214/blob/master/extras/images/fdc-on-serialplot-noise.PNG?raw=true "Noise") 64 | 65 | #Have Fun 66 | -------------------------------------------------------------------------------- /examples/testFDC-Serial/testFDC-Serial.ino: -------------------------------------------------------------------------------- 1 | // This is example code to demonstrate the functionality of FDC2214 library 2 | // 3 | // There is no warranty to the code. There is no support, don't ask for it. 4 | // Use or skip on your own responsibility. 5 | // NOT ALL FEATURES ARE TESTED! 6 | // 7 | // The code might get revisited at some point or it might not. 8 | // The code does more than I need at the moment. 9 | // 10 | // Feel free to do whatever you want with it. No licensing BS. No limitations. 11 | // 12 | // Created by Harijs Zablockis, Intelitech, March 2018 13 | // 14 | // Supproted chips: FDC2112, FDC2114, FDC2212, FDC2214 15 | // Transmitts data via serial - use SerialPlot to draw graphs 16 | // 17 | // FDC2x1x hardware configuration: 18 | // Component value as in default circuit form datasheet. (18uH inductor and 33pF cap) 19 | // 20 | // SD and ADDR pins tied to GND 21 | // INTB pin not used 22 | // 23 | // ARDUINO <--> FDC 24 | // A4 <-------> SDA 25 | // A5 <-------> SCL 26 | // 27 | // !!!!!! Arduinos are mostly 5V. FDC chips are 3.3V, so either use 3.3V version of Arduino, like pro mini, or use level shifter on I2C bus. 28 | // 29 | 30 | // ### FDC 31 | #include 32 | #include "FDC2214.h" 33 | FDC2214 capsense(FDC2214_I2C_ADDR_0); // Use FDC2214_I2C_ADDR_1 34 | 35 | // ### 36 | void setup() { 37 | 38 | // ### Start I2C 39 | Wire.begin(); 40 | // Wire.setClock(400000L); 41 | 42 | // ### Start serial 43 | Serial.begin(115200); 44 | Serial.println("\nFDC2x1x test"); 45 | 46 | // ### Start FDC 47 | // Start FDC2212 with 2 channels init 48 | // bool capOk = capsense.begin(0x3, 0x4, 0x5, false); //setup first two channels, autoscan with 2 channels, deglitch at 10MHz, external oscillator 49 | // Start FDC2214 with 4 channels init 50 | bool capOk = capsense.begin(0xF, 0x6, 0x5, false); //setup all four channels, autoscan with 4 channels, deglitch at 10MHz, external oscillator 51 | // Start FDC2214 with 4 channels init 52 | // bool capOk = capsense.begin(0xF, 0x6, 0x5, true); //setup all four channels, autoscan with 4 channels, deglitch at 10MHz, internal oscillator 53 | if (capOk) Serial.println("Sensor OK"); 54 | else Serial.println("Sensor Fail"); 55 | 56 | } 57 | 58 | // ### Tell aplication how many chanels will be smapled in main loop 59 | #define CHAN_COUNT 4 60 | 61 | // ### 62 | void loop() { 63 | unsigned long capa[CHAN_COUNT]; // variable to store data from FDC 64 | for (int i = 0; i < CHAN_COUNT; i++){ // for each channel 65 | // ### read 28bit data 66 | capa[i]= capsense.getReading28(i);// 67 | // ### Transmit data to serial in simple format readable by SerialPlot application. 68 | Serial.print(capa[i]); 69 | if (i < CHAN_COUNT-1) Serial.print(", "); 70 | else Serial.println(""); 71 | } 72 | // No point in sleeping 73 | //delay(100); 74 | } 75 | 76 | 77 | -------------------------------------------------------------------------------- /src/FDC2214.h: -------------------------------------------------------------------------------- 1 | // This is a header file for FDC2214 library 2 | // By Harijs Zablockis, Intelitech, March 2018 3 | // This file is heavily based on NelsonsLog_FDC2214.h by Chris Nelson 4 | // Masks and channels added 5 | // 6 | // There is no warranty to the code. There is no support, don't ask for it. 7 | // Use or skip on your own responsibility. 8 | // NOT ALL FEATURES ARE TESTED! 9 | // 10 | // The code might get revisited at some point or it might not. 11 | // The code does more than I need at the moment. 12 | // 13 | // Feel free to do whatever you want with it. No licensing BS. No limitations. 14 | // 15 | 16 | 17 | #ifndef _FDC2214_H_ 18 | #define _FDC2214_H_ 19 | 20 | #if ARDUINO >= 100 21 | #include "Arduino.h" 22 | #define WIRE_WRITE Wire.write 23 | #else 24 | #include "WProgram.h" 25 | #define WIRE_WRITE Wire.send 26 | #endif 27 | 28 | #if defined(__SAM3X8E__) 29 | typedef volatile RwReg PortReg; 30 | typedef uint32_t PortMask; 31 | #define HAVE_PORTREG 32 | #elif defined(ARDUINO_ARCH_SAMD) 33 | // not supported 34 | #elif defined(ESP8266) || defined(ESP32) || defined(ARDUINO_STM32_FEATHER) || defined(__arc__) 35 | typedef volatile uint32_t PortReg; 36 | typedef uint32_t PortMask; 37 | #elif defined(__AVR__) 38 | typedef volatile uint8_t PortReg; 39 | typedef uint8_t PortMask; 40 | #define HAVE_PORTREG 41 | #else 42 | // chances are its 32 bit so assume that 43 | typedef volatile uint32_t PortReg; 44 | typedef uint32_t PortMask; 45 | #endif 46 | 47 | #define FDC2214_I2C_ADDR_0 0x2A 48 | #define FDC2214_I2C_ADDR_1 0x2B 49 | // Address is 0x2A (default) or 0x2B (if ADDR is high) 50 | 51 | //bitmasks 52 | #define FDC2214_CH0_UNREADCONV 0x0008 //denotes unread CH0 reading in STATUS register 53 | #define FDC2214_CH1_UNREADCONV 0x0004 //denotes unread CH1 reading in STATUS register 54 | #define FDC2214_CH2_UNREADCONV 0x0002 //denotes unread CH2 reading in STATUS register 55 | #define FDC2214_CH3_UNREADCONV 0x0001 //denotes unread CH3 reading in STATUS register 56 | 57 | 58 | //registers 59 | #define FDC2214_DEVICE_ID 0x7F 60 | #define FDC2214_MUX_CONFIG 0x1B 61 | #define FDC2214_CONFIG 0x1A 62 | #define FDC2214_RCOUNT_CH0 0x08 63 | #define FDC2214_RCOUNT_CH1 0x09 64 | #define FDC2214_RCOUNT_CH2 0x0A 65 | #define FDC2214_RCOUNT_CH3 0x0B 66 | #define FDC2214_OFFSET_CH0 0x0C 67 | #define FDC2214_OFFSET_CH1 0x0D 68 | #define FDC2214_OFFSET_CH2 0x0E 69 | #define FDC2214_OFFSET_CH3 0x0F 70 | #define FDC2214_SETTLECOUNT_CH0 0x10 71 | #define FDC2214_SETTLECOUNT_CH1 0x11 72 | #define FDC2214_SETTLECOUNT_CH2 0x12 73 | #define FDC2214_SETTLECOUNT_CH3 0x13 74 | #define FDC2214_CLOCK_DIVIDERS_CH0 0x14 75 | #define FDC2214_CLOCK_DIVIDERS_CH1 0x15 76 | #define FDC2214_CLOCK_DIVIDERS_CH2 0x16 77 | #define FDC2214_CLOCK_DIVIDERS_CH3 0x17 78 | #define FDC2214_STATUS 0x18 79 | #define FDC2214_DATA_CH0_MSB 0x00 80 | #define FDC2214_DATA_CH0_LSB 0x01 81 | #define FDC2214_DATA_CH1_MSB 0x02 82 | #define FDC2214_DATA_CH1_LSB 0x03 83 | #define FDC2214_DATA_CH2_MSB 0x04 84 | #define FDC2214_DATA_CH2_LSB 0x05 85 | #define FDC2214_DATA_CH3_MSB 0x06 86 | #define FDC2214_DATA_CH3_LSB 0x07 87 | #define FDC2214_DRIVE_CH0 0x1E 88 | #define FDC2214_DRIVE_CH1 0x1F 89 | #define FDC2214_DRIVE_CH2 0x20 90 | #define FDC2214_DRIVE_CH3 0x21 91 | 92 | // mask for 28bit data to filter out flag bits 93 | #define FDC2214_DATA_CHx_MASK_DATA 0x0FFF 94 | #define FDC2214_DATA_CHx_MASK_ERRAW 0x1000 95 | #define FDC2214_DATA_CHx_MASK_ERRWD 0x2000 96 | 97 | 98 | 99 | class FDC2214 { 100 | public: 101 | FDC2214(uint8_t i2caddr); 102 | //_i2caddr = i2caddr 103 | 104 | boolean begin(uint8_t chanMask, uint8_t autoscanSeq, uint8_t deglitchValue, bool intOsc); 105 | 106 | // double readCapacitance(); 107 | // To be used with FDC2112 and FDC2114 108 | unsigned long getReading16(uint8_t channel); 109 | // To be used with FDC2212 and FDC2214 110 | unsigned long getReading28(uint8_t channel); 111 | 112 | private: 113 | void loadSettings(uint8_t chanMask, uint8_t autoscanSeq, uint8_t deglitchValue, bool intOsc); 114 | // void setGain(void); 115 | // double calculateCapacitance(long long fsensor); 116 | // long long calculateFsensor(unsigned long reading); 117 | void write8FDC(uint16_t address, uint8_t data); 118 | void write16FDC(uint16_t address, uint16_t data); 119 | uint32_t read32FDC(uint16_t address); 120 | uint16_t read16FDC(uint16_t address); 121 | uint8_t read8FDC(uint16_t address); 122 | uint8_t _i2caddr; 123 | }; 124 | 125 | #endif //include guard 126 | -------------------------------------------------------------------------------- /examples/testFDC-Serial-OLED/testFDC-Serial-OLED.ino: -------------------------------------------------------------------------------- 1 | // This is example code to demonstrate the functionality of FDC2214 library 2 | // 3 | // There is no warranty to the code. There is no support, don't ask for it. 4 | // Use or skip on your own responsibility. 5 | // NOT ALL FEATURES ARE TESTED! 6 | // 7 | // The code might get revisited at some point or it might not. 8 | // The code does more than I need at the moment. 9 | // 10 | // Feel free to do whatever you want with it. No licensing BS. No limitations. 11 | // 12 | // Created by Harijs Zablockis, Intelitech, March 2018 13 | // 14 | // Supproted chips: FDC2112, FDC2114, FDC2212, FDC2214 15 | // Uses SSD1306Ascii library to display result on 0.96 inch ebay OLED screen 16 | // Transmitts data via serial - use SerialPlot to draw graphs 17 | // 18 | // FDC2x1x hardware configuration: 19 | // Component value as in default circuit form datasheet. (18uH inductor and 33pF cap) 20 | // 21 | // SD and ADDR pins tied to GND 22 | // INTB pin not used 23 | // 24 | // OLED <--> ARDUINO <--> FDC 25 | // SDA <---> A4 <-------> SDA 26 | // SCL <---> A5 <-------> SCL 27 | // 28 | // !!!!!! Arduinos are mostly 5V. FDC chips are 3.3V, so either use 3.3V version of Arduino, like pro mini, or use level shifter on I2C bus. 29 | // 30 | 31 | // ### OLED. 32 | #include 33 | #include "SSD1306Ascii.h" 34 | #include "SSD1306AsciiWire.h" 35 | #define I2C_ADDRESS 0x3C 36 | #define RST_PIN -1 37 | SSD1306AsciiWire oled; 38 | 39 | // ### FDC 40 | #include "FDC2214.h" 41 | FDC2214 capsense(FDC2214_I2C_ADDR_0); // Use FDC2214_I2C_ADDR_1 42 | unsigned long sensorThreshold[2]; // threshold for proximity detection 43 | 44 | // ### Local function prototypes 45 | int iicScan(); // check for attached devices on I2C bus 46 | 47 | // ### 48 | void setup() { 49 | 50 | // ### Start I2C 51 | Wire.begin(); 52 | // Wire.setClock(400000L); 53 | 54 | // ### Start serial 55 | Serial.begin(115200); 56 | Serial.println("\nI2C Scanner"); 57 | 58 | // ### Start OLED display 59 | oled.begin(&Adafruit128x64, I2C_ADDRESS); 60 | oled.setFont(Adafruit5x7); 61 | oled.clear(); 62 | oled.println("Intelitech "); 63 | int devices = iicScan(); 64 | oled.print(":"); 65 | oled.print(devices); 66 | oled.println("devs"); 67 | 68 | // ### Start FDC 69 | // Start FDC2212 with 2 channels init 70 | // bool capOk = capsense.begin(0x3, 0x4, 0x5, false); //setup first two channels, autoscan with 2 channels, deglitch at 10MHz, external oscillator 71 | // Start FDC2214 with 4 channels init 72 | bool capOk = capsense.begin(0xF, 0x6, 0x5, false); //setup all four channels, autoscan with 4 channels, deglitch at 10MHz, external oscillator 73 | // Start FDC2214 with 4 channels init 74 | // bool capOk = capsense.begin(0xF, 0x6, 0x5, true); //setup all four channels, autoscan with 4 channels, deglitch at 10MHz, internal oscillator 75 | if (capOk) oled.println("Sensor OK"); 76 | else oled.println("Sensor Fail"); 77 | sensorThreshold[0] = 14000000+320000; 78 | sensorThreshold[1] = 320000; 79 | 80 | }; 81 | 82 | // ### Tell aplication how many chanels will be smapled in main loop 83 | #define CHAN_COUNT 4 84 | 85 | // ### 86 | void loop() { 87 | unsigned long capa[CHAN_COUNT]; // variable to store data from FDC 88 | for (int i = 0; i < CHAN_COUNT; i++){ // for each channel 89 | // ### read 28bit data 90 | capa[i]= capsense.getReading28(i); 91 | // ### jump cursor, set font and display channel data on OLED 92 | oled.setCursor(0,4+(2*i)); 93 | oled.set2X(); 94 | oled.print(capa[i]); 95 | oled.print(" "); 96 | oled.set1X(); 97 | // ### Transmit data to serial in simple format readable by SerialPlot application. 98 | Serial.print(capa[i]); 99 | if (i < CHAN_COUNT-1) Serial.print(", "); 100 | else Serial.println(""); 101 | // ### display proximity threshold on OLED 102 | oled.setCursor(110,4+(2*i)); 103 | if (capa[i] < sensorThreshold[i]){ 104 | oled.set2X(); 105 | oled.print("*"); 106 | oled.set1X(); 107 | } else { 108 | oled.set2X(); 109 | oled.print(" "); 110 | oled.set1X(); 111 | } 112 | } 113 | // No point in sleeping 114 | //delay(100); 115 | } 116 | 117 | // 118 | // ### scan for I2C devices. This code fragment comes from I2C scan example. 119 | int iicScan (){ 120 | byte error, address; 121 | int nDevices; 122 | Serial.println("Scanning..."); 123 | nDevices = 0; 124 | for(address = 1; address < 127; address++ ) { 125 | // The i2c_scanner uses the return value of 126 | // the Write.endTransmisstion to see if 127 | // a device did acknowledge to the address. 128 | Wire.beginTransmission(address); 129 | error = Wire.endTransmission(); 130 | // 131 | if (error == 0) { 132 | Serial.print("I2C device found at address 0x"); 133 | if (address<16) Serial.print("0"); 134 | Serial.print(address,HEX); 135 | Serial.println(" !"); 136 | oled.print("0x"); 137 | oled.print(address,HEX); 138 | oled.print(" "); 139 | nDevices++; 140 | } 141 | else if (error==4) { 142 | Serial.print("Unknow error at address 0x"); 143 | if (address<16) 144 | Serial.print("0"); 145 | Serial.println(address,HEX); 146 | } 147 | } 148 | if (nDevices == 0) 149 | Serial.println("No I2C devices found\n"); 150 | else 151 | Serial.println("done\n"); 152 | return nDevices; 153 | } 154 | -------------------------------------------------------------------------------- /src/FDC2214.cpp: -------------------------------------------------------------------------------- 1 | // This is a source file for FDC2214 library 2 | // By Harijs Zablockis, Intelitech, March 2018 3 | // This file is based on NelsonsLog_FDC2214.c by Chris Nelson 4 | // 5 | // The 16 bit output overflow bug is fixed. 6 | // Configuration is made more dynamic and register comments are made readable 7 | // Added other channels 8 | // Added masking out error bits from data 9 | // Some junk code and header form original file left for historical value 10 | // 11 | // There is no warranty to the code. There is no support, don't ask for it. 12 | // Use or skip on your own responsibility. 13 | // NOT ALL FEATURES ARE TESTED! 14 | // 15 | // The code might get revisited at some point or it might not. 16 | // The code does more than I need at the moment. 17 | // 18 | // Feel free to do whatever you want with it. No licensing BS. No limitations. 19 | // 20 | 21 | /**************************************************************************/ 22 | /*! 23 | @file NelsonsLog_FDC2214.cpp 24 | @author Chris Nelson 25 | @license BSD (see license.txt) 26 | 27 | This is a library for an FDC2214 capacitive sensor 28 | ----> http://www.nelsonsloxg.com 29 | 30 | @section HISTORY 31 | 32 | v1.0 - First release 33 | */ 34 | /**************************************************************************/ 35 | 36 | #include "Arduino.h" 37 | #include 38 | #include "FDC2214.h" 39 | 40 | FDC2214::FDC2214(uint8_t i2caddr) { 41 | _i2caddr = i2caddr; 42 | //_i2caddr = FDC2214_I2C_ADDRESS; 43 | } 44 | 45 | // Checking for chip ID, if OK, calls chip init 46 | boolean FDC2214::begin(uint8_t chanMask, uint8_t autoscanSeq, uint8_t deglitchValue, bool intOsc) { 47 | Wire.begin(); 48 | 49 | int devId = read16FDC(FDC2214_DEVICE_ID); 50 | if (devId != 0x3054) { 51 | if (devId != 0x3055) { 52 | //two valid device ids for FDC2214 0x3054 and 0x3055 53 | return false; 54 | } 55 | } 56 | 57 | loadSettings(chanMask, autoscanSeq, deglitchValue, intOsc); 58 | // setGain(); 59 | 60 | return true; 61 | } 62 | 63 | 64 | //Internal routine to do actual chip init 65 | void FDC2214::loadSettings(uint8_t chanMask, uint8_t autoscanSeq, uint8_t deglitchValue, bool intOsc) { 66 | 67 | //Configuration register 68 | // Active channel Select: b00 = ch0; b01 = ch1; b10 = ch2; b11 = ch3; 69 | // |Sleep Mode: 0 - device active; 1 - device in sleep; 70 | // ||Reserved, reserved, set to 1 71 | // |||Sensor Activation Mode: 0 - drive sensor with full current. 1 - drive sensor with current set by DRIVE_CURRENT_CHn 72 | // ||||Reserved, set to 1 73 | // |||||Reference clock: 0 - use internal; 1 - use external clock 74 | // ||||||Reserved, set to 0 75 | // |||||||Disable interrupt. 0 - interrupt output on INTB pin; 1 - no interrupt output 76 | // ||||||||High current sensor mode: 0 - 1.5mA max. 1 - > 1.5mA, not available if Autoscan is enabled 77 | // ||||||||| Reserved, set to 000001 78 | // ||||||||| | 79 | // CCS1A1R0IH000000 -> 0001 1110 1000 0001 -> 0x1E81 ExtOsc 80 | // CCS1A1R0IH000000 -> 0001 1100 1000 0001 -> 0x1C81 IntOsc 81 | if (intOsc) { 82 | write16FDC(FDC2214_CONFIG, 0x1C81); //set config 83 | } else { 84 | write16FDC(FDC2214_CONFIG, 0x1E81); //set config 85 | } 86 | //If channel 1 selected, init it.. 87 | if (chanMask & 0x01) { 88 | 89 | //settle count maximized, slow application 90 | write16FDC(FDC2214_SETTLECOUNT_CH0, 0x64); 91 | 92 | //rcount maximized for highest accuracy 93 | write16FDC(FDC2214_RCOUNT_CH0, 0xFFFF); 94 | 95 | //no offset 96 | write16FDC(FDC2214_OFFSET_CH0, 0x0000); 97 | 98 | // Set clock dividers 99 | // Reserved 100 | // | Sensor Frequency Select. b01 = /1 = sensor freq 0.01 to 8.75MHz; b10 = /2 = sensor freq 0.01 to 10 or 5 to 10 MHz 101 | // | | Reserved 102 | // | | | Reference divider. Must be > 1. fref = fclk / this register` 103 | // | | | | 104 | // 00FF00RRRRRRRRRR -> 0010000000000001 -> 0x2001 105 | write16FDC(FDC2214_CLOCK_DIVIDERS_CH0, 0x2001); 106 | //set drive register 107 | write16FDC(FDC2214_DRIVE_CH0, 0xF800); 108 | } 109 | // Init chan2, if selected by channel init mask 110 | if (chanMask & 0x02) { 111 | write16FDC(FDC2214_SETTLECOUNT_CH1, 0x64); 112 | write16FDC(FDC2214_RCOUNT_CH1, 0xFFFF); 113 | write16FDC(FDC2214_OFFSET_CH1, 0x0000); 114 | write16FDC(FDC2214_CLOCK_DIVIDERS_CH1, 0x2001); 115 | write16FDC(FDC2214_DRIVE_CH1, 0xF800); 116 | } 117 | if (chanMask & 0x04) { 118 | write16FDC(FDC2214_SETTLECOUNT_CH2, 0x64); 119 | write16FDC(FDC2214_RCOUNT_CH2, 0xFFFF); 120 | write16FDC(FDC2214_OFFSET_CH2, 0x0000); 121 | write16FDC(FDC2214_CLOCK_DIVIDERS_CH2, 0x2001); 122 | write16FDC(FDC2214_DRIVE_CH2, 0xF800); 123 | } 124 | if (chanMask & 0x08) { 125 | write16FDC(FDC2214_SETTLECOUNT_CH3, 0x64); 126 | write16FDC(FDC2214_RCOUNT_CH3, 0xFFFF); 127 | write16FDC(FDC2214_OFFSET_CH3, 0x0000); 128 | write16FDC(FDC2214_CLOCK_DIVIDERS_CH3, 0x2001); 129 | write16FDC(FDC2214_DRIVE_CH3, 0xF800); 130 | } 131 | // Autoscan: 0 = single channel, selected by CONFIG.ACTIVE_CHAN 132 | // | Autoscan sequence. b00 for chan 1-2, b01 for chan 1-2-3, b10 for chan 1-2-3-4 133 | // | | Reserved - must be b0001000001 134 | // | | | Deglitch frequency. b001 for 1 MHz, b100 for 3.3 MHz, b101 for 10 Mhz, b111 for 33 MHz 135 | // | | | | 136 | // ARR0001000001DDD -> b0000 0010 0000 1000 -> h0208 137 | uint16_t muxVal = 0x0208 | ((uint16_t)autoscanSeq << 13) | deglitchValue; 138 | // 139 | write16FDC(FDC2214_MUX_CONFIG, muxVal); //set mux config for channels 140 | } 141 | 142 | ///**************************************************************************/ 143 | ///*! 144 | // @brief Given a reading calculates the sensor frequency 145 | //*/ 146 | ///**************************************************************************/ 147 | //long long NelsonsLog_FDC2214::calculateFsensor(unsigned long reading){ 148 | //// Serial.println("reading: "+ String(reading)); 149 | // //fsensor = (CH_FIN_SEL * fref * data) / 2 ^ 28 150 | // //should be mega hz so can truncate to long long 151 | // Serial.println("FDC reading: " + String(reading)); 152 | // unsigned long long temp; 153 | // temp = 1 * 40000000 * reading; 154 | // temp = temp / (2^28); 155 | //// Serial.println("frequency: " + String((long)temp)); 156 | // return temp; 157 | //} 158 | 159 | ///**************************************************************************/ 160 | ///*! 161 | // @brief Given sensor frequency calculates capacitance 162 | //*/ 163 | ///**************************************************************************/ 164 | //double NelsonsLog_FDC2214::calculateCapacitance(long long fsensor){ 165 | // //differential configuration 166 | // //c sensor = 1 - (Cboard + Cparacitic) 167 | // // / (L * (2*pi * fsensor)^2) 168 | // 169 | // double pi = 3.14159265359; 170 | // double L = 18; //uH 171 | // double Cboard = 33; //pf 172 | // double Cparacitic = 3; //pf 173 | // 174 | // double temp = 2 * pi * fsensor; 175 | // temp = temp * temp; 176 | // 177 | // temp = temp / 1000000; //uH 178 | // temp *= L; 179 | // 180 | //// Serial.println("capacitance: " + String(temp)); 181 | // return temp; 182 | // 183 | //} 184 | 185 | 186 | 187 | // Gets 28bit reading for FDC2212 and FDC2214 188 | // Takes in channel number, gives out the formatted 28 bit reading. 189 | unsigned long FDC2214::getReading28(uint8_t channel) { 190 | int timeout = 100; 191 | unsigned long reading = 0; 192 | int status = read16FDC(FDC2214_STATUS); 193 | uint8_t addressMSB; 194 | uint8_t addressLSB; 195 | uint8_t bitUnreadConv; 196 | switch (channel){ 197 | case (0): 198 | addressMSB = FDC2214_DATA_CH0_MSB; 199 | addressLSB = FDC2214_DATA_CH0_LSB; 200 | bitUnreadConv = FDC2214_CH0_UNREADCONV; 201 | break; 202 | case (1): 203 | addressMSB = FDC2214_DATA_CH1_MSB; 204 | addressLSB = FDC2214_DATA_CH1_LSB; 205 | bitUnreadConv = FDC2214_CH1_UNREADCONV; 206 | break; 207 | case (2): 208 | addressMSB = FDC2214_DATA_CH2_MSB; 209 | addressLSB = FDC2214_DATA_CH2_LSB; 210 | bitUnreadConv = FDC2214_CH2_UNREADCONV; 211 | break; 212 | case (3): 213 | addressMSB = FDC2214_DATA_CH3_MSB; 214 | addressLSB = FDC2214_DATA_CH3_LSB; 215 | bitUnreadConv = FDC2214_CH3_UNREADCONV; 216 | break; 217 | default: return 0; 218 | } 219 | 220 | while (timeout && !(status & bitUnreadConv)) { 221 | status = read16FDC(FDC2214_STATUS); 222 | timeout--; 223 | } 224 | if (timeout == 100) { 225 | // ##################################################################################################### 226 | // There was this weird double read, as "first readout could be stale" in Nelsons file. 227 | // I have not confirmed the existence of this silicon bug. 228 | // I suspect that it might be due to crappy breadboard or rats nest wiring or lack of signal integrity for other reason 229 | // 230 | // On the other hand, I have done far too little testing to be sure, so I am leaving that bit in for now. 231 | // 232 | // ##################################################################################################### 233 | //could be stale grab another //could it really it? ????? 234 | //read the 28 bit result 235 | reading = (uint32_t)(read16FDC(addressMSB) & FDC2214_DATA_CHx_MASK_DATA) << 16; 236 | reading |= read16FDC(addressLSB); 237 | while (timeout && !(status & bitUnreadConv)) { 238 | status = read16FDC(FDC2214_STATUS); 239 | timeout--; 240 | } 241 | } 242 | if (timeout) { 243 | //read the 28 bit result 244 | reading = (uint32_t)(read16FDC(addressMSB) & FDC2214_DATA_CHx_MASK_DATA) << 16; 245 | reading |= read16FDC(addressLSB); 246 | return reading; 247 | } else { 248 | // Could not get data, chip readynes flag timeout 249 | return 0; 250 | } 251 | } 252 | 253 | // Gets 16bit reading for FDC2112 and FDC2114 254 | // Takes in channel number, gives out the formatted 28 bit reading. 255 | unsigned long FDC2214::getReading16(uint8_t channel) { 256 | int timeout = 100; 257 | unsigned long reading = 0; 258 | int status = read16FDC(FDC2214_STATUS); 259 | uint8_t addressMSB; 260 | uint8_t bitUnreadConv; 261 | switch (channel){ 262 | case (0): 263 | addressMSB = FDC2214_DATA_CH0_MSB; 264 | bitUnreadConv = FDC2214_CH0_UNREADCONV; 265 | break; 266 | case (1): 267 | addressMSB = FDC2214_DATA_CH1_MSB; 268 | bitUnreadConv = FDC2214_CH1_UNREADCONV; 269 | break; 270 | case (2): 271 | addressMSB = FDC2214_DATA_CH2_MSB; 272 | bitUnreadConv = FDC2214_CH2_UNREADCONV; 273 | break; 274 | case (3): 275 | addressMSB = FDC2214_DATA_CH3_MSB; 276 | bitUnreadConv = FDC2214_CH3_UNREADCONV; 277 | break; 278 | default: return 0; 279 | } 280 | 281 | while (timeout && !(status & bitUnreadConv)) { 282 | status = read16FDC(FDC2214_STATUS); 283 | timeout--; 284 | } 285 | if (timeout == 100) { 286 | // ##################################################################################################### 287 | // There was this weird double read, as "first readout could be stale" in Nelsons file. 288 | // I have not confirmed the existence of this silicon bug. 289 | // I suspect that it might be due to crappy breadboard or rats nest wiring or lack of signal integrity for other reason 290 | // 291 | // On the other hand, I have done far too little testing to be sure, so I am leaving that bit in for now. 292 | // 293 | // ##################################################################################################### 294 | //could be stale grab another //could it really it? ????? 295 | //read the 28 bit result 296 | reading = (uint32_t)(read16FDC(addressMSB) & FDC2214_DATA_CHx_MASK_DATA) << 16; 297 | while (timeout && !(status & bitUnreadConv)) { 298 | status = read16FDC(FDC2214_STATUS); 299 | timeout--; 300 | } 301 | } 302 | if (timeout) { 303 | //read the 16 bit result 304 | reading = (uint32_t)(read16FDC(addressMSB) & FDC2214_DATA_CHx_MASK_DATA) << 16; 305 | return reading; 306 | } else { 307 | // Could not get data, chip readynes flag timeout 308 | return 0; 309 | } 310 | } 311 | 312 | ///**************************************************************************/ 313 | ///*! 314 | // @brief Takes a reading and calculates capacitance from it 315 | //*/ 316 | ///**************************************************************************/ 317 | //double NelsonsLog_FDC2214::readCapacitance() { 318 | // int timeout = 100; 319 | // unsigned long reading = 0; 320 | // long long fsensor = 0; 321 | // int status = read16FDC(FDC2214_STATUS_REGADDR); 322 | // while (timeout && !(status & FDC2214_CH0_UNREADCONV)) { 323 | //// Serial.println("status: " + String(status)); 324 | // status = read16FDC(FDC2214_STATUS_REGADDR); 325 | // timeout--; 326 | // } 327 | // if (timeout) { 328 | // //read the 28 bit result 329 | // reading = read16FDC(FDC2214_DATA_CH0_REGADDR) << 16; 330 | // reading |= read16FDC(FDC2214_DATA_LSB_CH0_REGADDR); 331 | // fsensor = calculateFsensor(reading); 332 | // return calculateCapacitance(fsensor); 333 | // } else { 334 | // //error not reading 335 | // Serial.println("error reading fdc"); 336 | // return 0; 337 | // } 338 | //} 339 | 340 | 341 | /**************************************************************************/ 342 | /*! 343 | @brief Scans various gain settings until the amplitude flag is cleared. 344 | WARNING: Changing the gain setting will generally have an impact on the 345 | reading. 346 | */ 347 | /**************************************************************************/ 348 | //void NelsonsLog_FDC2214::setGain(void) { 349 | // //todo 350 | //} 351 | /**************************************************************************/ 352 | /*! 353 | @brief I2C low level interfacing 354 | */ 355 | /**************************************************************************/ 356 | 357 | // Read 2 bytes from the FDC at 'address' 358 | uint16_t FDC2214::read16FDC(uint16_t address) { 359 | uint16_t data = 0; 360 | 361 | Wire.beginTransmission(_i2caddr); 362 | Wire.write(address); 363 | Wire.endTransmission(false); //restart 364 | 365 | Wire.requestFrom(_i2caddr, (uint8_t) 2); 366 | 367 | if (Wire.available() == 2) { 368 | data = Wire.read(); 369 | data <<= 8; 370 | data |= Wire.read(); 371 | } 372 | 373 | return data; 374 | } 375 | 376 | // write 2 bytes to FDC 377 | void FDC2214::write16FDC(uint16_t address, uint16_t data) { 378 | Wire.beginTransmission(_i2caddr); 379 | Wire.write(address & 0xFF); 380 | Wire.write(data >> 8); 381 | Wire.write(data); 382 | Wire.endTransmission(); 383 | } 384 | --------------------------------------------------------------------------------