if you can find one ... the "i2c protocol information section" seems pretty straightforward I think:
Reading the distance is done by first writing a Trigger Reading command to the sensor -
send 0x62 (this is the 7 bit address 0x31 followed by the write bit ‘0’) and then reading
from the sensor by sending 0x63 (the base address with the Read bit ‘1’) followed by
three byte read operations. The first two bytes you receive are a 16 bit word containing
the latest measurement in mm**, the third byte is the CRC8 checksum.
If I understand correctly, you should write a 0x00
(TRIGGER READING
) byte, then wait
a wait of approximately 500us
then read three bytes. The first two bytes you read will be the ones containing the measurement. You can optionally check the checksum to verify the integrity of the received data.
If I understood correctly, this is all you need. The datasheet doesn't really say what order the two data bytes are in, so I had to guess below. If this gives wonky readings, uncomment the other option:
In Evo.h
:
#include <I2c.h>
class Evo : public I2c
{
public:
int readI2C() override {
i2c_char_t c = 0;
if(write(i2C_file, &c, sizeof(c)) != sizeof(c))
{
// error, abort
fprintf(stderr, "Error while writing\n");
return -1;
}
usleep(500);
i2c_char_t r[3];
if(sizeof(r) != read(i2C_file, r, sizeof(r)))
{
// handle error
fprintf(stderr, "Error while reading\n");
return -1;
}
// the manual is not clear about whether the first byte is the MSB or LSB
distance_ = r[0] << 8 | r[1]; // either this (MSB first)...
// distance_ = r[1] << 8 | r[0]; // or this (LSB first)...
return 0;
}
int getDistance()
{
return distance_;
}
private:
int distance_ = 0;
};
in render.cpp
:
#include <Bela.h>
#include <libraries/Oscillator/Oscillator.h>
#include "Evo.h"
#include <cmath>
Evo gEvo;
int gI2cBus = 1; // the I2c bus the sensor is connected to
int gI2cAddress = 0x31; // "Primary Slave Address"
int gReadSleepMs = 10; // how often to read from the Evo
int gPrintIntervalMs = 100; // how often to print
Oscillator gOsc;
void readTask(void*)
{
int elapsedMs = 0;
while(!Bela_stopRequested())
{
if(gEvo.readI2C()) {
fprintf(stderr, "Error reading. Stopping\n");
Bela_requestStop();
break;
}
elapsedMs += gReadSleepMs;
if(elapsedMs >= gPrintIntervalMs)
{
printf("%5d\n", gEvo.getDistance());
elapsedMs = 0;
}
usleep(gReadSleepMs * 1000);
}
}
bool setup(BelaContext *context, void *userData)
{
if(gEvo.initI2C_RW(gI2cBus, gI2cAddress, -1))
return false; // wrong bus, or address out of range
if(gEvo.readI2C()) //verify that we can read from the device
return false; // ... or fail otherwise
gOsc.setup(context->audioSampleRate);
Bela_runAuxiliaryTask(readTask);
return true;
}
void render(BelaContext *context, void *userData)
{
float distance = gEvo.getDistance();
float frequency = 110 * powf(2, distance / 120); // 1cm per semitone (??)
gOsc.setFrequency(frequency);
for(unsigned int n = 0; n < context->audioFrames; ++n)
{
float out = gOsc.process();
for(unsigned int c = 0; c < context->audioOutChannels; ++c)
{
audioWrite(context, n, c, out);
}
}
}
void cleanup(BelaContext *context, void *userData)
{}
The UART interface seems even simpler, as you can simply read from it. Refer to 4.4.3 UART output format
for the format details and look at Communication/Serial
to use the Serial
library.