Library for Si114x optical sensors. Currently intended for the Si1146, although it will work also for the Si1145, and without full functionality for the Si1147

Dependents:   Si114x_HelloWorld Hello-Uzuki-sensor-shield

Files at this revision

API Documentation at this revision

Comitter:
Sissors
Date:
Sun Aug 23 16:58:36 2015 +0000
Commit message:
Initial commit

Changed in this revision

Si114x.cpp Show annotated file Show diff for this revision Revisions of this file
Si114x.h Show annotated file Show diff for this revision Revisions of this file
Si114x_defs.h Show annotated file Show diff for this revision Revisions of this file
diff -r 000000000000 -r 971d705818e7 Si114x.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Si114x.cpp	Sun Aug 23 16:58:36 2015 +0000
@@ -0,0 +1,149 @@
+#include "Si114x.h"
+#include "Si114x_defs.h"
+
+#define PS_ADC_GAIN     0x02
+
+
+Si114x::Si114x(PinName sda, PinName scl) : i2c(sda,scl) {
+    //Wait startup time and enable the device
+    i2c.frequency(400000);
+    wait_ms(30);       
+    write_byte(REG_MEAS_RATE0, 0x00);
+    write_byte(REG_MEAS_RATE1, 0x00);
+         
+    write_cmd(CMD_RESET);
+    wait_ms(10);
+    write_byte(REG_HW_KEY, 0x17);
+    
+    //Set UV coefficients
+    write_byte(REG_UCOEF0, 0x29);
+    write_byte(REG_UCOEF1, 0x89);
+    write_byte(REG_UCOEF2, 0x02);
+    write_byte(REG_UCOEF3, 0x00);
+    
+    //Set LED current (max, which apparantly is not going to destroy anything)
+    write_byte(REG_PS_LED21, 0xFF);
+    
+    //Set default LED channels
+    setPSLEDs(1, 0x01);
+    setPSLEDs(2, 0x02);
+    
+    continious = false;
+    
+}
+
+bool Si114x::verifyConnection(void) {
+    uint8_t part_id = read_byte(REG_PART_ID);
+    if ((part_id == 0x45) || (part_id == 0x46) || (part_id == 0x47))
+        return true;
+    return false;
+}
+
+//-------------------Get light functions---------------------------
+
+unsigned short Si114x::getVisibleLight(void) {
+    if (continious == false) {
+        //Enable visible light measurement, clear current interrupt, start conversion, wait until done
+        write_byte(REG_IRQ_STATUS, 0x01);
+        param_set(RAM_CHLIST, (1<<4));
+        write_cmd(CMD_ALS_FORCE);
+        while(read_byte(REG_IRQ_STATUS) & 0x01 != 0x01);
+    }
+    return read_word(REG_ALS_VIS_DATA0);
+}
+
+unsigned short Si114x::getIRLight(void) {
+    if (continious == false) {
+        //Enable IR light measurement, clear current interrupt, start conversion, wait until done
+        write_byte(REG_IRQ_STATUS, 0x01);
+        param_set(RAM_CHLIST, (1<<5));
+        write_cmd(CMD_ALS_FORCE);
+        while(read_byte(REG_IRQ_STATUS) & 0x01 != 0x01);
+    }
+    return read_word(REG_ALS_IR_DATA0);
+}
+
+unsigned short Si114x::getUVIndex(void) {
+    if (continious == false) {
+        //Enable IR light measurement, clear current interrupt, start conversion, wait until done
+        write_byte(REG_IRQ_STATUS, 0x01);
+        param_set(RAM_CHLIST, (1<<7));
+        write_cmd(CMD_ALS_FORCE);
+        while(read_byte(REG_IRQ_STATUS) & 0x01 != 0x01);
+    }
+    return read_word(REG_UV_INDEX0);
+}
+
+//---------------------------------- Proximity -----------------------------------------------------
+unsigned short Si114x::getProximity(char pschannel) {
+    if (continious == false) {
+        //Enable IR light measurement, clear current interrupt, start conversion, wait until done
+        write_byte(REG_IRQ_STATUS, 0x04);
+        param_set(RAM_CHLIST, (1<<(pschannel-1)));
+        write_cmd(CMD_PS_FORCE);
+        while(read_byte(REG_IRQ_STATUS) & 0x04 != 0x04);
+    }
+    return read_word(REG_PS1_DATA0 + (pschannel - 1)* 2);
+}
+
+void Si114x::setPSLEDs(char pschannel, char ledmask) {
+    char psled12 = param_query(RAM_PSLED12_SELECT);
+    if (pschannel == 1) {
+        psled12 = (psled12 & ~0x0F) | ledmask;
+    } 
+    else {
+        psled12 = (psled12 & ~0xF0) | (ledmask << 4);
+    }
+    param_set(RAM_PSLED12_SELECT, psled12);
+}
+        
+
+//---------------------------------- Read/Write functions ---------------------------------------------
+    
+char Si114x::read_byte(const char reg) {
+    char retval;
+    i2c.write(SI114x_ADDRESS, &reg, 1, true);
+    i2c.read(SI114x_ADDRESS, &retval, 1);
+    return retval;
+}
+
+unsigned short Si114x::read_word(const char reg) {
+    unsigned short retval;
+    i2c.write(SI114x_ADDRESS, &reg, 1, true);
+    i2c.read(SI114x_ADDRESS, (char*)&retval, 2);    //This actually seems to put them in correct order
+    return retval;
+}
+
+void Si114x::write_byte(const char reg, const char byte) {
+    char data[] = {reg, byte};
+    i2c.write(SI114x_ADDRESS, data, 2);
+}
+
+void Si114x::param_set(const char param, const char value) {
+    write_byte(REG_PARAM_WR, value);
+    write_cmd(CMD_PARAM_SET | param);
+}
+
+char Si114x::param_query(const char param) {
+    write_cmd(CMD_PARAM_QUERY | param);
+    return read_byte(REG_PARAM_RD);
+}
+
+void Si114x::write_cmd(const char cmd) {
+    uint8_t old_value = read_byte(REG_RESPONSE);
+    
+    write_byte(REG_COMMAND, cmd);
+    
+    if (cmd == CMD_RESET) {
+        return;    
+    }
+    
+    char i = 0;
+    while(read_byte(REG_RESPONSE) == old_value) {
+        wait_ms(1);
+        if (i > 25) {
+            break;
+        }
+        i++;
+    }
+}
\ No newline at end of file
diff -r 000000000000 -r 971d705818e7 Si114x.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Si114x.h	Sun Aug 23 16:58:36 2015 +0000
@@ -0,0 +1,97 @@
+#ifndef SI114X_H
+#define SI114X_H
+
+
+#include "mbed.h"
+/*
+ * Class to interface with Si114x sensors
+ *
+ * Currently only intended for Si1146. Should work also on the Si1145,
+ * but the extra LED of the Si1147 is not supported. Everyone is welcome
+ * to add this support and submit a pull request.
+ *
+ * Aditionally only synchronous mode is for now supported (no async I2C API is used
+ * and the sensor is not placed in automatic measurement mode: Each request starts a new
+ * measurement. Also for this and other issues: Everyone is welcome to submit
+ * pull requests
+ *
+ * For now this is just returning raw values, no scaling is done by the library code
+*/
+class Si114x {
+    public:
+    /* Constructor to create new Si114x instance
+    *
+    * @param sda SDA pin of the I2C interface
+    * @param scl SCL pin of the I2C interface
+    */
+    Si114x(PinName sda, PinName scl);
+    
+    /* Get the measure visible light intensity
+    *
+    * @return unsigned short (uint16_t) representing visible light intensity
+    */
+    unsigned short getVisibleLight(void);
+    
+    /* Get the measure IR light intensity
+    *
+    * @return unsigned short (uint16_t) representing IR light intensity
+    */
+    unsigned short getIRLight(void);
+    
+    /* Get the measure UV intensity
+    *
+    * The retval is supposed to be 10 times the UV index. It will be modified
+    * to return a float representing the UV index once it doesn't claim
+    * the UV index is 50 outside. 
+    *
+    * @return unsigned short (uint16_t) representing UV intensity
+    */
+    unsigned short getUVIndex(void);
+    
+    /* Perform a proximity measurement
+    *
+    * This enabled LEDs (set using setPSLEDs) and performs a 
+    * reflection measurement. It can be used to obtain (relative)
+    * proximity, but also to measure for example heartbeat, as in 
+    * the HelloWorld program.
+    *
+    * Currently the code does not substract ambient light (todo)
+    *
+    * @param pschannel channel to use for the measurement (1-2)
+    * @return unsigned short (uint16_t) representing the reflection
+    */
+    unsigned short getProximity(char pschannel);
+    
+    /* Set the LEDs for a given proximity measurement
+    *
+    * The Si1146 has two channels to do measurements with and can control 2 LEDs.
+    * This function is used to set which LEDs are used for which channel.
+    * Multiple LEDs can be active at the same time. By default the
+    * constructor sets LED1 to be active with channel 1 and LED2 to
+    * be active with channel 2.
+    *
+    * @param pschannel channel to set active LEDs for (1-2)
+    * @param ledmask LEDs to be active for the set channel (bit 0 is LED1, bit1 is LED2)
+    */
+    void setPSLEDs(char pschannel, char ledmask);
+    
+    /* Verify I2C communication can occur with the sensor
+    *
+    * @return true when the sensor is found
+    */
+    bool verifyConnection(void);
+    
+    protected:
+    char read_byte(const char reg);
+    unsigned short read_word(const char reg);
+    void write_byte(const char reg, const char byte);
+    void param_set(const char param, const char value);
+    char param_query(const char param);
+    void write_cmd(const char cmd);
+    
+    I2C i2c;
+    
+    bool continious;
+    };
+
+#endif
\ No newline at end of file
diff -r 000000000000 -r 971d705818e7 Si114x_defs.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Si114x_defs.h	Sun Aug 23 16:58:36 2015 +0000
@@ -0,0 +1,76 @@
+#ifndef SI114X_DEFS_H
+#define SI114X_DEFS_H
+
+
+#define SI114x_ADDRESS (0x60 << 1)
+
+enum Si114x_reg { 
+    REG_PART_ID = 0x00,
+    REG_REV_ID,
+    REG_SEQ_ID,
+    REG_INT_CFG,
+    REG_IRQ_ENABLE,
+    REG_HW_KEY = 0x07,
+    REG_MEAS_RATE0, REG_MEAS_RATE1,
+    REG_PS_LED21 = 0x0F, REG_PS_LED3,
+    REG_UCOEF0 = 0x13, REG_UCOEF1, REG_UCOEF2, REG_UCOEF3,
+    REG_PARAM_WR,
+    REG_COMMAND,
+    REG_RESPONSE = 0x20,
+    REG_IRQ_STATUS,
+    REG_ALS_VIS_DATA0, REG_ALS_VIS_DATA1,
+    REG_ALS_IR_DATA0, REG_ALS_IR_DATA1,
+    REG_PS1_DATA0, REG_PS1_DATA1,
+    REG_PS2_DATA0, REG_PS2_DATA1,
+    REG_PS3_DATA0 = 0x2A, REG_PS3_DATA1,
+    REG_UV_INDEX0, REG_UV_INDEX1,
+    REG_PARAM_RD,
+    REG_CHIP_STAT = 0x30,
+    REG_ANA_IN_KEY = 0x3B
+    };
+
+enum Si114x_commands {
+    CMD_PARAM_QUERY = 0x80,
+    CMD_PARAM_SET = 0xA0,
+    CMD_NOP = 0x00,
+    CMD_RESET = 0x01,
+    CMD_BUS_ADDRESS = 0x02,
+    CMD_PS_FORCE = 0x05,
+    CMD_GET_CAL = 0x12,
+    CMD_ALS_FORCE = 0x06,
+    CMD_PLSALS_FORCE = 0x07,
+    CMD_PS_AUTO = 0x0D,
+    CMD_ALS_AUTO = 0x0E,
+    CMD_PSALS_AUTO = 0x0F
+};
+
+enum Si114x_ram_address {
+    RAM_I2C_ADDR,
+    RAM_CHLIST,
+    RAM_PSLED12_SELECT,
+    RAM_PSLED3_SELECT,
+    RAM_PS_ENCODING,
+    RAM_ALS_ENCODING,
+    RAM_PS1_ADCMUX,
+    RAM_PS2_ADCMUX,
+    RAM_PS3_ADCMUX,
+    RAM_PS_ADC_COUNTER,
+    RAM_PS_ADC_GAIN,
+    RAM_PS_ADC_MISC,
+    RAM_RESERVED0,
+    RAM_ALS_IR_ADCMUX,
+    RAM_AUX_ADCMUX,
+    RAM_ALS_VIS_ADC_COUNTER,
+    RAM_ALS_VIS_ADC_GAIN,
+    RAM_ALS_VIS_ADC_MISC,
+    RAM_RESERVED1,
+    RAM_RESERVED2,
+    RAM_RESERVED3,
+    RAM_LED_REC,
+    RAM_IR_ADC_COUNTER,
+    RAM_IR_ADC_GAIN,
+    RAM_IR_ADC_MISC
+};
+    
+    
+#endif
\ No newline at end of file