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
Revision 0:971d705818e7, committed 2015-08-23
- Comitter:
- Sissors
- Date:
- Sun Aug 23 16:58:36 2015 +0000
- Commit message:
- Initial commit
Changed in this revision
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, ®, 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, ®, 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