OSRAM SFH7779 device driver: Ambient Light and proximity Sensor with Integrated 940nm IR Emitter Version 1.2
SFH7779.h@1:fe29e6d3a11e, 2017-09-14 (annotated)
- Committer:
- ninensei
- Date:
- Thu Sep 14 00:18:48 2017 +0000
- Revision:
- 1:fe29e6d3a11e
Converted to template so that I2C driver derivations can be used (I2C, SoftI2C, etc...); Changed filename to match class name.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
ninensei | 1:fe29e6d3a11e | 1 | /* mbed Microcontroller Library |
ninensei | 1:fe29e6d3a11e | 2 | * Copyright (c) 2017 AT&T, IIoT Foundry, Plano, TX, USA |
ninensei | 1:fe29e6d3a11e | 3 | * |
ninensei | 1:fe29e6d3a11e | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
ninensei | 1:fe29e6d3a11e | 5 | * you may not use this file except in compliance with the License. |
ninensei | 1:fe29e6d3a11e | 6 | * You may obtain a copy of the License at |
ninensei | 1:fe29e6d3a11e | 7 | * |
ninensei | 1:fe29e6d3a11e | 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
ninensei | 1:fe29e6d3a11e | 9 | * |
ninensei | 1:fe29e6d3a11e | 10 | * Unless required by applicable law or agreed to in writing, software |
ninensei | 1:fe29e6d3a11e | 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
ninensei | 1:fe29e6d3a11e | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
ninensei | 1:fe29e6d3a11e | 13 | * See the License for the specific language governing permissions and |
ninensei | 1:fe29e6d3a11e | 14 | * limitations under the License. |
ninensei | 1:fe29e6d3a11e | 15 | */ |
ninensei | 1:fe29e6d3a11e | 16 | |
ninensei | 1:fe29e6d3a11e | 17 | /** \addtogroup drivers */ |
ninensei | 1:fe29e6d3a11e | 18 | |
ninensei | 1:fe29e6d3a11e | 19 | /** Support for the OSRAM SFH7779 I2C IR-LED, proximity and ambient light sensor |
ninensei | 1:fe29e6d3a11e | 20 | * |
ninensei | 1:fe29e6d3a11e | 21 | * Example: |
ninensei | 1:fe29e6d3a11e | 22 | * @code |
ninensei | 1:fe29e6d3a11e | 23 | * |
ninensei | 1:fe29e6d3a11e | 24 | * #include "mbed.h" |
ninensei | 1:fe29e6d3a11e | 25 | * #include "SFH7779.h" |
ninensei | 1:fe29e6d3a11e | 26 | * |
ninensei | 1:fe29e6d3a11e | 27 | * I2C i2c(I2C_SDA, I2C_SCL); |
ninensei | 1:fe29e6d3a11e | 28 | * SFH7779<I2C> sfh7779(&i2c); |
ninensei | 1:fe29e6d3a11e | 29 | * |
ninensei | 1:fe29e6d3a11e | 30 | * int main() { |
ninensei | 1:fe29e6d3a11e | 31 | * sfh7779_measurements_t data; |
ninensei | 1:fe29e6d3a11e | 32 | * bool ok; |
ninensei | 1:fe29e6d3a11e | 33 | * |
ninensei | 1:fe29e6d3a11e | 34 | * ok = sfh7779.enable() && |
ninensei | 1:fe29e6d3a11e | 35 | * sfh7779.read(&data) && |
ninensei | 1:fe29e6d3a11e | 36 | * sfh7779.disable(); |
ninensei | 1:fe29e6d3a11e | 37 | * |
ninensei | 1:fe29e6d3a11e | 38 | * if (ok) { |
ninensei | 1:fe29e6d3a11e | 39 | * printf("shf7779 proximity reading = %d\r\n", data.prox); |
ninensei | 1:fe29e6d3a11e | 40 | * } else { |
ninensei | 1:fe29e6d3a11e | 41 | * printf("shf7779 error!\r\n"); |
ninensei | 1:fe29e6d3a11e | 42 | * } |
ninensei | 1:fe29e6d3a11e | 43 | * } |
ninensei | 1:fe29e6d3a11e | 44 | * @endcode |
ninensei | 1:fe29e6d3a11e | 45 | * @ingroup drivers |
ninensei | 1:fe29e6d3a11e | 46 | */ |
ninensei | 1:fe29e6d3a11e | 47 | |
ninensei | 1:fe29e6d3a11e | 48 | #pragma once |
ninensei | 1:fe29e6d3a11e | 49 | |
ninensei | 1:fe29e6d3a11e | 50 | #define SFH7779_BASE_ADDR_7BIT 0x39 |
ninensei | 1:fe29e6d3a11e | 51 | |
ninensei | 1:fe29e6d3a11e | 52 | #define SYSTEM_CONTROL_REG 0x40 |
ninensei | 1:fe29e6d3a11e | 53 | |
ninensei | 1:fe29e6d3a11e | 54 | #define MODE_CONTROL_REG 0x41 |
ninensei | 1:fe29e6d3a11e | 55 | #define PS_MODE_NORMAL (0x00<<4) // default |
ninensei | 1:fe29e6d3a11e | 56 | #define PS_MODE_TWO_PULSE (0x10<<4) |
ninensei | 1:fe29e6d3a11e | 57 | #define MRR_ALS0PS0 (0x00<<0) // default |
ninensei | 1:fe29e6d3a11e | 58 | #define MRR_ALS0PS10 (0x01<<0) |
ninensei | 1:fe29e6d3a11e | 59 | #define MRR_ALS0PS40 (0x02<<0) |
ninensei | 1:fe29e6d3a11e | 60 | #define MRR_ALS0PS100 (0x03<<0) |
ninensei | 1:fe29e6d3a11e | 61 | #define MRR_ALS0PS400 (0x04<<0) |
ninensei | 1:fe29e6d3a11e | 62 | #define MRR_ALS100PS0 (0x05<<0) |
ninensei | 1:fe29e6d3a11e | 63 | #define MRR_ALS100PS100 (0x06<<0) |
ninensei | 1:fe29e6d3a11e | 64 | #define MRR_ALS100PS400 (0x07<<0) |
ninensei | 1:fe29e6d3a11e | 65 | #define MRR_ALS401PS0 (0x08<<0) |
ninensei | 1:fe29e6d3a11e | 66 | #define MRR_ALS401PS100 (0x09<<0) |
ninensei | 1:fe29e6d3a11e | 67 | #define MRR_ALS400PS0 (0x0A<<0) |
ninensei | 1:fe29e6d3a11e | 68 | #define MRR_ALS400PS400 (0x0B<<0) |
ninensei | 1:fe29e6d3a11e | 69 | #define MRR_ALS50PS50 (0x0C<<0) |
ninensei | 1:fe29e6d3a11e | 70 | |
ninensei | 1:fe29e6d3a11e | 71 | #define ALS_PS_CONTROL_REG 0x42 |
ninensei | 1:fe29e6d3a11e | 72 | #define PS_OUT_PROXIMITY (0x00<<6) // default |
ninensei | 1:fe29e6d3a11e | 73 | #define PS_OUT_INFRARED_DC (0x01<<6) |
ninensei | 1:fe29e6d3a11e | 74 | #define ALS_GAIN_ALS1IR1 (0x00<<2) // default |
ninensei | 1:fe29e6d3a11e | 75 | #define ALS_GAIN_ALS2IR1 (0x04<<2) |
ninensei | 1:fe29e6d3a11e | 76 | #define ALS_GAIN_ALS2IR2 (0x05<<2) |
ninensei | 1:fe29e6d3a11e | 77 | #define ALS_GAIN_ALS64IR64 (0x0A<<2) |
ninensei | 1:fe29e6d3a11e | 78 | #define ALS_GAIN_ALS128IR64 (0x0E<<2) |
ninensei | 1:fe29e6d3a11e | 79 | #define ALS_GAIN_ALS128IR128 (0x0F<<2) |
ninensei | 1:fe29e6d3a11e | 80 | #define LED_CURRENT_25MA (0x00<<0) |
ninensei | 1:fe29e6d3a11e | 81 | #define LED_CURRENT_50MA (0x01<<0) |
ninensei | 1:fe29e6d3a11e | 82 | #define LED_CURRENT_100M (0x02<<0) |
ninensei | 1:fe29e6d3a11e | 83 | #define LED_CURRENT_200MA (0x03<<0) // default |
ninensei | 1:fe29e6d3a11e | 84 | |
ninensei | 1:fe29e6d3a11e | 85 | #define PERSISTANCE_REG 0x43 |
ninensei | 1:fe29e6d3a11e | 86 | #define INTR_ON_DATA_AVAIL (0x00<<0) |
ninensei | 1:fe29e6d3a11e | 87 | #define INTR_AFTER_1_VAL (0x01<<0) // default |
ninensei | 1:fe29e6d3a11e | 88 | #define INTR_AFTER_2_VALS (0x02<<0) |
ninensei | 1:fe29e6d3a11e | 89 | #define INTR_AFTER_3_VALS (0x03<<0) |
ninensei | 1:fe29e6d3a11e | 90 | #define INTR_AFTER_4_VALS (0x04<<0) |
ninensei | 1:fe29e6d3a11e | 91 | #define INTR_AFTER_5_VALS (0x05<<0) |
ninensei | 1:fe29e6d3a11e | 92 | #define INTR_AFTER_6_VALS (0x06<<0) |
ninensei | 1:fe29e6d3a11e | 93 | #define INTR_AFTER_7_VALS (0x07<<0) |
ninensei | 1:fe29e6d3a11e | 94 | #define INTR_AFTER_8_VALS (0x08<<0) |
ninensei | 1:fe29e6d3a11e | 95 | #define INTR_AFTER_9_VALS (0x09<<0) |
ninensei | 1:fe29e6d3a11e | 96 | #define INTR_AFTER_10_VALS (0x0A<<0) |
ninensei | 1:fe29e6d3a11e | 97 | #define INTR_AFTER_11_VALS (0x0B<<0) |
ninensei | 1:fe29e6d3a11e | 98 | #define INTR_AFTER_12_VALS (0x0C<<0) |
ninensei | 1:fe29e6d3a11e | 99 | #define INTR_AFTER_13_VALS (0x0D<<0) |
ninensei | 1:fe29e6d3a11e | 100 | #define INTR_AFTER_14_VALS (0x0E<<0) |
ninensei | 1:fe29e6d3a11e | 101 | #define INTR_AFTER_15_VALS (0x0F<<0) |
ninensei | 1:fe29e6d3a11e | 102 | |
ninensei | 1:fe29e6d3a11e | 103 | #define PS_DATA_LSB_REG 0x44 |
ninensei | 1:fe29e6d3a11e | 104 | #define PS_DATA_MSB_REG 0x45 |
ninensei | 1:fe29e6d3a11e | 105 | #define ALS_VIS_DATA_LSB_REG 0x46 |
ninensei | 1:fe29e6d3a11e | 106 | #define ALS_VIS_DATA_MSB_REG 0x47 |
ninensei | 1:fe29e6d3a11e | 107 | #define ALS_IR_DATA_LSB_REG 0x48 |
ninensei | 1:fe29e6d3a11e | 108 | #define ALS_IR_DATA_MSB_REG 0x49 |
ninensei | 1:fe29e6d3a11e | 109 | |
ninensei | 1:fe29e6d3a11e | 110 | #define INTERRUPT_CONTROL_REG 0x4A |
ninensei | 1:fe29e6d3a11e | 111 | #define PS_INT_ACTIVE (0x01<<7) |
ninensei | 1:fe29e6d3a11e | 112 | #define ALS_INT_ACTIVE (0x01<<6) |
ninensei | 1:fe29e6d3a11e | 113 | #define INT_MODE_PS_HIGH (0x00<<4) // default |
ninensei | 1:fe29e6d3a11e | 114 | #define INT_MODE_PS_HIGHLOW_HYS (0x01<<4) |
ninensei | 1:fe29e6d3a11e | 115 | #define INT_MODE_PS_HIGHLOW_OD (0x02<<4) |
ninensei | 1:fe29e6d3a11e | 116 | #define INT_ASSERT_LOW_ONLY (0x00<<3) // default |
ninensei | 1:fe29e6d3a11e | 117 | #define INT_ASSERT_LOW_THEN_HIGH (0x01<<3) |
ninensei | 1:fe29e6d3a11e | 118 | #define INT_LATCHED (0x00<<2) // default |
ninensei | 1:fe29e6d3a11e | 119 | #define INT_UNLATCHED (0x01<<2) |
ninensei | 1:fe29e6d3a11e | 120 | #define INT_PIN_INACTIVE (0x00<<0) // default |
ninensei | 1:fe29e6d3a11e | 121 | #define INT_PIN_PS_ONLY (0x01<<0) // default |
ninensei | 1:fe29e6d3a11e | 122 | #define INT_PIN_ALS_ONLY (0x02<<0) // default |
ninensei | 1:fe29e6d3a11e | 123 | #define INT_PIN_PS_AND_ALS (0x03<<0) // default |
ninensei | 1:fe29e6d3a11e | 124 | |
ninensei | 1:fe29e6d3a11e | 125 | typedef struct { |
ninensei | 1:fe29e6d3a11e | 126 | short prox; |
ninensei | 1:fe29e6d3a11e | 127 | short als_vis; |
ninensei | 1:fe29e6d3a11e | 128 | short als_ir; |
ninensei | 1:fe29e6d3a11e | 129 | } sfh7779_measurements_t; |
ninensei | 1:fe29e6d3a11e | 130 | |
ninensei | 1:fe29e6d3a11e | 131 | template <class T> |
ninensei | 1:fe29e6d3a11e | 132 | class SFH7779 |
ninensei | 1:fe29e6d3a11e | 133 | { |
ninensei | 1:fe29e6d3a11e | 134 | public: |
ninensei | 1:fe29e6d3a11e | 135 | /** |
ninensei | 1:fe29e6d3a11e | 136 | * Constructor |
ninensei | 1:fe29e6d3a11e | 137 | * |
ninensei | 1:fe29e6d3a11e | 138 | * @param i2c I2C class servicing the sensor |
ninensei | 1:fe29e6d3a11e | 139 | */ |
ninensei | 1:fe29e6d3a11e | 140 | SFH7779(T * i2c) : _i2c(i2c) {}; |
ninensei | 1:fe29e6d3a11e | 141 | |
ninensei | 1:fe29e6d3a11e | 142 | protected: |
ninensei | 1:fe29e6d3a11e | 143 | /** |
ninensei | 1:fe29e6d3a11e | 144 | * Write to a sensor register |
ninensei | 1:fe29e6d3a11e | 145 | * |
ninensei | 1:fe29e6d3a11e | 146 | * @param reg sensor register to write |
ninensei | 1:fe29e6d3a11e | 147 | * @param val value to write |
ninensei | 1:fe29e6d3a11e | 148 | * |
ninensei | 1:fe29e6d3a11e | 149 | * @returns true if successful |
ninensei | 1:fe29e6d3a11e | 150 | */ |
ninensei | 1:fe29e6d3a11e | 151 | bool write_reg(char reg, char val) { |
ninensei | 1:fe29e6d3a11e | 152 | char out[2] = {reg, val}; |
ninensei | 1:fe29e6d3a11e | 153 | return 0 == _i2c->write(SFH7779_BASE_ADDR_7BIT << 1, out, 2); |
ninensei | 1:fe29e6d3a11e | 154 | } |
ninensei | 1:fe29e6d3a11e | 155 | |
ninensei | 1:fe29e6d3a11e | 156 | /** |
ninensei | 1:fe29e6d3a11e | 157 | * Read multiple sensor registers |
ninensei | 1:fe29e6d3a11e | 158 | * |
ninensei | 1:fe29e6d3a11e | 159 | * @param start_reg first sensor register to be read |
ninensei | 1:fe29e6d3a11e | 160 | * @param count number of registers to be read |
ninensei | 1:fe29e6d3a11e | 161 | * @param buff pointer to buffer where to store the register values |
ninensei | 1:fe29e6d3a11e | 162 | * |
ninensei | 1:fe29e6d3a11e | 163 | * @returns true if successful |
ninensei | 1:fe29e6d3a11e | 164 | */ |
ninensei | 1:fe29e6d3a11e | 165 | bool read_regs(char start_reg, uint8_t count, void * buff) { |
ninensei | 1:fe29e6d3a11e | 166 | bool ok; |
ninensei | 1:fe29e6d3a11e | 167 | ok = (0 == _i2c->write(SFH7779_BASE_ADDR_7BIT << 1, &start_reg, 1, true)) |
ninensei | 1:fe29e6d3a11e | 168 | && (0 == _i2c->read(SFH7779_BASE_ADDR_7BIT << 1, (char *)buff, count)); |
ninensei | 1:fe29e6d3a11e | 169 | return ok; |
ninensei | 1:fe29e6d3a11e | 170 | } |
ninensei | 1:fe29e6d3a11e | 171 | |
ninensei | 1:fe29e6d3a11e | 172 | public: |
ninensei | 1:fe29e6d3a11e | 173 | /** |
ninensei | 1:fe29e6d3a11e | 174 | * Activate the sensor (begin measurement sampling). Data samples are |
ninensei | 1:fe29e6d3a11e | 175 | * taken 10 times per second. |
ninensei | 1:fe29e6d3a11e | 176 | * |
ninensei | 1:fe29e6d3a11e | 177 | * @param start_reg first sensor register to be read |
ninensei | 1:fe29e6d3a11e | 178 | * @param count number of registers to be read |
ninensei | 1:fe29e6d3a11e | 179 | * @param buff pointer to buffer where to store the register values |
ninensei | 1:fe29e6d3a11e | 180 | * |
ninensei | 1:fe29e6d3a11e | 181 | * @returns true if successful |
ninensei | 1:fe29e6d3a11e | 182 | */ |
ninensei | 1:fe29e6d3a11e | 183 | bool enable(void) { |
ninensei | 1:fe29e6d3a11e | 184 | bool ok; |
ninensei | 1:fe29e6d3a11e | 185 | ok = write_reg(MODE_CONTROL_REG, // Start ALS and PS sampling |
ninensei | 1:fe29e6d3a11e | 186 | PS_MODE_NORMAL | MRR_ALS100PS100) |
ninensei | 1:fe29e6d3a11e | 187 | && write_reg(ALS_PS_CONTROL_REG, // set ALS_VIS=ALS_IR GAIN = 64 current 25ma |
ninensei | 1:fe29e6d3a11e | 188 | PS_OUT_PROXIMITY | ALS_GAIN_ALS64IR64 | LED_CURRENT_25MA) |
ninensei | 1:fe29e6d3a11e | 189 | && write_reg(PERSISTANCE_REG, // set interrupt flag upon [any] data available |
ninensei | 1:fe29e6d3a11e | 190 | INTR_ON_DATA_AVAIL); |
ninensei | 1:fe29e6d3a11e | 191 | return ok; |
ninensei | 1:fe29e6d3a11e | 192 | } |
ninensei | 1:fe29e6d3a11e | 193 | |
ninensei | 1:fe29e6d3a11e | 194 | /** |
ninensei | 1:fe29e6d3a11e | 195 | * Deactivate the sensor (stop measurement sampling and put the sensor in |
ninensei | 1:fe29e6d3a11e | 196 | * standby/low-power mode) |
ninensei | 1:fe29e6d3a11e | 197 | * |
ninensei | 1:fe29e6d3a11e | 198 | * @returns true if successful |
ninensei | 1:fe29e6d3a11e | 199 | */ |
ninensei | 1:fe29e6d3a11e | 200 | bool disable(void) { |
ninensei | 1:fe29e6d3a11e | 201 | bool ok; |
ninensei | 1:fe29e6d3a11e | 202 | ok = write_reg(MODE_CONTROL_REG, // Stop ALS and PS sampling |
ninensei | 1:fe29e6d3a11e | 203 | PS_MODE_NORMAL | MRR_ALS0PS0); |
ninensei | 1:fe29e6d3a11e | 204 | return ok; |
ninensei | 1:fe29e6d3a11e | 205 | } |
ninensei | 1:fe29e6d3a11e | 206 | |
ninensei | 1:fe29e6d3a11e | 207 | /** |
ninensei | 1:fe29e6d3a11e | 208 | * Wait for and return the next new sensor measurement (proximity, |
ninensei | 1:fe29e6d3a11e | 209 | * ambient visual light, and ambient infrared light). |
ninensei | 1:fe29e6d3a11e | 210 | * |
ninensei | 1:fe29e6d3a11e | 211 | * @param buff pointer to buffer where to store the register values |
ninensei | 1:fe29e6d3a11e | 212 | * @param timeout_ms maximum time to wait for a new sample to become |
ninensei | 1:fe29e6d3a11e | 213 | * available. Time is in milliseconds. Example timeouts are: |
ninensei | 1:fe29e6d3a11e | 214 | * 0 - return a sample if one is available, otherwise don't |
ninensei | 1:fe29e6d3a11e | 215 | * wait. |
ninensei | 1:fe29e6d3a11e | 216 | * n - wait up to n milliseconds for a sample to become |
ninensei | 1:fe29e6d3a11e | 217 | * available. |
ninensei | 1:fe29e6d3a11e | 218 | * -1 - wait forever for a sample to become available |
ninensei | 1:fe29e6d3a11e | 219 | * |
ninensei | 1:fe29e6d3a11e | 220 | * @returns true if successful |
ninensei | 1:fe29e6d3a11e | 221 | */ |
ninensei | 1:fe29e6d3a11e | 222 | bool read(sfh7779_measurements_t * buff, int timeout_ms = -1) { |
ninensei | 1:fe29e6d3a11e | 223 | Timer timer; |
ninensei | 1:fe29e6d3a11e | 224 | timer.start(); |
ninensei | 1:fe29e6d3a11e | 225 | while (true) { |
ninensei | 1:fe29e6d3a11e | 226 | struct PACKED { |
ninensei | 1:fe29e6d3a11e | 227 | sfh7779_measurements_t measurements; |
ninensei | 1:fe29e6d3a11e | 228 | char stat; |
ninensei | 1:fe29e6d3a11e | 229 | } in; |
ninensei | 1:fe29e6d3a11e | 230 | if (false == read_regs(PS_DATA_LSB_REG, sizeof(in), &in)) { |
ninensei | 1:fe29e6d3a11e | 231 | break; |
ninensei | 1:fe29e6d3a11e | 232 | } |
ninensei | 1:fe29e6d3a11e | 233 | if (in.stat & PS_INT_ACTIVE) { |
ninensei | 1:fe29e6d3a11e | 234 | *buff = in.measurements; |
ninensei | 1:fe29e6d3a11e | 235 | return true; |
ninensei | 1:fe29e6d3a11e | 236 | } |
ninensei | 1:fe29e6d3a11e | 237 | if (timeout_ms != -1 && (timer.read_ms() >= timeout_ms)) { |
ninensei | 1:fe29e6d3a11e | 238 | break; |
ninensei | 1:fe29e6d3a11e | 239 | } |
ninensei | 1:fe29e6d3a11e | 240 | #ifdef RTOS_H |
ninensei | 1:fe29e6d3a11e | 241 | Thread::wait(5); |
ninensei | 1:fe29e6d3a11e | 242 | #else |
ninensei | 1:fe29e6d3a11e | 243 | wait(0.005); |
ninensei | 1:fe29e6d3a11e | 244 | #endif |
ninensei | 1:fe29e6d3a11e | 245 | } |
ninensei | 1:fe29e6d3a11e | 246 | return false; |
ninensei | 1:fe29e6d3a11e | 247 | } |
ninensei | 1:fe29e6d3a11e | 248 | |
ninensei | 1:fe29e6d3a11e | 249 | protected: |
ninensei | 1:fe29e6d3a11e | 250 | T *_i2c; |
ninensei | 1:fe29e6d3a11e | 251 | }; |
ninensei | 1:fe29e6d3a11e | 252 |