SI1133 light sensor
Revision 0:fe6c4edd0ecc, committed 2019-11-06
- Comitter:
- brunnobbco
- Date:
- Wed Nov 06 20:10:47 2019 +0000
- Commit message:
- Light sensor to NRF52840
Changed in this revision
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, ®_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