SI1133 light sensor

Files at this revision

API Documentation at this revision

Comitter:
brunnobbco
Date:
Wed Nov 06 20:10:47 2019 +0000
Commit message:
Light sensor to NRF52840

Changed in this revision

Si1133.cpp Show annotated file Show diff for this revision Revisions of this file
Si1133.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed_app.json Show annotated file Show diff for this revision Revisions of this file
mbed_coragem.lib Show annotated file Show diff for this revision Revisions of this file
diff -r 000000000000 -r fe6c4edd0ecc Si1133.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Si1133.cpp	Wed Nov 06 20:10:47 2019 +0000
@@ -0,0 +1,913 @@
+/***************************************************************************//**
+ * @file Si1133.cpp
+ *******************************************************************************
+ * @section License
+ * <b>(C) Copyright 2017 Silicon Labs, http://www.silabs.com</b>
+ *******************************************************************************
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include "Si1133.h"
+
+#define SI1133_I2C_ADDRESS (0xAA) /** Hardcoded address for Si1133 sensor */
+
+/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
+
+#define X_ORDER_MASK            0x0070
+#define Y_ORDER_MASK            0x0007
+#define SIGN_MASK               0x0080
+#define GET_X_ORDER(m)          ( ((m) & X_ORDER_MASK) >> 4)
+#define GET_Y_ORDER(m)          ( ((m) & Y_ORDER_MASK) )
+#define GET_SIGN(m)             ( ((m) & SIGN_MASK) >> 7)
+
+#define UV_INPUT_FRACTION       15
+#define UV_OUTPUT_FRACTION      12
+#define UV_NUMCOEFF             2
+
+#define ADC_THRESHOLD           16000
+#define INPUT_FRACTION_HIGH     7
+#define INPUT_FRACTION_LOW      15
+#define LUX_OUTPUT_FRACTION     12
+#define NUMCOEFF_LOW            9
+#define NUMCOEFF_HIGH           4
+
+/** @endcond */
+
+/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
+/***************************************************************************//**
+ * @brief
+ *    Coefficients for lux calculation
+ ******************************************************************************/
+const Si1133::LuxCoeff_t Si1133::lk = {
+    {   {     0, 209 },           /**< coeff_high[0]   */
+        {  1665, 93  },           /**< coeff_high[1]   */
+        {  2064, 65  },           /**< coeff_high[2]   */
+        { -2671, 234 } },         /**< coeff_high[3]   */
+    {   {     0, 0   },           /**< coeff_low[0]    */
+        {  1921, 29053 },         /**< coeff_low[1]    */
+        { -1022, 36363 },         /**< coeff_low[2]    */
+        {  2320, 20789 },         /**< coeff_low[3]    */
+        {  -367, 57909 },         /**< coeff_low[4]    */
+        { -1774, 38240 },         /**< coeff_low[5]    */
+        {  -608, 46775 },         /**< coeff_low[6]    */
+        { -1503, 51831 },         /**< coeff_low[7]    */
+        { -1886, 58928 } }        /**< coeff_low[8]    */
+};
+
+/***************************************************************************//**
+ * @brief
+ *    Coefficients for UV index calculation
+ ******************************************************************************/
+const Si1133::Coeff_t Si1133::uk[2] = {
+    { 1281, 30902 },            /**< coeff[0]        */
+    { -638, 46301 }             /**< coeff[1]        */
+};
+
+/**************************************************************************//**
+* @name Error Codes
+* @{
+******************************************************************************/
+#define SI1133_OK                            0x0000   /**< No errors                  */
+#define SI1133_ERROR_I2C_TRANSACTION_FAILED  0x0001   /**< I2C transaction failed     */
+#define SI1133_ERROR_SLEEP_FAILED            0x0002   /**< Entering sleep mode failed */
+/**@}*/
+
+/** @endcond */
+
+Si1133::Si1133(PinName sda, PinName scl, int hz) : m_I2C(sda, scl)
+{
+    //Set the I2C bus frequency
+    m_I2C.frequency(hz);
+}
+
+Si1133::~Si1133(void)
+{
+    deinit();
+}
+
+bool Si1133::open()
+{
+    //Probe for the Si1133 using a Zero Length Transfer
+    if (m_I2C.write(SI1133_I2C_ADDRESS, NULL, 0)) {
+        //Return success
+        return false;
+    }
+
+    // initialize sensor
+    if (SI1133_OK == init()) {
+        return true;
+    }
+    return false;
+}
+
+/** Measure the current light level (in lux) on the Si1133
+ *
+ * @returns The current temperature measurement in Lux.
+ */
+float Si1133::get_light_level()
+{
+    float lux, uvi;
+    measure_lux_uv(&lux, &uvi);
+    return lux;
+}
+
+/** Measure the current UV Index on the Si1133
+ *
+ * @returns The current UV index.
+ */
+float Si1133::get_uv_index()
+{
+    float lux, uvi;
+    measure_lux_uv(&lux, &uvi);
+    return uvi;
+}
+
+bool Si1133::get_light_and_uv(float *light_level, float *uv_index)
+{
+    if(measure_lux_uv(light_level, uv_index)) {
+        return false;
+    }
+    return true;
+}
+
+/***************************************************************************//**
+ * @brief
+ *    Reads register from the Si1133 sensor
+ *
+ * @param[in] reg
+ *    The register address to read from in the sensor.
+ *
+ * @param[out] data
+ *    The data read from the sensor
+ *
+ * @return
+ *    Returns zero on OK, non-zero otherwise
+ ******************************************************************************/
+uint32_t Si1133::read_register(enum Si1133::Register reg, uint8_t *data)
+{
+    char buf[1];
+    buf[0] = (char) reg;
+
+    if (m_I2C.write(SI1133_I2C_ADDRESS, buf, 1, true)) {
+        //Return failure
+        return SI1133_ERROR_I2C_TRANSACTION_FAILED;
+    }
+
+    if (m_I2C.read(SI1133_I2C_ADDRESS, buf, 1)) {
+        //Return failure
+        return SI1133_ERROR_I2C_TRANSACTION_FAILED;
+    }
+
+    *data = buf[0];
+
+    return SI1133_OK;
+}
+
+/***************************************************************************//**
+ * @brief
+ *    Writes register in the Si1133 sensor
+ *
+ * @param[in] reg
+ *    The register address to write to in the sensor
+ *
+ * @param[in] data
+ *    The data to write to the sensor
+ *
+ * @return
+ *    Returns zero on OK, non-zero otherwise
+ ******************************************************************************/
+uint32_t Si1133::write_register(enum Si1133::Register reg, uint8_t data)
+{
+    char buf[2];
+    buf[0] = (char) reg;
+    buf[1] = (char) data;
+
+    if (m_I2C.write(SI1133_I2C_ADDRESS, buf, 2)) {
+        //Return failure
+        return SI1133_ERROR_I2C_TRANSACTION_FAILED;
+    }
+
+    return SI1133_OK;
+}
+
+/***************************************************************************//**
+ * @brief
+ *    Writes a block of data to the Si1133 sensor.
+ *
+ * @param[in] reg
+ *    The first register to begin writing to
+ *
+ * @param[in] length
+ *    The number of bytes to write to the sensor
+ *
+ * @param[in] data
+ *    The data to write to the sensor
+ *
+ * @return
+ *    Returns zero on OK, non-zero otherwise
+ ******************************************************************************/
+uint32_t Si1133::write_register_block(enum Si1133::Register reg, uint8_t length, uint8_t *data)
+{
+    char buf[3];
+    buf[0] = (char)reg;
+
+    if (length > 2) {
+        return SI1133_ERROR_I2C_TRANSACTION_FAILED;
+    }
+
+    memcpy(&buf[1], data, length);
+
+    if (m_I2C.write(SI1133_I2C_ADDRESS, buf, length + 1)) {
+        //Return failure
+        return SI1133_ERROR_I2C_TRANSACTION_FAILED;
+    }
+
+    return SI1133_OK;
+}
+
+/***************************************************************************//**
+ * @brief
+ *    Reads a block of data from the Si1133 sensor.
+ *
+ * @param[in] reg
+ *    The first register to begin reading from
+ *
+ * @param[in] length
+ *    The number of bytes to write to the sensor
+ *
+ * @param[out] data
+ *    The data read from the sensor
+ *
+ * @return
+ *    Returns zero on OK, non-zero otherwise
+ ******************************************************************************/
+uint32_t Si1133::read_register_block(enum Si1133::Register reg, uint8_t length, uint8_t *data)
+{
+    char reg_c = (char)reg;
+    if (m_I2C.write(SI1133_I2C_ADDRESS, &reg_c, 1, true)) {
+        //Return failure
+        return SI1133_ERROR_I2C_TRANSACTION_FAILED;
+    }
+
+    if (m_I2C.read(SI1133_I2C_ADDRESS, (char*) data, length)) {
+        //Return failure
+        return SI1133_ERROR_I2C_TRANSACTION_FAILED;
+    }
+
+    return SI1133_OK;
+}
+
+/***************************************************************************//**
+ * @brief
+ *    Reads the interrupt status register of the device
+ *
+ * @param[out] irqStatus
+ *    The contentof the IRQ status register
+ *
+ * @return
+ *    Returns zero on OK, non-zero otherwise
+ ******************************************************************************/
+uint32_t Si1133::get_irq_status(uint8_t *irq_status)
+{
+    return read_register(REG_IRQ_STATUS, irq_status);
+}
+
+/***************************************************************************//**
+ * @brief
+ *    Waits until the Si1133 is sleeping before proceeding
+ *
+ * @return
+ *    Returns zero on OK, non-zero otherwise
+ ******************************************************************************/
+uint32_t Si1133::wait_until_sleep(void)
+{
+  uint32_t ret;
+  uint8_t response;
+  size_t count = 0;
+
+  /* This loops until the Si1133 is known to be in its sleep state  */
+  /* or if an i2c error occurs                                      */
+  while ( count < 5 ) {
+    ret = read_register(REG_RESPONSE0, &response);
+    if ( (response & (uint8_t)RSP0_CHIPSTAT_MASK) == (uint8_t)RSP0_SLEEP ) {
+      return SI1133_OK;
+    }
+
+    if ( ret != SI1133_OK ) {
+      return SI1133_ERROR_SLEEP_FAILED;
+    }
+
+    count++;
+  }
+
+  return SI1133_ERROR_SLEEP_FAILED;
+}
+
+/***************************************************************************//**
+ * @brief
+ *    Resets the Si1133
+ *
+ * @return
+ *    Returns zero on OK, non-zero otherwise
+ ******************************************************************************/
+uint32_t Si1133::reset(void)
+{
+    uint32_t retval;
+
+    /* Do not access the Si1133 earlier than 25 ms from power-up */
+    wait_ms(30);
+
+    /* Perform the Reset Command */
+    retval = write_register(REG_COMMAND, (uint8_t)CMD_RESET);
+
+    /* Delay for 10 ms. This delay is needed to allow the Si1133   */
+    /* to perform internal reset sequence.                         */
+    wait_ms(10);
+
+    return retval;
+}
+
+/***************************************************************************//**
+ * @brief
+ *    Helper function to send a command to the Si1133
+ *
+ * @param[in] command
+ *    The command to send to the sensor
+ *
+ * @return
+ *    Returns zero on OK, non-zero otherwise
+ ******************************************************************************/
+uint32_t Si1133::send_cmd(enum Si1133::Command command)
+{
+    uint8_t response;
+    uint8_t response_stored;
+    uint8_t count = 0;
+    uint32_t ret;
+
+    /* Get the response register contents */
+    ret = read_register(REG_RESPONSE0, &response_stored);
+    if ( ret != SI1133_OK ) {
+        return ret;
+    }
+
+    response_stored = response_stored & (uint8_t)RSP0_COUNTER_MASK;
+
+    /* Double-check the response register is consistent */
+    while ( count < 5 ) {
+        ret = wait_until_sleep();
+        if ( ret != SI1133_OK ) {
+            return ret;
+        }
+        /* Skip if the command is RESET COMMAND COUNTER */
+        if ( command == (uint8_t)CMD_RESET_CMD_CTR ) {
+            break;
+        }
+
+        ret = read_register(REG_RESPONSE0, &response);
+
+        if ( (response & (uint8_t)RSP0_COUNTER_MASK) == response_stored ) {
+            break;
+        } else {
+            if ( ret != SI1133_OK ) {
+                return ret;
+            } else {
+                response_stored = response & (uint8_t)RSP0_COUNTER_MASK;
+            }
+        }
+
+        count++;
+    }
+
+    /* Send the command */
+    ret = write_register(REG_COMMAND, command);
+    if ( ret != SI1133_OK ) {
+        return ret;
+    }
+
+    count = 0;
+    /* Expect a change in the response register */
+    while ( count < 5 ) {
+        /* Skip if the command is RESET COMMAND COUNTER */
+        if ( command == (uint8_t)CMD_RESET_CMD_CTR ) {
+            break;
+        }
+
+        ret = read_register(REG_RESPONSE0, &response);
+        if ( (response & (uint8_t)RSP0_COUNTER_MASK) != response_stored ) {
+            break;
+        } else {
+            if ( ret != SI1133_OK ) {
+                return ret;
+            }
+        }
+
+        count++;
+    }
+
+    return SI1133_OK;
+}
+
+/***************************************************************************//**
+ * @brief
+ *    Sends a RESET COMMAND COUNTER command to the Si1133
+ *
+ * @return
+ *    Returns zero on OK, non-zero otherwise
+ ******************************************************************************/
+uint32_t Si1133::reset_cmd_counter(void)
+{
+  return send_cmd(CMD_RESET_CMD_CTR);
+}
+
+/***************************************************************************//**
+ * @brief
+ *    Sends a FORCE command to the Si1133
+ *
+ * @return
+ *    Returns zero on OK, non-zero otherwise
+ ******************************************************************************/
+uint32_t Si1133::force_measurement(void)
+{
+  return send_cmd(CMD_FORCE_CH);
+}
+
+/***************************************************************************//**
+ * @brief
+ *    Sends a START command to the Si1133
+ *
+ * @return
+ *    Returns zero on OK, non-zero otherwise
+ ******************************************************************************/
+uint32_t Si1133::start_measurement(void)
+{
+  return send_cmd(CMD_START);
+}
+
+/***************************************************************************//**
+ * @brief
+ *    Sends a PAUSE command to the Si1133
+ *
+ * @return
+ *    Returns zero on OK, non-zero otherwise
+ ******************************************************************************/
+uint32_t Si1133::pause_measurement(void)
+{
+  return send_cmd(CMD_PAUSE_CH);
+}
+
+/***************************************************************************//**
+ * @brief
+ *    Writes a byte to an Si1133 Parameter
+ *
+ * @param[in] address
+ *    The parameter address
+ *
+ * @param[in] value
+ *    The byte value to be written to the Si1133 parameter
+ *
+ * @return
+ *    Returns zero on OK, non-zero otherwise
+ *
+ * @note
+ *    This function ensures that the Si1133 is idle and ready to
+ *    receive a command before writing the parameter. Furthermore,
+ *    command completion is checked. If setting parameter is not done
+ *    properly, no measurements will occur. This is the most common
+ *    error. It is highly recommended that host code make use of this
+ *    function.
+ ******************************************************************************/
+uint32_t Si1133::set_parameter (enum Si1133::Parameter address, uint8_t value)
+{
+    uint32_t retval;
+    uint8_t buffer[2];
+    uint8_t response_stored;
+    uint8_t response;
+    size_t count;
+
+    retval = wait_until_sleep();
+    if ( retval != SI1133_OK ) {
+        return retval;
+    }
+
+    read_register(REG_RESPONSE0, &response_stored);
+    response_stored &= (uint8_t)RSP0_COUNTER_MASK;
+
+    buffer[0] = value;
+    buffer[1] = 0x80 + ((uint8_t)address & 0x3F);
+
+    retval = write_register_block(REG_HOSTIN0, 2, (uint8_t*) buffer);
+    if ( retval != SI1133_OK ) {
+        return retval;
+    }
+
+    /* Wait for command to finish */
+    count = 0;
+    /* Expect a change in the response register */
+    while ( count < 5 ) {
+        retval = read_register(REG_RESPONSE0, &response);
+        if ( (response & (uint8_t)RSP0_COUNTER_MASK) != response_stored ) {
+            break;
+        } else {
+            if ( retval != SI1133_OK ) {
+                return retval;
+            }
+        }
+
+        count++;
+    }
+
+    if (count >= 5) {
+        return SI1133_ERROR_I2C_TRANSACTION_FAILED;
+    }
+
+    return SI1133_OK;
+}
+
+/***************************************************************************//**
+ * @brief
+ *    Reads a parameter from the Si1133
+ *
+ * @param[in] address
+ *    The address of the parameter.
+ *
+ * @return
+ *    Returns zero on OK, non-zero otherwise
+ ******************************************************************************/
+uint32_t Si1133::read_parameter (enum Si1133::Parameter address)
+{
+    uint8_t retval;
+    uint8_t cmd;
+
+    cmd = 0x40 + ((uint8_t)address & 0x3F);
+
+    retval = send_cmd((enum Si1133::Command)cmd);
+    if ( retval != SI1133_OK ) {
+        return retval;
+    }
+
+    read_register(REG_RESPONSE1, &retval);
+
+    return retval;
+}
+
+/**************************************************************************//**
+ * @brief
+ *    Initializes the Si1133 chip
+ *
+ * @return
+ *    Returns zero on OK, non-zero otherwise
+ *****************************************************************************/
+uint32_t Si1133::init (void)
+{
+    uint32_t retval;
+
+    /* Allow some time for the part to power up */
+    wait_ms(5);
+
+    retval = reset();
+
+    wait_ms(10);
+
+    retval += set_parameter(PARAM_CH_LIST, 0x0f);
+    retval += set_parameter(PARAM_ADCCONFIG0, 0x78);
+    retval += set_parameter(PARAM_ADCSENS0, 0x71);
+    retval += set_parameter(PARAM_ADCPOST0, 0x40);
+    retval += set_parameter(PARAM_ADCCONFIG1, 0x4d);
+    retval += set_parameter(PARAM_ADCSENS1, 0xe1);
+    retval += set_parameter(PARAM_ADCPOST1, 0x40);
+    retval += set_parameter(PARAM_ADCCONFIG2, 0x41);
+    retval += set_parameter(PARAM_ADCSENS2, 0xe1);
+    retval += set_parameter(PARAM_ADCPOST2, 0x50);
+    retval += set_parameter(PARAM_ADCCONFIG3, 0x4d);
+    retval += set_parameter(PARAM_ADCSENS3, 0x87);
+    retval += set_parameter(PARAM_ADCPOST3, 0x40);
+
+    retval += write_register(REG_IRQ_ENABLE, 0x0f);
+
+    return retval;
+}
+
+/***************************************************************************//**
+ * @brief
+ *    Stops the measurements on all channel and waits until the chip
+ *    goes to sleep state.
+ *
+ * @return
+ *    Returns zero on OK, non-zero otherwise
+ ******************************************************************************/
+uint32_t Si1133::deinit (void)
+{
+    uint32_t retval;
+
+    retval = set_parameter(PARAM_CH_LIST, 0x3f);
+    retval += pause_measurement();
+    retval += wait_until_sleep();
+
+    return retval;
+}
+
+/***************************************************************************//**
+ * @brief
+ *    Read samples from the Si1133 chip
+ *
+ * @param[out] samples
+ *    Retrieves interrupt status and measurement data for channel 0..3 and
+ *    converts the data to int32_t format
+ *
+ * @return
+ *    Returns zero on OK, non-zero otherwise
+ ******************************************************************************/
+uint32_t Si1133::measure (Si1133::Samples_t *samples)
+{
+    uint8_t buffer[13];
+    uint32_t retval;
+
+    retval = read_register_block(REG_IRQ_STATUS, 13, buffer);
+
+    samples->irq_status = buffer[0];
+
+    samples->ch0 = buffer[1] << 16;
+    samples->ch0 |= buffer[2] << 8;
+    samples->ch0 |= buffer[3];
+    if ( samples->ch0 & 0x800000 ) {
+        samples->ch0 |= 0xFF000000;
+    }
+
+    samples->ch1 = buffer[4] << 16;
+    samples->ch1 |= buffer[5] << 8;
+    samples->ch1 |= buffer[6];
+    if ( samples->ch1 & 0x800000 ) {
+        samples->ch1 |= 0xFF000000;
+    }
+
+    samples->ch2 = buffer[7] << 16;
+    samples->ch2 |= buffer[8] << 8;
+    samples->ch2 |= buffer[9];
+    if ( samples->ch2 & 0x800000 ) {
+        samples->ch2 |= 0xFF000000;
+    }
+
+    samples->ch3 = buffer[10] << 16;
+    samples->ch3 |= buffer[11] << 8;
+    samples->ch3 |= buffer[12];
+    if ( samples->ch3 & 0x800000 ) {
+        samples->ch3 |= 0xFF000000;
+    }
+
+    return retval;
+}
+
+int32_t Si1133::calculate_polynomial_helper (int32_t input, int8_t fraction, uint16_t mag, int8_t shift)
+{
+    int32_t value;
+
+    if ( shift < 0 ) {
+        value = ( (input << fraction) / mag) >> -shift;
+    } else {
+        value = ( (input << fraction) / mag) << shift;
+    }
+
+    return value;
+}
+
+int32_t Si1133::calculate_polynomial (int32_t x, int32_t y, uint8_t input_fraction, uint8_t output_fraction, uint8_t num_coeff, const Si1133::Coeff_t *kp)
+{
+    uint8_t info, x_order, y_order, counter;
+    int8_t sign, shift;
+    uint16_t mag;
+    int32_t output = 0, x1, x2, y1, y2;
+
+    for ( counter = 0; counter < num_coeff; counter++ ) {
+        info = kp->info;
+        x_order = GET_X_ORDER(info);
+        y_order = GET_Y_ORDER(info);
+
+        shift = ( (uint16_t) kp->info & 0xff00) >> 8;
+        shift ^= 0x00ff;
+        shift += 1;
+        shift = -shift;
+
+        mag = kp->mag;
+
+        if ( GET_SIGN(info) ) {
+            sign = -1;
+        } else {
+            sign = 1;
+        }
+
+        if ( (x_order == 0) && (y_order == 0) ) {
+            output += sign * mag << output_fraction;
+        } else {
+            if ( x_order > 0 ) {
+                x1 = calculate_polynomial_helper(x, input_fraction, mag, shift);
+                if ( x_order > 1 ) {
+                    x2 = calculate_polynomial_helper(x, input_fraction, mag, shift);
+                } else {
+                    x2 = 1;
+                }
+            } else {
+                x1 = 1;
+                x2 = 1;
+            }
+
+            if ( y_order > 0 ) {
+                y1 = calculate_polynomial_helper(y, input_fraction, mag, shift);
+                if ( y_order > 1 ) {
+                    y2 = calculate_polynomial_helper(y, input_fraction, mag, shift);
+                } else {
+                    y2 = 1;
+                }
+            } else {
+                y1 = 1;
+                y2 = 1;
+            }
+
+            output += sign * x1 * x2 * y1 * y2;
+        }
+
+        kp++;
+    }
+
+    if ( output < 0 ) {
+        output = -output;
+    }
+
+    return output;
+}
+
+/***************************************************************************//**
+ * @brief
+ *    Compute UV index
+ *
+ * @param[in] uv
+ *    UV sensor raw data
+ *
+ * @param[in] uk
+ *    UV calculation coefficients
+ *
+ * @return
+ *    UV index scaled by UV_OUPTUT_FRACTION
+ ******************************************************************************/
+int32_t Si1133::get_uv (int32_t uv)
+{
+    int32_t uvi;
+
+    uvi = calculate_polynomial(0, uv, UV_INPUT_FRACTION, UV_OUTPUT_FRACTION, UV_NUMCOEFF, uk);
+
+    return uvi;
+}
+
+/***************************************************************************//**
+ * @brief
+ *    Compute lux value
+ *
+ * @param[in] vis_high
+ *    Visible light sensor raw data
+ *
+ * @param[in] vis_low
+ *    Visible light sensor raw data
+ *
+ * @param[in] ir
+ *    Infrared sensor raw data
+ *
+ * @param[in] lk
+ *    Lux calculation coefficients
+ *
+ * @return
+ *    Lux value scaled by LUX_OUPTUT_FRACTION
+ ******************************************************************************/
+int32_t Si1133::get_lux (int32_t vis_high, int32_t vis_low, int32_t ir)
+{
+    int32_t lux;
+
+    if ( (vis_high > ADC_THRESHOLD) || (ir > ADC_THRESHOLD) ) {
+        lux = calculate_polynomial(vis_high,
+                                   ir,
+                                   INPUT_FRACTION_HIGH,
+                                   LUX_OUTPUT_FRACTION,
+                                   NUMCOEFF_HIGH,
+                                   &(lk.coeff_high[0]) );
+    } else {
+        lux = calculate_polynomial(vis_low,
+                                   ir,
+                                   INPUT_FRACTION_LOW,
+                                   LUX_OUTPUT_FRACTION,
+                                   NUMCOEFF_LOW,
+                                   &(lk.coeff_low[0]) );
+    }
+
+    return lux;
+}
+
+/***************************************************************************//**
+ * @brief
+ *    Measure lux and UV index using the Si1133 sensor
+ *
+ * @param[out] lux
+ *    The measured ambient light illuminace in lux
+ *
+ * @param[out] uvi
+ *    UV index
+ *
+ * @return
+ *    Returns zero on OK, non-zero otherwise
+ ******************************************************************************/
+uint32_t Si1133::measure_lux_uv (float *lux, float *uvi)
+{
+    Si1133::Samples_t samples;
+    uint32_t retval;
+    uint8_t response;
+
+    /* Force measurement */
+    retval = force_measurement();
+
+    /* Go to sleep while the sensor does the conversion */
+    wait_ms(200);
+
+    /* Check if the measurement finished, if not then wait */
+    retval += read_register(REG_IRQ_STATUS, &response);
+    while ( response != 0x0F ) {
+        wait_ms(5);
+        retval += read_register(REG_IRQ_STATUS, &response);
+    }
+
+    /* Get the results */
+    measure(&samples);
+
+    /* Convert the readings to lux */
+    *lux = (float) get_lux(samples.ch1, samples.ch3, samples.ch2);
+    *lux = *lux / (1 << LUX_OUTPUT_FRACTION);
+
+    /* Convert the readings to UV index */
+    *uvi = (float) get_uv(samples.ch0);
+    *uvi = *uvi / (1 << UV_OUTPUT_FRACTION);
+
+    return retval;
+}
+
+/***************************************************************************//**
+ * @brief
+ *    Reads Hardware ID from the SI1133 sensor
+ *
+ * @param[out] hardwareID
+ *    The Hardware ID of the chip (should be 0x33)
+ *
+ * @return
+ *    Returns zero on OK, non-zero otherwise
+ ******************************************************************************/
+uint32_t Si1133::get_hardware_id (uint8_t *hardware_id)
+{
+    uint32_t retval;
+
+    retval = read_register(REG_PART_ID, hardware_id);
+
+    return retval;
+}
+
+/***************************************************************************//**
+ * @brief
+ *    Retrieve the sample values from the chip and convert them
+ *    to lux and UV index values
+ *
+ * @param[out] lux
+ *    The measured ambient light illuminace in lux
+ *
+ * @param[out] uvi
+ *    UV index
+ *
+ * @return
+ *    Returns zero on OK, non-zero otherwise
+ ******************************************************************************/
+uint32_t Si1133::get_measurement (float *lux, float *uvi)
+{
+    Si1133::Samples_t samples;
+    uint32_t retval;
+
+    /* Get the results */
+    retval = measure(&samples);
+
+    /* Convert the readings to lux */
+    *lux = (float) get_lux(samples.ch1, samples.ch3, samples.ch2);
+    *lux = *lux / (1 << LUX_OUTPUT_FRACTION);
+
+    /* Convert the readings to UV index */
+    *uvi = (float) get_uv(samples.ch0);
+    *uvi = *uvi / (1 << UV_OUTPUT_FRACTION);
+
+    return retval;
+}
+
diff -r 000000000000 -r fe6c4edd0ecc Si1133.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Si1133.h	Wed Nov 06 20:10:47 2019 +0000
@@ -0,0 +1,297 @@
+/***************************************************************************//**
+ * @file Si1133.h
+ *******************************************************************************
+ * @section License
+ * <b>(C) Copyright 2017 Silicon Labs, http://www.silabs.com</b>
+ *******************************************************************************
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#ifndef SI1133_H
+#define SI1133_H
+
+#include "mbed.h"
+
+/** Si1133 class.
+ *  Used for taking Light level and UV index measurements.
+ *
+ * Example:
+ * @code
+ * #include "mbed.h"
+ * #include "Si1133.h"
+ *
+ * //Create an Si1133 object
+ * Si1133 sensor(PC4, PC5);
+ *
+ * int main()
+ * {
+ *     //Try to open the Si1133
+ *     if (sensor.open()) {
+ *         printf("Device detected!\n");
+ *
+ *         while (1) {
+ *             //Print the current light level
+ *             printf("Lux = %.3f\n", (float)sensor.get_light_level());
+ *             //Print the current UV index
+ *             printf("UV index = %.3f\n", (float)sensor.get_uv_index());
+ *
+ *             //Sleep for 0.5 seconds
+ *             wait(0.5);
+ *         }
+ *     } else {
+ *         error("Device not detected!\n");
+ *     }
+ * }
+ * @endcode
+ */
+class Si1133
+{
+public:
+
+    /** Create an Si1133 object connected to the specified I2C pins with the specified I2C slave address
+     *
+     * @param sda The I2C data pin.
+     * @param scl The I2C clock pin.
+     * @param hz The I2C bus frequency (defaults to 400kHz).
+     */
+    Si1133(PinName sda, PinName scl, int hz = 400000);
+
+    /**
+    * Si1133 destructor
+    */
+    ~Si1133(void);
+
+    /** Probe for the Si1133 and try to initialize the sensor
+     *
+     * @returns
+     *   'true' if the device exists on the bus,
+     *   'false' if the device doesn't exist on the bus.
+     */
+    bool open();
+
+    /** Measure the current light level (in lux) on the Si1133
+     *
+     * @returns The current temperature measurement in Lux.
+     */
+    float get_light_level();
+
+    /** Measure the current UV Index on the Si1133
+     *
+     * @returns The current UV index measurement.
+     */
+    float get_uv_index();
+
+    /** Do a combined measurement and return both the light level and UV index
+     *
+     * @param[out] light_level Measured light level in Lux
+     * @param[out] uv_index Measured UV index
+     *
+     * @returns true if measurement was successful
+     */
+    bool get_light_and_uv(float *light_level, float *uv_index);
+
+#ifdef MBED_OPERATORS
+    /** A shorthand for get_light_level()
+     *
+     * @returns The current temperature measurement in Lux.
+     */
+    operator float();
+#endif
+
+private:
+    /**
+    * @name I2C Registers
+    * @{
+    */
+    enum Register {
+        REG_PART_ID     = 0x00,     /**< Part ID                                                            */
+        REG_HW_ID       = 0x01,     /**< Hardware ID                                                        */
+        REG_REV_ID      = 0x02,     /**< Hardware revision                                                  */
+        REG_HOSTIN0     = 0x0A,     /**< Data for parameter table on PARAM_SET write to COMMAND register    */
+        REG_COMMAND     = 0x0B,     /**< Initiated action in Sensor when specific codes written here        */
+        REG_IRQ_ENABLE  = 0x0F,     /**< Interrupt enable                                                   */
+        REG_RESPONSE1   = 0x10,     /**< Contains the readback value from a query or a set command          */
+        REG_RESPONSE0   = 0x11,     /**< Chip state and error status                                        */
+        REG_IRQ_STATUS  = 0x12,     /**< Interrupt status                                                   */
+        REG_HOSTOUT0    = 0x13,     /**< Captured Sensor Data                                               */
+        REG_HOSTOUT1    = 0x14,     /**< Captured Sensor Data                                               */
+        REG_HOSTOUT2    = 0x15,     /**< Captured Sensor Data                                               */
+        REG_HOSTOUT3    = 0x16,     /**< Captured Sensor Data                                               */
+        REG_HOSTOUT4    = 0x17,     /**< Captured Sensor Data                                               */
+        REG_HOSTOUT5    = 0x18,     /**< Captured Sensor Data                                               */
+        REG_HOSTOUT6    = 0x19,     /**< Captured Sensor Data                                               */
+        REG_HOSTOUT7    = 0x1A,     /**< Captured Sensor Data                                               */
+        REG_HOSTOUT8    = 0x1B,     /**< Captured Sensor Data                                               */
+        REG_HOSTOUT9    = 0x1C,     /**< Captured Sensor Data                                               */
+        REG_HOSTOUT10   = 0x1D,     /**< Captured Sensor Data                                               */
+        REG_HOSTOUT11   = 0x1E,     /**< Captured Sensor Data                                               */
+        REG_HOSTOUT12   = 0x1F,     /**< Captured Sensor Data                                               */
+        REG_HOSTOUT13   = 0x20,     /**< Captured Sensor Data                                               */
+        REG_HOSTOUT14   = 0x21,     /**< Captured Sensor Data                                               */
+        REG_HOSTOUT15   = 0x22,     /**< Captured Sensor Data                                               */
+        REG_HOSTOUT16   = 0x23,     /**< Captured Sensor Data                                               */
+        REG_HOSTOUT17   = 0x24,     /**< Captured Sensor Data                                               */
+        REG_HOSTOUT18   = 0x25,     /**< Captured Sensor Data                                               */
+        REG_HOSTOUT19   = 0x26,     /**< Captured Sensor Data                                               */
+        REG_HOSTOUT20   = 0x27,     /**< Captured Sensor Data                                               */
+        REG_HOSTOUT21   = 0x28,     /**< Captured Sensor Data                                               */
+        REG_HOSTOUT22   = 0x29,     /**< Captured Sensor Data                                               */
+        REG_HOSTOUT23   = 0x2A,     /**< Captured Sensor Data                                               */
+        REG_HOSTOUT24   = 0x2B,     /**< Captured Sensor Data                                               */
+        REG_HOSTOUT25   = 0x2C,     /**< Captured Sensor Data                                               */
+    };
+    /**@}*/
+
+    /**
+    * @name Parameters
+    * @{
+    */
+    enum Parameter {
+        PARAM_I2C_ADDR      = 0x00, /**< I2C address                                                        */
+        PARAM_CH_LIST       = 0x01, /**< Channel list                                                       */
+        PARAM_ADCCONFIG0    = 0x02, /**< ADC config for Channel 0                                           */
+        PARAM_ADCSENS0      = 0x03, /**< ADC sensitivity setting for Channel 0                              */
+        PARAM_ADCPOST0      = 0x04, /**< ADC resolution, shift and threshold settings for Channel 0         */
+        PARAM_MEASCONFIG0   = 0x05, /**< ADC measurement counter selection for Channel 0                    */
+        PARAM_ADCCONFIG1    = 0x06, /**< ADC config for Channel 1                                           */
+        PARAM_ADCSENS1      = 0x07, /**< ADC sensitivity setting for Channel 1                              */
+        PARAM_ADCPOST1      = 0x08, /**< ADC resolution, shift and threshold settings for Channel 1         */
+        PARAM_MEASCONFIG1   = 0x09, /**< ADC measurement counter selection for Channel 1                    */
+        PARAM_ADCCONFIG2    = 0x0A, /**< ADC config for Channel 2                                           */
+        PARAM_ADCSENS2      = 0x0B, /**< ADC sensitivity setting for Channel 2                              */
+        PARAM_ADCPOST2      = 0x0C, /**< ADC resolution, shift and threshold settings for Channel 2         */
+        PARAM_MEASCONFIG2   = 0x0D, /**< ADC measurement counter selection for Channel 2                    */
+        PARAM_ADCCONFIG3    = 0x0E, /**< ADC config for Channel 3                                           */
+        PARAM_ADCSENS3      = 0x0F, /**< ADC sensitivity setting for Channel 3                              */
+        PARAM_ADCPOST3      = 0x10, /**< ADC resolution, shift and threshold settings for Channel 3         */
+        PARAM_MEASCONFIG3   = 0x11, /**< ADC measurement counter selection for Channel 3                    */
+        PARAM_ADCCONFIG4    = 0x12, /**< ADC config for Channel 4                                           */
+        PARAM_ADCSENS4      = 0x13, /**< ADC sensitivity setting for Channel 4                              */
+        PARAM_ADCPOST4      = 0x14, /**< ADC resolution, shift and threshold settings for Channel 4         */
+        PARAM_MEASCONFIG4   = 0x15, /**< ADC measurement counter selection for Channel 4                    */
+        PARAM_ADCCONFIG5    = 0x16, /**< ADC config for Channel 5                                           */
+        PARAM_ADCSENS5      = 0x17, /**< ADC sensitivity setting for Channel 5                              */
+        PARAM_ADCPOST5      = 0x18, /**< ADC resolution, shift and threshold settings for Channel 5         */
+        PARAM_MEASCONFIG5   = 0x19, /**< ADC measurement counter selection for Channel 5                    */
+        PARAM_MEASRATE_H    = 0x1A, /**< Main measurement rate counter MSB                                  */
+        PARAM_MEASRATE_L    = 0x1B, /**< Main measurement rate counter LSB                                  */
+        PARAM_MEASCOUNT0    = 0x1C, /**< Measurement rate extension counter 0                               */
+        PARAM_MEASCOUNT1    = 0x1D, /**< Measurement rate extension counter 1                               */
+        PARAM_MEASCOUNT2    = 0x1E, /**< Measurement rate extension counter 2                               */
+        PARAM_THRESHOLD0_H  = 0x25, /**< Threshold level 0 MSB                                              */
+        PARAM_THRESHOLD0_L  = 0x26, /**< Threshold level 0 LSB                                              */
+        PARAM_THRESHOLD1_H  = 0x27, /**< Threshold level 1 MSB                                              */
+        PARAM_THRESHOLD1_L  = 0x28, /**< Threshold level 1 LSB                                              */
+        PARAM_THRESHOLD2_H  = 0x29, /**< Threshold level 2 MSB                                              */
+        PARAM_THRESHOLD2_L  = 0x2A, /**< Threshold level 2 LSB                                              */
+        PARAM_BURST         = 0x2B, /**< Burst enable and burst count                                       */
+    };
+    /**@}*/
+
+    /**
+    * @name Commands
+    * @{
+    */
+    enum Command {
+        CMD_RESET_CMD_CTR   = 0x00, /**< Resets the command counter                                         */
+        CMD_RESET           = 0x01, /**< Forces a Reset                                                     */
+        CMD_NEW_ADDR        = 0x02, /**< Stores the new I2C address                                         */
+        CMD_FORCE_CH        = 0x11, /**< Initiates a set of measurements specified in CHAN_LIST parameter   */
+        CMD_PAUSE_CH        = 0x12, /**< Pauses autonomous measurements                                     */
+        CMD_START           = 0x13, /**< Starts autonomous measurements                                     */
+        CMD_PARAM_SET       = 0x80, /**< Sets a parameter                                                   */
+        CMD_PARAM_QUERY     = 0x40, /**< Reads a parameter                                                  */
+    };
+    /**@}*/
+
+    /**
+    * @name Responses
+    * @{
+    */
+    enum Response {
+        RSP0_CHIPSTAT_MASK  = 0xE0, /**< Chip state mask in Response0 register                              */
+        RSP0_COUNTER_MASK   = 0x1F, /**< Command counter and error indicator mask in Response0 register     */
+        RSP0_SLEEP          = 0x20, /**< Sleep state indicator bit mask in Response0 register               */
+    };
+    /**@}*/
+
+    /**
+     * @brief
+     *    Structure to store the data measured by the Si1133
+     */
+    typedef struct {
+        uint8_t     irq_status;     /**< Interrupt status of the device    */
+        int32_t     ch0;            /**< Channel 0 measurement data        */
+        int32_t     ch1;            /**< Channel 1 measurement data        */
+        int32_t     ch2;            /**< Channel 2 measurement data        */
+        int32_t     ch3;            /**< Channel 3 measurement data        */
+    } Samples_t;
+
+    /**
+     * @brief
+     *    Structure to store the calculation coefficients
+     */
+    typedef struct {
+        int16_t     info;           /**< Info                              */
+        uint16_t    mag;            /**< Magnitude                         */
+    } Coeff_t;
+
+    /**
+     * @brief
+     *    Structure to store the coefficients used for Lux calculation
+     */
+    typedef struct {
+        Coeff_t   coeff_high[4];   /**< High amplitude coeffs */
+        Coeff_t   coeff_low[9];    /**< Low amplitude coeffs  */
+    } LuxCoeff_t;
+
+    /* Forward-declare constant coefficient table */
+    static const LuxCoeff_t lk;
+    static const Coeff_t uk[];
+
+    /* Private functions */
+    uint32_t read_register(enum Register reg, uint8_t *data);
+    uint32_t write_register(enum Register reg, uint8_t data);
+    uint32_t write_register_block(enum Register reg, uint8_t length, uint8_t *data);
+    uint32_t read_register_block(enum Register reg, uint8_t length, uint8_t *data);
+    uint32_t get_irq_status(uint8_t *irq_status);
+    uint32_t wait_until_sleep(void);
+    uint32_t reset(void);
+    uint32_t reset_cmd_counter (void);
+    uint32_t send_cmd(enum Command command);
+    uint32_t force_measurement (void);
+    uint32_t pause_measurement (void);
+    uint32_t start_measurement (void);
+    uint32_t set_parameter (enum Parameter address, uint8_t value);
+    uint32_t read_parameter (enum Parameter address);
+    uint32_t init (void);
+    uint32_t deinit (void);
+    uint32_t measure (Samples_t *samples);
+    int32_t  get_uv (int32_t uv);
+    int32_t  get_lux (int32_t vis_high, int32_t vis_low, int32_t ir);
+    uint32_t measure_lux_uv (float *lux, float *uvi);
+    uint32_t get_measurement (float *lux, float *uvi);
+    uint32_t get_hardware_id (uint8_t *hardware_id);
+
+    int32_t calculate_polynomial_helper (int32_t input, int8_t fraction, uint16_t mag, int8_t  shift);
+    int32_t calculate_polynomial (int32_t x, int32_t y, uint8_t input_fraction, uint8_t output_fraction, uint8_t num_coeff, const Coeff_t *kp);
+
+    /* Member variables */
+    I2C m_I2C;
+};
+
+#endif
diff -r 000000000000 -r fe6c4edd0ecc main.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Wed Nov 06 20:10:47 2019 +0000
@@ -0,0 +1,26 @@
+#include "mbed.h"
+#include "Si1133.h"
+
+//I2C i2c (p13, p15);
+//Create an Si1133 object
+Si1133 sensor(P0_13, P0_15);
+//Serial pc(p25, p26);
+
+int main()
+{
+    
+   //Try to open the Si1133
+    if (sensor.open()) {
+        printf("Device detected!\n");
+        while (1) {
+            //Print the current light level
+            printf("Lux = %.3f\n", (float)sensor.get_light_level());
+            //Print the current UV index
+            printf("UV index = %.3f\n", (float)sensor.get_uv_index());
+            //Sleep for 0.5 seconds
+            wait(0.5);
+        }
+    } else {
+        error("Device not detected!\n");
+    }
+}
diff -r 000000000000 -r fe6c4edd0ecc mbed_app.json
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed_app.json	Wed Nov 06 20:10:47 2019 +0000
@@ -0,0 +1,31 @@
+{  
+    
+    "target_overrides": {
+        "K64F": {
+            "target.features_add": ["BLE"],
+            "target.extra_labels_add": ["CORDIO", "CORDIO_BLUENRG"]
+        },
+        "NUCLEO_F401RE": {
+            "target.features_add": ["BLE"],
+            "target.extra_labels_add": ["CORDIO", "CORDIO_BLUENRG"]
+        },
+        "DISCO_L475VG_IOT01A": {
+            "target.features_add": ["BLE"],
+            "target.extra_labels_add": ["CORDIO", "CORDIO_BLUENRG"]
+        },
+        "NRF52840_DK": {
+            "target.features_add": ["BLE"],
+            "target.extra_labels_add": ["CORDIO", "CORDIO_LL", "SOFTDEVICE_N ONE", "NORDIC_CORDIO"],
+            "target.extra_labels_remove": ["SOFTDEVICE_COMMON", "SOFTDEVICE_S140_FULL", "NORDIC_SOFTDEVICE"],           
+            "target.lf_clock_src": "NRF_LF_SRC_RC",
+            "target.lf_clock_rc_calib_timer_interval": 16,
+            "target.lf_clock_rc_calib_mode_config": 2
+            
+        },
+        "NRF52_DK": {
+            "target.features_add": ["BLE"],
+            "target.extra_labels_add": ["CORDIO", "CORDIO_LL", "SOFTDEVICE_NONE", "NORDIC_CORDIO"],
+            "target.extra_labels_remove": ["SOFTDEVICE_COMMON", "SOFTDEVICE_S132_FULL", "NORDIC_SOFTDEVICE"]
+        }
+    }
+}
\ No newline at end of file
diff -r 000000000000 -r fe6c4edd0ecc mbed_coragem.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed_coragem.lib	Wed Nov 06 20:10:47 2019 +0000
@@ -0,0 +1,1 @@
+https://github.com/leiachewbacca/mbed_coragem.git/#b8dad0652c9cd2321126a590280a18a964e1eed0