Mirror with some correction

Dependencies:   mbed FastIO FastPWM USBDevice

Committer:
mjr
Date:
Mon Feb 22 06:57:59 2021 +0000
Revision:
111:42dc75fbe623
Child:
113:7330439f2ffc
Add initial support for VCNL4010 IR distance sensor -  experimental and untested

Who changed what in which revision?

UserRevisionLine numberNew contents of line
mjr 111:42dc75fbe623 1 // VCNL4010 IR proximity sensor
mjr 111:42dc75fbe623 2
mjr 111:42dc75fbe623 3 #include "mbed.h"
mjr 111:42dc75fbe623 4 #include "math.h"
mjr 111:42dc75fbe623 5 #include "VCNL4010.h"
mjr 111:42dc75fbe623 6
mjr 111:42dc75fbe623 7 VCNL4010::VCNL4010(PinName sda, PinName scl, bool internalPullups)
mjr 111:42dc75fbe623 8 : i2c(sda, scl, internalPullups)
mjr 111:42dc75fbe623 9 {
mjr 111:42dc75fbe623 10 }
mjr 111:42dc75fbe623 11
mjr 111:42dc75fbe623 12 void VCNL4010::init()
mjr 111:42dc75fbe623 13 {
mjr 111:42dc75fbe623 14 printf("VCNL4010 initializing\r\n");
mjr 111:42dc75fbe623 15
mjr 111:42dc75fbe623 16 // reset the I2C bus
mjr 111:42dc75fbe623 17 i2c.reset();
mjr 111:42dc75fbe623 18
mjr 111:42dc75fbe623 19 // Set the proximity sampling rate to the fastest available rate of
mjr 111:42dc75fbe623 20 // 250 samples/second (4ms/sample). This isn't really fast enough for
mjr 111:42dc75fbe623 21 // good plunger motion tracking - a minimum sampling frequency of 400/s
mjr 111:42dc75fbe623 22 // is needed to avoid aliasing during the bounce-back phase of release
mjr 111:42dc75fbe623 23 // motions - but it's as fast as this device can go.
mjr 111:42dc75fbe623 24 writeReg(0x82, 0x07);
mjr 111:42dc75fbe623 25
mjr 111:42dc75fbe623 26 // Set the current for the IR LED (the light source for proximity
mjr 111:42dc75fbe623 27 // measurements). From the data sheet, it appears that higher current
mjr 111:42dc75fbe623 28 // settings yield slightly more linear response curves, but with
mjr 111:42dc75fbe623 29 // diminishing returns above 100mA. Assuming that the installation
mjr 111:42dc75fbe623 30 // will be powering the sensor from the KL25Z 3.3V regulator, we'd
mjr 111:42dc75fbe623 31 // like to keep the current as small as possible, though, to avoid
mjr 111:42dc75fbe623 32 // putting too much load on the regulator (since it has to provide
mjr 111:42dc75fbe623 33 // power to teh KL25Z itself as well). I'm going to try 50mA as a
mjr 111:42dc75fbe623 34 // compromise. It might be worth experimenting with different values
mjr 111:42dc75fbe623 35 // to see if they make a different to signal quality.
mjr 111:42dc75fbe623 36 //
mjr 111:42dc75fbe623 37 // The LED current in milliamps is 10mA times the numeric value we
mjr 111:42dc75fbe623 38 // set in the register, up to a maximum of 20 for 200mA.
mjr 111:42dc75fbe623 39 writeReg(0x83, 5);
mjr 111:42dc75fbe623 40
mjr 111:42dc75fbe623 41 // disable self-timed measurements - we'll start measurements on demand
mjr 111:42dc75fbe623 42 writeReg(0x80, 0x00);
mjr 111:42dc75fbe623 43
mjr 111:42dc75fbe623 44 // start the sample timer, which we use to gather timing statistics
mjr 111:42dc75fbe623 45 sampleTimer.start();
mjr 111:42dc75fbe623 46
mjr 111:42dc75fbe623 47 printf("VCNL4010 initialization done\r\n");
mjr 111:42dc75fbe623 48 }
mjr 111:42dc75fbe623 49
mjr 111:42dc75fbe623 50 // Start a proximity measurement
mjr 111:42dc75fbe623 51 void VCNL4010::startProxReading()
mjr 111:42dc75fbe623 52 {
mjr 111:42dc75fbe623 53 // set the prox_od (initiate proximity on demand) bit (0x08) in
mjr 111:42dc75fbe623 54 // the command register, if it's not already set
mjr 111:42dc75fbe623 55 uint8_t b = readReg(0x80);
mjr 111:42dc75fbe623 56 if ((b & 0x08) == 0)
mjr 111:42dc75fbe623 57 {
mjr 111:42dc75fbe623 58 tSampleStart = sampleTimer.read_us();
mjr 111:42dc75fbe623 59 writeReg(0x80, b | 0x08);
mjr 111:42dc75fbe623 60 }
mjr 111:42dc75fbe623 61 }
mjr 111:42dc75fbe623 62
mjr 111:42dc75fbe623 63 bool VCNL4010::proxReady()
mjr 111:42dc75fbe623 64 {
mjr 111:42dc75fbe623 65 // read the command register to get the status bits
mjr 111:42dc75fbe623 66 uint8_t b = readReg(0x80);
mjr 111:42dc75fbe623 67
mjr 111:42dc75fbe623 68 // if the prox_data_rdy bit (0x20) is set, a reading is ready
mjr 111:42dc75fbe623 69 if ((b & 0x20) != 0)
mjr 111:42dc75fbe623 70 return true;
mjr 111:42dc75fbe623 71
mjr 111:42dc75fbe623 72 // Not ready. Since the caller is polling, they must expect a reading
mjr 111:42dc75fbe623 73 // to be in progress; if not, start one now. A reading in progress is
mjr 111:42dc75fbe623 74 // indicated and initiated by the prox_od bit
mjr 111:42dc75fbe623 75 if ((b & 0x08) == 0)
mjr 111:42dc75fbe623 76 {
mjr 111:42dc75fbe623 77 tSampleStart = sampleTimer.read_us();
mjr 111:42dc75fbe623 78 writeReg(0x80, b | 0x08);
mjr 111:42dc75fbe623 79 }
mjr 111:42dc75fbe623 80
mjr 111:42dc75fbe623 81 // a reading is available if the prox_data_rdy (0x08) is set
mjr 111:42dc75fbe623 82 return (b & 0x20) != 0;
mjr 111:42dc75fbe623 83 }
mjr 111:42dc75fbe623 84
mjr 111:42dc75fbe623 85 int VCNL4010::getProx(uint8_t &distance, uint32_t &tMid, uint32_t &dt, uint32_t timeout_us)
mjr 111:42dc75fbe623 86 {
mjr 111:42dc75fbe623 87 // wait for the sample
mjr 111:42dc75fbe623 88 Timer t;
mjr 111:42dc75fbe623 89 t.start();
mjr 111:42dc75fbe623 90 for (;;)
mjr 111:42dc75fbe623 91 {
mjr 111:42dc75fbe623 92 // check for a sample
mjr 111:42dc75fbe623 93 if (proxReady())
mjr 111:42dc75fbe623 94 break;
mjr 111:42dc75fbe623 95
mjr 111:42dc75fbe623 96 // if we've exceeded the timeout, return failure
mjr 111:42dc75fbe623 97 if (t.read_us() > timeout_us)
mjr 111:42dc75fbe623 98 return -1;
mjr 111:42dc75fbe623 99 }
mjr 111:42dc75fbe623 100
mjr 111:42dc75fbe623 101 // figure the time since we initiated the reading
mjr 111:42dc75fbe623 102 dt = sampleTimer.read_us() - tSampleStart;
mjr 111:42dc75fbe623 103
mjr 111:42dc75fbe623 104 // figure the midpoint time
mjr 111:42dc75fbe623 105 tMid = tSampleStart + dt/2;
mjr 111:42dc75fbe623 106
mjr 111:42dc75fbe623 107 // read the result from the sensor, as a 16-bit proximity count value
mjr 111:42dc75fbe623 108 int N = (readReg(0x87) << 8) | readReg(0x88);
mjr 111:42dc75fbe623 109
mjr 111:42dc75fbe623 110 // start a new reading, so that the sensor is collecting the next
mjr 111:42dc75fbe623 111 // reading concurrently with the time-consuming floating-point math
mjr 111:42dc75fbe623 112 // we're about to do
mjr 111:42dc75fbe623 113 startProxReading();
mjr 111:42dc75fbe623 114
mjr 111:42dc75fbe623 115 // Figure the distance in abstract units. The raw count data from the
mjr 111:42dc75fbe623 116 // sensor is proportional to the intensity of the reflected light from
mjr 111:42dc75fbe623 117 // the target, which is proportional to the inverse of the square of
mjr 111:42dc75fbe623 118 // the distance. So the distance is proportional to the inverse of
mjr 111:42dc75fbe623 119 // the square root of the count. The proportionality factor is chosen
mjr 111:42dc75fbe623 120 // to normalize the result to a range of 0..65535.
mjr 111:42dc75fbe623 121 distance = static_cast<int>(146540.0f / sqrtf(static_cast<float>(N)));
mjr 111:42dc75fbe623 122
mjr 111:42dc75fbe623 123 // success
mjr 111:42dc75fbe623 124 return 0;
mjr 111:42dc75fbe623 125 }
mjr 111:42dc75fbe623 126
mjr 111:42dc75fbe623 127 uint8_t VCNL4010::readReg(uint8_t registerAddr)
mjr 111:42dc75fbe623 128 {
mjr 111:42dc75fbe623 129 // write the request
mjr 111:42dc75fbe623 130 uint8_t data_write[1] = { registerAddr };
mjr 111:42dc75fbe623 131 if (i2c.write(I2C_ADDR, data_write, 1, false))
mjr 111:42dc75fbe623 132 return 0x00;
mjr 111:42dc75fbe623 133
mjr 111:42dc75fbe623 134 // read the result
mjr 111:42dc75fbe623 135 uint8_t data_read[1];
mjr 111:42dc75fbe623 136 if (i2c.read(I2C_ADDR, data_read, 1))
mjr 111:42dc75fbe623 137 return 0x00;
mjr 111:42dc75fbe623 138
mjr 111:42dc75fbe623 139 // return the result
mjr 111:42dc75fbe623 140 return data_read[0];
mjr 111:42dc75fbe623 141 }
mjr 111:42dc75fbe623 142
mjr 111:42dc75fbe623 143 void VCNL4010::writeReg(uint8_t registerAddr, uint8_t data)
mjr 111:42dc75fbe623 144 {
mjr 111:42dc75fbe623 145 // set up the write: register number, data byte
mjr 111:42dc75fbe623 146 uint8_t data_write[2] = { registerAddr, data };
mjr 111:42dc75fbe623 147 i2c.write(I2C_ADDR, data_write, 2);
mjr 111:42dc75fbe623 148 }