Communicating between VL6180x & T4.1 using I2C2 instead of I2C

Status
Not open for further replies.
Hello. I can't figure out how to change my code to use I2C2 with a LV6180. it worked fine using pins 19 & 18, but when I changed to pins 24 & 25 the program hangs. I was thinking the only thing I had to add was the following lines:
Wire.setSCL(24); // SCL2 on third i2c bus on T4.1
Wire.setSDA(25); // SDA2 on third i2c bus on T4.1
Wire.begin();

I'm relatively inexperienced at Arduino and and completely inexperienced at I2C. My project uses a Teensy 4.1, an ILI9341, & a VL6180x. sketch and photo attached (hopefully). I'll greatly appreciate any help you can offer.

Code:
// This sketch uses the following:  Radio Buttons,  Second Hand using sin() and cos(),
// Bar Graph reading VL6180X
//
//
//
#include <SPI.h>
#include <Wire.h>
#include <ILI9341_t3.h>
#include <XPT2046_Touchscreen.h>
#include <TimeLib.h> //added
#include "Adafruit_VL6180X.h"  //add ed from vl6180
#include <movingAvg.h>         // https://github.com/JChristensen/movingAvg

Adafruit_VL6180X vl = Adafruit_VL6180X();  //add ed from vl6180

// This is calibration data for the raw touch data to the screen coordinates
#define TS_MINX 400  //150
#define TS_MINY 300  //130
#define TS_MAXX 3900 //3800
#define TS_MAXY 3900 //4000

#define CS_PIN 8
#define TIRQ_PIN  2

XPT2046_Touchscreen ts(CS_PIN, TIRQ_PIN);
#define TFT_CS 10
#define TFT_DC  9
ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC);
uint8_t range = 0;
int buttX = 255, buttWid = 60, buttHgt = 40, buttRnd = 10, buttSel = 3;
int buttY[] = {195, 145, 95, 45};
const char* buttText[] = {"GRN", "YEL", "RED", "AUT"};
// unsigned int buttColor[] = {ILI9341_GREEN, ILI9341_YELLOW, ILI9341_RED, ILI9341_WHITE};
unsigned int buttColor[] = {0x07E0, 0xFFE0, 0xF800, 0xFFFF};
movingAvg rangeAvg(20);

void setup(void)
{
  Wire.setSCL(24); // SCL2 on third i2c bus on T4.1
  Wire.setSDA(25); // SDA2 on third i2c bus on T4.1
  Wire.begin();

  vl.begin();
  //Serial.begin(38400);
  //delay(1000);
  tft.begin();
  //if (!ts.begin()) { 
  //  Serial.println("Unable to start touchscreen.");
  //} 
  //else { 
  //  Serial.println("Touchscreen started."); 
  //}
  ts.begin();
  setSyncProvider(getTeensy3Time); //added

  tft.fillScreen(ILI9341_NAVY);
  // origin = left,top landscape (USB left upper)
  tft.setRotation(3); 
  ts.setRotation(1); 
  clockFace();
  for(int buttNum = 0; buttNum < 4; buttNum ++)
  {
    drawButton(buttNum);
  }
  rangeAvg.begin();
}

void loop()
{
  checkTouchData();
  static int lastSec = 99;
  if (lastSec != second())
  {
    lastSec = second();
    digitalClockDisplay();  
  }
  static int lastSel = 99;
  if (lastSel != buttSel)
  {
    lastSel = buttSel;
    for(int buttNum = 0; buttNum < 4; buttNum ++)
    {
      drawButton(buttNum);
    }
  }
  unsigned long lastShortTime = 0;
  if ((millis() - lastShortTime) > 200)
  {
    getRange();
    lastShortTime = millis();
  }
}

void checkTouchData()
{
  if (!ts.bufferEmpty())
  {   
    // Retrieve a point  
    TS_Point p = ts.getPoint(); 
    // Scale using the calibration #'s
    // and rotate coordinate system
    int x = map(p.x, TS_MINX, TS_MAXX, 0, tft.width());
    int y = map(p.y, TS_MINY, TS_MAXY, 0, tft.height());
    if((x > buttX) && (x < (buttX + buttWid)))
    {
      for(int buttNum = 0; buttNum < 4; buttNum ++)
      {
        if(buttSel != buttNum)
        {
          if((y > buttY[buttNum]) && (y < (buttY[buttNum] + buttHgt)))
          {
            buttSel = buttNum;
          }
        }
      }
    }
  }
}

void drawButton(int buttNum)
{
  tft.setCursor((buttX + 12) , (buttY[buttNum] + 12));
  tft.setTextSize(2);
  if(buttNum != buttSel)
  {
    tft.fillRoundRect(buttX, buttY[buttNum], buttWid, buttHgt, buttRnd, ILI9341_BLACK); // Auto
    tft.setTextColor(buttColor[buttNum]);
  }
  else
  {
    tft.fillRoundRect(buttX, buttY[buttNum], buttWid, buttHgt, buttRnd, buttColor[buttNum]); // Auto
    tft.setTextColor(ILI9341_BLACK);
  }
  tft.println(buttText[buttNum]);
  tft.drawRoundRect(buttX, buttY[buttNum], buttWid, buttHgt, buttRnd, ILI9341_WHITE); // Auto
}

void clockFace()
{
  int circCentX = 120;
  int circCentY = 120;
  int circRad1 = 90;
  int circRad2 = 100;
  tft.fillCircle(circCentX, circCentY, circRad2, ILI9341_BLACK);
  tft.drawCircle(circCentX, circCentY, circRad1, ILI9341_WHITE);
  tft.drawCircle(circCentX, circCentY, circRad2, ILI9341_WHITE);
  for(int i = 0; (i < 12); i ++)
  {
    int endX = circCentX + circRad2 * sin(i * 2 * PI / 12);
    int endY = circCentY - circRad2 * cos(i * 2 * PI / 12);
    tft.drawLine(circCentX, circCentY, endX, endY, ILI9341_WHITE);
  }
  tft.fillRect((circCentX - circRad2), (circCentY - 2), (circRad2 * 2), (5), ILI9341_YELLOW);
  tft.fillRect((circCentX - 2), (circCentY - circRad2), (5), (circRad2 * 2), ILI9341_YELLOW);
  tft.fillCircle(circCentX, circCentY, circRad1 - 1, ILI9341_BLACK);
}

void secondHand(int sec)
{
  int circCentX = 120;
  int circCentY = 120;
  int circRad1 = 90;
//  if(sec < 60) // ** single line
  if(sec == 0) // ** fills face **
  {
    tft.fillCircle(circCentX, circCentY, circRad1 - 1, ILI9341_BLACK);
  }
  int endX = circCentX + (circRad1 - 1) * sin(sec * 2 * PI / 60);
  int endY = circCentY - (circRad1 - 1) * cos(sec * 2 * PI / 60);
  if(buttSel == 3)
  {
    tft.drawLine(circCentX, circCentY, endX, endY, buttColor[autClr(range)]);
    tft.fillCircle(circCentX, circCentY, 25, ILI9341_BLACK);
    tft.fillCircle(circCentX, circCentY, 20, buttColor[autClr(range)]);
  }
  else
  {
    tft.drawLine(circCentX, circCentY, endX, endY, buttColor[buttSel]);
    tft.fillCircle(circCentX, circCentY, 25, ILI9341_BLACK);
    tft.fillCircle(circCentX, circCentY, 20, buttColor[buttSel]);
  }
  tft.setCursor((circCentX - 11), (circCentY - 7));
  tft.setTextColor(ILI9341_BLACK);
  tft.setTextSize(2);
  printCentSec(second());
  tft.println();
}

void digitalClockDisplay() {
  tft.setCursor(184, 6);
  tft.setTextColor(ILI9341_WHITE, ILI9341_NAVY);
  tft.setTextSize(2);
  int disHour = hour();
  if(hour() == 0) disHour = 12;
  else if(hour() >12) disHour = hour() - 12;
  if(disHour < 10) tft.print(" ");
  tft.print(disHour);
  printDigits(minute());
  printDigits(second());
  if (hour() > 12) tft.print(" PM");
  else tft.print(" AM");
  //tft.print(" ");
  tft.println(); 
  tft.setCursor(220, 22);
  tft.print(month());
  tft.print("/");
  tft.print(day());
  tft.print("/");
  tft.print(year() - 2000); 
  tft.println(); 
  secondHand(second());
}

time_t getTeensy3Time()
{
  return Teensy3Clock.get();
}

void printDigits(int digits){
  // utility function for digital clock display: prints preceding colon and leading 0
  tft.print(":");
  if(digits < 10)
    tft.print('0');
  tft.print(digits);
}

void printCentSec(int digits)
{
  // utility function for center second display: prints leading 0
  if(digits < 10)
    tft.print('0');
  tft.print(digits);
}

void getRange()
{
  //added from vl6180x
  range = vl.readRange();
  range = rangeAvg.reading(range);
  uint8_t status = vl.readRangeStatus();
// dispRangeTxt
  tft.setCursor(6, 3);
  tft.setTextColor(ILI9341_WHITE, ILI9341_NAVY);
  tft.print(range); 
  tft.println(" MM  ");
// limit range
  if(range > 180) range = 180;
  barGrHrz(range);
}
void barGrHrz(int val)
{
  int xPos = 30, yPos = 223, xLen = 180, yLen = 16;
  tft.fillRect((xPos + val),  yPos, (xLen - val), yLen, (CL(32, 32, 32))); // darker grey
  tft.fillRect(xPos,  yPos, val, yLen, buttColor[autClr(val)]);
  tft.drawRect((xPos - 1), (yPos - 1), (xLen + 1), (yLen + 1), 0xFFFF); // white
}
int autClr(int val)
{
  int clr = 0;
  int sp[] = {50, 100, 150};
  if(val <= sp[0]) clr = 0;
  else if((sp[0] < val) &&(val <= sp[1])) clr = 1;
  else if((sp[1] < val) &&(val <= sp[2])) clr = 2;
  else  clr = 3;
  return clr;
}

IMG_0740 (1).jpg
Thanks
Rocky
 
Thanks BriComp!

I'll try that this afternoon.

Can you help me understand what the argument (&Wire2) does exactly? Or can you point me to some resource that might explain it?

Thanks again!
 
See 'Adafruit_VL6180X.h' for the prototype of the begin() function:
Code:
boolean begin(TwoWire *theWire = &Wire)
So, it defaults to using Wire, but that can be overridden by supplying a pointer to a different TwoWire object.
 
I think @gfvalvo said it before I got back.
You also do not need the other Wire stuff in setup.
Code:
/*
  Wire.setSCL(24); // SCL2 on third i2c bus on T4.1
  Wire.setSDA(25); // SDA2 on third i2c bus on T4.1
  Wire.begin();
*/
  vl.begin(&Wire2);   //Pass over the pointer to the relevant Wire channel - vl (Adafruit_VL6180X.) will do the rest

Wire addresses the first I2C bus (I2C),
Wire1 the second (I2C1) and
Wire2 the third (I2C2).
 
I think @gfvalvo said it before I got back.
You also do not need the other Wire stuff in setup.
Code:
/*
  Wire.setSCL(24); // SCL2 on third i2c bus on T4.1
  Wire.setSDA(25); // SDA2 on third i2c bus on T4.1
  Wire.begin();
*/
  vl.begin(&Wire2);   //Pass over the pointer to the relevant Wire channel - vl (Adafruit_VL6180X.) will do the rest

Wire addresses the first I2C bus (I2C),
Wire1 the second (I2C1) and
Wire2 the third (I2C2).

Side notes here:
I believe Wire2 only has one set of valid pins 24 and 25 which it defaults to, so you don't need to do a setSCL or setSDA.

Also if it did have multiple valid pins like Wire1 on T4.1 has SCL with two possible pins (17, 44) and SDA (16, 45)
Where the defaults as 16, 17... In these cases if I wanted to use pins 44 and 45 I do need to tell the system to use those pins.

In this case you would do:
Code:
Wire1.setSCL(44);
Wire1.setSDA(45);
Note You use the Wire1 object in this case, not the Wire object.

Also unclear if you will need to do a Wire1.begin()... The Adafruit class may do that internal.. But probably does not hurt to do so.
 
Also unclear if you will need to do a Wire1.begin()... The Adafruit class may do that internal.. But probably does not hurt to do so.
It does do the necessary begin(&wire). I downloaded the code too ensure that before giving my recommendation.
 
Here is a snippet of the Adafruit LV6180X code:
Code:
/**************************************************************************/
/*!
    @brief  Initializes I2C interface, checks that VL6180X is found and resets
   chip.
    @param  theWire Optional pointer to I2C interface, &Wire is used by default
    @returns True if chip found and initialized, False otherwise
*/
/**************************************************************************/ 
boolean Adafruit_VL6180X::begin(TwoWire *theWire) {
  // only needed to support setAddress()
  _i2c = theWire;

  if (i2c_dev)
    delete i2c_dev;
  i2c_dev = new Adafruit_I2CDevice(_i2caddr, _i2c);
  if (!i2c_dev->begin())
    return false;

  // check for expected model id
  if (read8(VL6180X_REG_IDENTIFICATION_MODEL_ID) != 0xB4) {
    return false;
  }

  // fresh out of reset?
  if (read8(VL6180X_REG_SYSTEM_FRESH_OUT_OF_RESET) & 0x01) {
    loadSettings();
    write8(VL6180X_REG_SYSTEM_FRESH_OUT_OF_RESET, 0x00);
  }

  return true;
}
As it says in the comments it uses the I2C Wire address (Pointer) you supply (&Wire1 or &Wire2). If no address (Pointer) is supplied it defaults to Wire.
 
See 'Adafruit_VL6180X.h' for the prototype of the begin() function:
Code:
boolean begin(TwoWire *theWire = &Wire)
So, it defaults to using Wire, but that can be overridden by supplying a pointer to a different TwoWire object.

Thanks! I don't really understand all the syntax of that line, but I suppose that knowledge will eventually trickle into my brain. There is lot to learn about this hobby. So far, it's been great.
 
Thanks KurtE! Side notes are good.

Thanks BriComp! My brain is full for now. All this will make more sense to me in time. I think you've given me everything that I need to know about it. :)
 
Status
Not open for further replies.
Back
Top