I am trying to set up I²C communications between two Adafruit TOF sensors VL6180X on nucleo STM32F466RE board. I am using cubeMX and VS code and also helps with the VL6180X API on x-nucleo-6180xa1 from ST website, I want to set this up so I can test both of the sensors separately. So far I succeeded to measure only one sensor but when I'm trying to connected both of the sensors to the SHDN to the GPIO on the nucleo STM32F466RE I having problems. I am trying to manage some master slave operation but I am new in this stuff does any one know how to?
What I am looking for is example code so I can see how it is implemented. This is not a production run, but for my home use. The goal to manage on this two TOF sensors, I have not been able to find any code to study.
That's my main code:
/* Private variables ---------------------------------------------------------*/
I2C_HandleTypeDef hi2c1;
UART_HandleTypeDef huart2;
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_I2C1_Init(void);
static void MX_USART2_UART_Init(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
void WaitMilliSec(int ms);
VL6180xDev_t theVL6180xDev;
struct MyVL6180Dev_t BoardDevs[2] = {
[0]= { .DevID = 0 },
[1]= { .DevID = 1 }
};
VL6180xDev_t theVL6180xDev = &BoardDevs[0];
/**
* VL6180x CubeMX F401 multiple device i2c implementation
*/
#define i2c_bus (&hi2c1)
#define def_i2c_time_out 100
int VL6180x_I2CWrite(VL6180xDev_t dev, uint8_t *buff, uint8_t len) {
int status;
status = HAL_I2C_Master_Transmit(i2c_bus, dev->I2cAddr, buff, len, def_i2c_time_out);
if (status) {
HAL_I2C_MspInit(&hi2c1);
}
return status? -1 : 0;
}
int VL6180x_I2CRead(VL6180xDev_t dev, uint8_t *buff, uint8_t len) {
int status;
status = HAL_I2C_Master_Receive(i2c_bus, dev->I2cAddr, buff, len, def_i2c_time_out);
if (status) {
HAL_I2C_MspInit(&hi2c1);
}
return status? -1 : 0;
}
void WaitMilliSec(int ms) {
HAL_Delay(ms); /* it's milli sec cos we do set systick to 1KHz */
}
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
#define MAX_DEV 1
VL6180x_RangeData_t Range[MAX_DEV];
int status;
int i;
int n_dev=1;
int PresentDevMask;
int nPresentDevs;
int PresentDevIds[MAX_DEV];
int nReady;
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_I2C1_Init();
MX_USART2_UART_Init();
/* USER CODE BEGIN 2 */
/* detect presence and initialize devices i2c address */
/*set device i2c address for dev[i] = 0x52+(i+1)*2 */
PresentDevMask = 0;
nPresentDevs = 0;
//strcpy(DisplayStr,"TLBR");
for (i = 0; i <= n_dev; i++){
int FinalI2cAddr;
uint8_t id;
/* unreset device that wake up at default i2c addres 0x52 */
WaitMilliSec(2); /* at least 400usec before to acces device */
BoardDevs[i].I2cAddr = 0x52;
/* to detect device presence try to read it's dev id */
status = VL6180x_RdByte(&BoardDevs[i], IDENTIFICATION_MODEL_ID, &id);
if (status) {
/* these device is not present skip init and clear it's letter on string */
BoardDevs[i].Present = 0;
//DisplayStr[i]=' ';
continue;
}
/* device present only */
BoardDevs[i].Present = 1;
PresentDevMask |= 1 << i;
PresentDevIds[nPresentDevs]=i;
nPresentDevs++;
status = VL6180x_InitData(&BoardDevs[i]);
FinalI2cAddr = 0x52 + ((i+1) * 2);
if (FinalI2cAddr != 0x52) {
status = VL6180x_SetI2CAddress(&BoardDevs[i], FinalI2cAddr);
if( status ){
//HandleError("VL6180x_SetI2CAddress fail");
}
BoardDevs[i].I2cAddr = FinalI2cAddr;
}
WaitMilliSec(1);
status = VL6180x_RdByte(&BoardDevs[i], IDENTIFICATION_MODEL_ID, &id);
WaitMilliSec(1);
status= VL6180x_Prepare(&BoardDevs[i]);
if( status<0 ){
//HandleError("VL6180x_Prepare fail");
}
/* Disable Dmax computation */
VL6180x_DMaxSetState(&BoardDevs[i], 0);
}
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
VL6180xDev_t dev;
/*
VL6180x_RangePollMeasurement(dev, &Range[0]);
HAL_Delay(20);
*/
// kick off measure on all device
for( i=0; i<nPresentDevs; i++){
dev = BoardDevs + PresentDevIds[i];
//TODO: GPIO enamble of pa11
status = VL6180x_RangeStartSingleShot(dev);
if( status<0 ){
//HandleError("VL6180x_RangeStartSingleShot fail");
}
dev->Ready=0;
}
// wait for all present device to have a measure
nReady=0;
do{
//DISP_ExecLoopBody();
for( i=0; i<nPresentDevs; i++){
dev = BoardDevs + PresentDevIds[i];
if( !dev->Ready ){
status = VL6180x_RangeGetMeasurementIfReady(dev, &Range[i]);
if( status == 0 ){
if(Range[i].errorStatus == DataNotReady)
continue;
// New measurement ready
dev->Ready=1;
nReady++;
} else {
//HandleError("VL6180x_RangeStartSingleShot fail");
}
}
}
}
while( nReady<nPresentDevs);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
...
I solved my problem. As you may know, for a few Adafruit TOF VL6180X sensors to work together they must be connected from their SHDN to the GPIO on the board. What was infact missing is the RESET for all the sensors and SET for these sensors with their addresses. One of the problems I had encountered with, while finding the solution is the order of commands. It's important to notice that we RESET all the sensors at first and SET after we assigned their addresses. The correction to the code is attached if you're interested as well. You can see the if query, in the code that's depended on a variable i in the loop in order to separate the two sensors. I've done it just so I could find the specific component. There's a smarter way to do it, it's just for understanding the order of commands.
see my solution in comments:
<<<<-------------------------RESET-----
<<<<-------------------------SET-----
/* USER CODE BEGIN PV */
// global vars only for debugging with STMStudio
VL6180x_RangeData_t Range[MAX_DEV];
VL6180x_RangeData_t RangeDB1;
VL6180x_RangeData_t RangeDB2;
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_I2C1_Init(void);
static void MX_USART2_UART_Init(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
void WaitMilliSec(int ms);
VL6180xDev_t theVL6180xDev;
struct MyVL6180Dev_t BoardDevs[MAX_DEV] = {
[0]= { .DevID = 0 },
[1]= { .DevID = 1 },
};
VL6180xDev_t theVL6180xDev = &BoardDevs[0];
/**
* VL6180x CubeMX F401 multiple device i2c implementation
*/
#define i2c_bus (&hi2c1)
#define def_i2c_time_out 100
int VL6180x_I2CWrite(VL6180xDev_t dev, uint8_t *buff, uint8_t len) {
int status;
status = HAL_I2C_Master_Transmit(i2c_bus, dev->I2cAddr, buff, len, def_i2c_time_out);
if (status) {
HAL_I2C_MspInit(&hi2c1);
}
return status? -1 : 0;
}
int VL6180x_I2CRead(VL6180xDev_t dev, uint8_t *buff, uint8_t len) {
int status;
status = HAL_I2C_Master_Receive(i2c_bus, dev->I2cAddr, buff, len, def_i2c_time_out);
if (status) {
HAL_I2C_MspInit(&hi2c1);
}
return status? -1 : 0;
}
void WaitMilliSec(int ms) {
HAL_Delay(ms); /* it's milli sec cos we do set systick to 1KHz */
}
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
int status;
int i;
int n_dev=2;
int PresentDevMask;
int nPresentDevs;
int PresentDevIds[MAX_DEV];
int nReady;
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
// here I put all my devices under reset <<<<-------------------------RESET-----
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_11, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_12, GPIO_PIN_RESET);
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_I2C1_Init();
MX_USART2_UART_Init();
/* USER CODE BEGIN 2 */
/* detect presence and initialize devices i2c address */
/*set device i2c address for dev[i] = 0x52+(i+1)*2 */
PresentDevMask = 0;
nPresentDevs = 0;
//strcpy(DisplayStr,"TLBR");
for (i = 0; i <= n_dev - 1; i++) {
int FinalI2cAddr;
uint8_t id;
// here I put all my devices under set <<<<-------------------------SET-----
if (i==0){
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_11, GPIO_PIN_SET);
}
if (i==1){
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_12, GPIO_PIN_SET);
}
/* unreset device that wake up at default i2c addres 0x52 */
WaitMilliSec(2); /* at least 400usec before to acces device */
BoardDevs[i].I2cAddr = 0x52;
/* to detect device presence try to read it's dev id */
status = VL6180x_RdByte(&BoardDevs[i], IDENTIFICATION_MODEL_ID, &id);
if (status) {
/* these device is not present skip init and clear it's letter on string */
/*we can add here some debug prints*/
//BoardDevs[i].Present = 0;
//DisplayStr[i]=' ';
continue;
}
/* device present only */
BoardDevs[i].Present = 1;
PresentDevMask |= 1 << i;
PresentDevIds[nPresentDevs]=i;
nPresentDevs++;
status = VL6180x_InitData(&BoardDevs[i]);
FinalI2cAddr = 0x52 + ((i+1) * 2);
if (FinalI2cAddr != 0x52) {
status = VL6180x_SetI2CAddress(&BoardDevs[i], FinalI2cAddr);
if( status ){
//HandleError("VL6180x_SetI2CAddress fail");
}
BoardDevs[i].I2cAddr = FinalI2cAddr;
}
WaitMilliSec(1);
status = VL6180x_RdByte(&BoardDevs[i], IDENTIFICATION_MODEL_ID, &id);
WaitMilliSec(1);
status= VL6180x_Prepare(&BoardDevs[i]);
if( status<0 ){
//HandleError("VL6180x_Prepare fail");
}
/* Disable Dmax computation */
VL6180x_DMaxSetState(&BoardDevs[i], 0);
}
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
VL6180xDev_t dev;
// kick off measure on all device
for( i=0; i<nPresentDevs; i++){
dev = BoardDevs + PresentDevIds[i];
status = VL6180x_RangeStartSingleShot(dev);
if( status<0 ){
//TODO: print error : debug
}
dev->Ready=0;
}
// wait for all present device to have a measure
nReady=0;
do{
//DISP_ExecLoopBody();
for( i=0; i<nPresentDevs; i++){
dev = BoardDevs + PresentDevIds[i];
if( !dev->Ready ){
status = VL6180x_RangeGetMeasurementIfReady(dev, &Range[i]);
if (i==0)
RangeDB1 = Range[i];
if (i==1)
RangeDB2 = Range[i];
if( status == 0 ){
if(Range[i].errorStatus == DataNotReady)
continue;
// New measurement ready
dev->Ready=1;
nReady++;
} else {
//HandleError("VL6180x_RangeStartSingleShot fail");
}
}
}
}
while( nReady<nPresentDevs);
HAL_Delay(10);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}