Trinket 3V - I2C stops

Adafruit's tiny microcontroller platform. Please tell us which board you are using.
For CircuitPython issues, ask in the Adafruit CircuitPython forum.

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
User avatar
Forest_25
 
Posts: 8
Joined: Sat Aug 19, 2017 6:07 am

Trinket 3V - I2C stops

Post by Forest_25 »

Hello,
I'm currently using a VL6180X ToF Distance sensor connected to a trinket 3V that is again connected to a Arduino Micro Board or a Mbientlab MetamotionR board. I established an I2C Bus between the ToF Sensor(Slave) and the Trinket (Master using a Software I2C Wire on the pins 3 and 4) and if something is in range the trinket starts to blink. This part works perfectly fine.
Then I want to send the signal to the Arduino Micro/MetamotionR to read the data and to print it. In this case the trinket is the slave(using the TinyWireS library on the I2C pins 0 and 2) and the Arduino Micro/Metamotion R is the slave. This configuration works perfectly fine, only that after approximately one minute the connection between the trinket and the Arduino/MetamotionR interrupts. I got the same problem for both boards. Basically the trinket doesn't send any data even though the Arduino or the MetamotionR requests it. Could it have to do with the clock speed of 8 MHz? Is there any way to solve this problem?
My code

Code: Select all

#include <TinyWireS.h>
#include <SoftwareWire.h>
SoftwareWire myWire( 3, 4);

//needed for the VL6180X

uint8_t address = 0b0101001;
uint8_t scaling = 0;
uint8_t ptp_offset = 0;
uint16_t io_timeout = 0;
bool did_timeout = false;
static uint16_t const ScalerValues[] = {0, 253, 127, 84};
//int Pin = 8;
int i=0;
uint8_t i2crange = 0;
uint8_t slowi2c = 0;
int ledState = LOW;
  
void setup() {

  pinMode(LED_BUILTIN, OUTPUT);
  TinyWireS.begin(8);                
  TinyWireS.onRequest(requestEvent);
  myWire.begin();

  //initialise VL6180X sensor

  ptp_offset = readReg(0x024);
  if (readReg(0x016) == 1)
  {
    scaling = 1;

    writeReg(0x207, 0x01);
    writeReg(0x208, 0x01);
    writeReg(0x096, 0x00);
    writeReg(0x097, 0xFD); // RANGE_SCALER = 253
    writeReg(0x0E3, 0x00);
    writeReg(0x0E4, 0x04);
    writeReg(0x0E5, 0x02);
    writeReg(0x0E6, 0x01);
    writeReg(0x0E7, 0x03);
    writeReg(0x0F5, 0x02);
    writeReg(0x0D9, 0x05);
    writeReg(0x0DB, 0xCE);
    writeReg(0x0DC, 0x03);
    writeReg(0x0DD, 0xF8);
    writeReg(0x09F, 0x00);
    writeReg(0x0A3, 0x3C);
    writeReg(0x0B7, 0x00);
    writeReg(0x0BB, 0x3C);
    writeReg(0x0B2, 0x09);
    writeReg(0x0CA, 0x09);
    writeReg(0x198, 0x01);
    writeReg(0x1B0, 0x17);
    writeReg(0x1AD, 0x00);
    writeReg(0x0FF, 0x05);
    writeReg(0x100, 0x05);
    writeReg(0x199, 0x05);
    writeReg(0x1A6, 0x1B);
    writeReg(0x1AC, 0x3E);
    writeReg(0x1A7, 0x1F);
    writeReg(0x030, 0x00);

    writeReg(0x016, 0);
  }
  else
  {
    // Sensor has already been initialized, so try to get scaling settings by
    // reading registers.
    uint16_t s = readReg16Bit(0x096);

    if      (s == ScalerValues[3]) { scaling = 3; }
    else if (s == ScalerValues[2]) { scaling = 2; }
    else                           { scaling = 1; }

    // Adjust the part-to-part range offset value read earlier to account for
    // existing scaling. If the sensor was already in 2x or 3x scaling mode,
    // precision will be lost calculating the original (1x) offset, but this can
    // be resolved by resetting the sensor and Arduino again.
    ptp_offset *= scaling;
  }

  //default configuration

  // "Recommended : Public registers"

  // readout__averaging_sample_period = 48
  writeReg(0x10A, 0x30);

  // sysals__analogue_gain_light = 6 (ALS gain = 1 nominal, actually 1.01 according to Table 14 in datasheet)
  writeReg(0x03F, 0x46);

  // sysrange__vhv_repeat_rate = 255 (auto Very High Voltage temperature recalibration after every 255 range measurements)
  writeReg(0x031, 0xFF);

  // sysals__integration_period = 99 (100 ms)
  // AN4545 incorrectly recommends writing to register 0x040; 0x63 should go in the lower byte, which is register 0x041.
  writeReg16Bit(0x040, 0x0063);

  // sysrange__vhv_recalibrate = 1 (manually trigger a VHV recalibration)
  writeReg(0x02E, 0x01);


  // "Optional: Public registers"

  // sysrange__intermeasurement_period = 9 (100 ms)
  writeReg(0x01B, 0x09);

  // sysals__intermeasurement_period = 49 (500 ms)
  writeReg(0x01B, 0x31);

  // als_int_mode = 4 (ALS new sample ready interrupt); range_int_mode = 4 (range new sample ready interrupt)
  writeReg(0x014, 0x24);


  // Reset other settings to power-on defaults

  // sysrange__max_convergence_time = 49 (49 ms)
  writeReg(0x01C, 0x31);

  // disable interleaved mode
  writeReg(0x2A3, 0);

  // reset range scaling factor to 1x
  //setScaling(1);

  io_timeout = 500;
}

void loop() {
  
  i2crange = readRangeSingle();
  //TinyWireS.send(i2crange);
    if(i2crange < 255)
  {

    digitalWrite(LED_BUILTIN, HIGH);
    delay(50);
    digitalWrite(LED_BUILTIN, LOW);
    delay(50);

  }

  
}

//functions for the sensor 

uint8_t readReg(uint16_t reg)
{
  uint8_t value;

  myWire.beginTransmission(0b0101001);
  myWire.write((reg >> 8) & 0xff);  // reg high byte
  myWire.write(reg & 0xff);         // reg low byte
  myWire.endTransmission();

  myWire.requestFrom(0b0101001, (uint8_t)1);
  value = myWire.read();
  myWire.endTransmission();

  return value;
}

void writeReg(uint16_t reg, uint8_t value)
{
  myWire.beginTransmission(0b0101001);
  myWire.write((reg >> 8) & 0xff);  // reg high byte
  myWire.write(reg & 0xff);         // reg low byte
  myWire.write(value);
  myWire.endTransmission();
}

uint16_t readReg16Bit(uint16_t reg)
{
  uint16_t value;

  myWire.beginTransmission(0b0101001);
  myWire.write((reg >> 8) & 0xff);  // reg high byte
  myWire.write(reg & 0xff);         // reg low byte
  myWire.endTransmission();

  myWire.requestFrom(0b0101001, (uint8_t)2);
  value = (uint16_t)myWire.read() << 8; // value high byte
  value |= myWire.read();               // value low byte
  myWire.endTransmission();
  return value;
}

void writeReg16Bit(uint16_t reg, uint16_t value)
{
  myWire.beginTransmission(0b0101001);
  myWire.write((reg >> 8) & 0xff);  // reg high byte
  myWire.write(reg & 0xff);         // reg low byte
  myWire.write((value >> 8) & 0xff);  // value high byte
  myWire.write(value & 0xff);         // value low byte
  myWire.endTransmission();
}

uint8_t readRangeSingle()
{
  writeReg(0x018, 0x01);
  uint8_t range = 0;
  return readRangeContinuous();
}
uint8_t readRangeContinuous() 
{
  uint16_t millis_start = millis();
  while ((readReg(0x04F) & 0x04) == 0)
  {
    if (io_timeout > 0 && ((uint16_t)millis() - millis_start) > io_timeout)
    {
      did_timeout = true;
      return 255;
    }
  }

  uint8_t range = readReg(0x062);
  writeReg(0x015, 0x01);
  slowi2c = range;
  return range;
}

//when using onrequest

void requestEvent() {
  TinyWireS.send(slowi2c);

}

Attachments
IMG_20170822_105028-min.jpg
IMG_20170822_105028-min.jpg (853.05 KiB) Viewed 309 times

User avatar
Forest_25
 
Posts: 8
Joined: Sat Aug 19, 2017 6:07 am

Re: Trinket 3V - I2C stops

Post by Forest_25 »

I realised that the trinket stops the I2C communication, but not the software I2C. If I'm using a smaller intervall between the requests, the trinket stops earlier, while it takes a longer time for longer intervalls. I need at least an intervall of 15 Hz. Is there any reason why the trinket could just stop the I2C connection?

User avatar
Forest_25
 
Posts: 8
Joined: Sat Aug 19, 2017 6:07 am

Re: Trinket 3V - I2C stops

Post by Forest_25 »

After some trying I fixed the problem by leaving the blinking of the LED outside. Turns out that the delay caused by the LED causes the trinket to stop after some measurements. This is great because it means that you can use two separate I2C Busses on the Trinket as long as they run with the same frequency!
Here is the updated code

Code: Select all

#include <TinyWireS.h>
#include <SoftwareWire.h>
SoftwareWire myWire( 3, 4);

//needed for the VL6180X

uint8_t address = 0b0101001;
uint8_t scaling = 0;
uint8_t ptp_offset = 0;
uint16_t io_timeout = 0;
bool did_timeout = false;
static uint16_t const ScalerValues[] = {0, 253, 127, 84};
//int Pin = 8;
int i=0;
uint8_t i2crange = 0;
uint8_t slowi2c = 0;
int ledState = LOW;
  
void setup() {

  pinMode(LED_BUILTIN, OUTPUT);
  TinyWireS.begin(8);                
  TinyWireS.onRequest(requestEvent);
  myWire.begin();

  //initialise VL6180X sensor

  ptp_offset = readReg(0x024);
  if (readReg(0x016) == 1)
  {
    scaling = 1;

    writeReg(0x207, 0x01);
    writeReg(0x208, 0x01);
    writeReg(0x096, 0x00);
    writeReg(0x097, 0xFD); // RANGE_SCALER = 253
    writeReg(0x0E3, 0x00);
    writeReg(0x0E4, 0x04);
    writeReg(0x0E5, 0x02);
    writeReg(0x0E6, 0x01);
    writeReg(0x0E7, 0x03);
    writeReg(0x0F5, 0x02);
    writeReg(0x0D9, 0x05);
    writeReg(0x0DB, 0xCE);
    writeReg(0x0DC, 0x03);
    writeReg(0x0DD, 0xF8);
    writeReg(0x09F, 0x00);
    writeReg(0x0A3, 0x3C);
    writeReg(0x0B7, 0x00);
    writeReg(0x0BB, 0x3C);
    writeReg(0x0B2, 0x09);
    writeReg(0x0CA, 0x09);
    writeReg(0x198, 0x01);
    writeReg(0x1B0, 0x17);
    writeReg(0x1AD, 0x00);
    writeReg(0x0FF, 0x05);
    writeReg(0x100, 0x05);
    writeReg(0x199, 0x05);
    writeReg(0x1A6, 0x1B);
    writeReg(0x1AC, 0x3E);
    writeReg(0x1A7, 0x1F);
    writeReg(0x030, 0x00);

    writeReg(0x016, 0);
  }
  else
  {
    // Sensor has already been initialized, so try to get scaling settings by
    // reading registers.
    uint16_t s = readReg16Bit(0x096);

    if      (s == ScalerValues[3]) { scaling = 3; }
    else if (s == ScalerValues[2]) { scaling = 2; }
    else                           { scaling = 1; }

    // Adjust the part-to-part range offset value read earlier to account for
    // existing scaling. If the sensor was already in 2x or 3x scaling mode,
    // precision will be lost calculating the original (1x) offset, but this can
    // be resolved by resetting the sensor and Arduino again.
    ptp_offset *= scaling;
  }

  //default configuration

  // "Recommended : Public registers"

  // readout__averaging_sample_period = 48
  writeReg(0x10A, 0x30);

  // sysals__analogue_gain_light = 6 (ALS gain = 1 nominal, actually 1.01 according to Table 14 in datasheet)
  writeReg(0x03F, 0x46);

  // sysrange__vhv_repeat_rate = 255 (auto Very High Voltage temperature recalibration after every 255 range measurements)
  writeReg(0x031, 0xFF);

  // sysals__integration_period = 99 (100 ms)
  // AN4545 incorrectly recommends writing to register 0x040; 0x63 should go in the lower byte, which is register 0x041.
  writeReg16Bit(0x040, 0x0063);

  // sysrange__vhv_recalibrate = 1 (manually trigger a VHV recalibration)
  writeReg(0x02E, 0x01);


  // "Optional: Public registers"

  // sysrange__intermeasurement_period = 9 (100 ms)
  writeReg(0x01B, 0x09);

  // sysals__intermeasurement_period = 49 (500 ms)
  writeReg(0x01B, 0x31);

  // als_int_mode = 4 (ALS new sample ready interrupt); range_int_mode = 4 (range new sample ready interrupt)
  writeReg(0x014, 0x24);


  // Reset other settings to power-on defaults

  // sysrange__max_convergence_time = 49 (49 ms)
  writeReg(0x01C, 0x31);

  // disable interleaved mode
  writeReg(0x2A3, 0);

  // reset range scaling factor to 1x
  //setScaling(1);

  io_timeout = 500;
}

void loop() {

  delay(25);
}

//functions for the sensor 

uint8_t readReg(uint16_t reg)
{
  uint8_t value;

  myWire.beginTransmission(0b0101001);
  myWire.write((reg >> 8) & 0xff);  // reg high byte
  myWire.write(reg & 0xff);         // reg low byte
  myWire.endTransmission();

  myWire.requestFrom(0b0101001, (uint8_t)1);
  value = myWire.read();
  myWire.endTransmission();

  return value;
}

void writeReg(uint16_t reg, uint8_t value)
{
  myWire.beginTransmission(0b0101001);
  myWire.write((reg >> 8) & 0xff);  // reg high byte
  myWire.write(reg & 0xff);         // reg low byte
  myWire.write(value);
  myWire.endTransmission();
}

uint16_t readReg16Bit(uint16_t reg)
{
  uint16_t value;

  myWire.beginTransmission(0b0101001);
  myWire.write((reg >> 8) & 0xff);  // reg high byte
  myWire.write(reg & 0xff);         // reg low byte
  myWire.endTransmission();

  myWire.requestFrom(0b0101001, (uint8_t)2);
  value = (uint16_t)myWire.read() << 8; // value high byte
  value |= myWire.read();               // value low byte
  myWire.endTransmission();
  return value;
}

void writeReg16Bit(uint16_t reg, uint16_t value)
{
  myWire.beginTransmission(0b0101001);
  myWire.write((reg >> 8) & 0xff);  // reg high byte
  myWire.write(reg & 0xff);         // reg low byte
  myWire.write((value >> 8) & 0xff);  // value high byte
  myWire.write(value & 0xff);         // value low byte
  myWire.endTransmission();
}

uint8_t readRangeSingle()
{
  writeReg(0x018, 0x01);
  uint8_t range = 0;
  return readRangeContinuous();
}
uint8_t readRangeContinuous() 
{
  uint16_t millis_start = millis();
  while ((readReg(0x04F) & 0x04) == 0)
  {
    if (io_timeout > 0 && ((uint16_t)millis() - millis_start) > io_timeout)
    {
      did_timeout = true;
      return 255;
    }
  }

  uint8_t range = readReg(0x062);
  writeReg(0x015, 0x01);
  return range;
}

//when using onrequest

void requestEvent() {
  TinyWireS.send(readRangeSingle());

}

User avatar
rlgjr562
 
Posts: 60
Joined: Sun Jan 21, 2018 5:02 pm

Re: Trinket 3V - I2C stops

Post by rlgjr562 »

Where did you get the TinyWireS library? I can find the Adafruit version of TinyWireM for a I2C Master but not TinyWireS for the I2C Slave.

User avatar
adafruit_support_mike
 
Posts: 67454
Joined: Thu Feb 11, 2010 2:51 pm

Re: Trinket 3V - I2C stops

Post by adafruit_support_mike »

The TineWireM library is built into the board support package for the Trinket. It has a few simple wrappers to make it look like the Wire library.

Locked
Please be positive and constructive with your questions and comments.

Return to “Trinket ATTiny, Trinket M0”