cancel
Showing results for 
Search instead for 
Did you mean: 

Unreasonable Data from VL53L8CX Sensor

kgb
Associate III

Hello Everyone,

I am currently using the vl53lmz_uld_api  tto process data measured by the VL53L8CX sensor. I have also used the "example_12_cnh_data" to retrieve data from my sensor. However, the incoming data seems completely incorrect, and I don't know where the issue lies. When I hold my sensor 20-25 cm in front of an obstacle, I receive highly unreasonable data:

Zone :  40, Status :   0, Distance : 1383 mm

Zone :  41, Status :  13, Distance : 1892 mm

Zone :  42, Status :   5, Distance : 1371 mm

Zone :  43, Status :   5, Distance : 1367 mm

Zone :  44, Status :   5, Distance : 1347 mm

Zone :  45, Status :   5, Distance : 1370 mm

Zone :  46, Status :   5, Distance : 2448 mm

Zone :  47, Status :   9, Distance : 2262 mm

Zone :  48, Status :   4, Distance : 2977 mm

Zone :  49, Status :   0, Distance : 1398 mm

Zone :  50, Status :   5, Distance : 1381 mm

 

 

Can someone please help me to understand what i am doing wrong  here is my main.c: 

int main(void)
{
  /* USER CODE BEGIN 1 */

  /* 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_DMA_Init();
  MX_USART2_UART_Init();
  /* USER CODE BEGIN 2 */
 // UartComm_Restart();

  //__________MY CODE ___________

 p_dev.platform.address = 0x52;


 Reset_Sensor();

 if (status != VL53LMZ_STATUS_OK){
 		printf("vl53lmz_init failed : %d\n");
 		return status;
 	}

	/* (Mandatory) Initialise the VL53LMZ sensor */
	status = vl53lmz_init(&p_dev);
	if(status)
	{
		printf("VL53LMZ ULD Loading failed\n");
		return status;
	}

	printf("VL53LMZ ULD ready ! (Version : %s)\n",
			VL53LMZ_API_REVISION);

	status = vl53lmz_set_resolution(&p_dev, 64);
	status |= vl53lmz_set_ranging_mode(&p_dev, VL53LMZ_RANGING_MODE_AUTONOMOUS);
	status |= vl53lmz_set_ranging_frequency_hz(&p_dev, 5);
	status |= vl53lmz_set_integration_time_ms(&p_dev, 20);
	if(status)
	{
		printf("ERROR - Failed basic configuration sequence, status=%u\n", status);
		return status;
	}

	status = vl53lmz_cnh_init_config( &cnh_config,
											0,		/* StartBin 	*/
											18,		/* NumBins   	*/
											1);	/* SubSample 	*/

	if (status != VL53LMZ_STATUS_OK){
			printf("VL53LMZ CNH init config failed\n");
			return status;
		}

	status = vl53lmz_cnh_create_agg_map( &cnh_config,
												64,				/* Resolution. Must match value used in vl53lmz_set_resolution() */
												0,				/* StartX 		*/
												0,				/* StartY 		*/
												1,				/* MergeX		*/
												1,				/* MergeY		*/
												8,				/* Cols			*/
												8 );			/* Rows 		*/

	if (status != VL53LMZ_STATUS_OK){
			printf("VL53LMZ CNH set aggregate map failed\n");
			return status;
		}

	status = vl53lmz_cnh_calc_required_memory( &cnh_config, &cnh_data_size );
	if (status != VL53LMZ_STATUS_OK){
		printf("VL53LMZ CNH calc required memory failed\n");
		if (cnh_data_size < 0){
			printf("Required memory is too high : %d. Maximum is %d!\n", (int)-cnh_data_size, (int)VL53LMZ_CNH_MAX_DATA_BYTES);
		}
		return status;
	}


	/* Send this CNH configuration to the sensor.										*/
	status = vl53lmz_cnh_send_config(&p_dev,&cnh_config);
	if (status != VL53LMZ_STATUS_OK){
		printf("VL53LMZ CNH send config failed\n");
		return status;
	}

	/* First create the standard data upload(output) configuration. 						*/
	status = vl53lmz_create_output_config(&p_dev);
	if (status != VL53LMZ_STATUS_OK){
		printf("VL53LMZ CNH create output config failed\n");
		return status;
	}

	/* Next, add the CNH data block, sized correctly for the configuration we are using. */
	union Block_header cnh_data_bh;
	cnh_data_bh.idx = VL53LMZ_CNH_DATA_IDX;
	cnh_data_bh.type = 4;
	cnh_data_bh.size = cnh_data_size / 4;
	status = vl53lmz_add_output_block(&p_dev, cnh_data_bh.bytes);
	if (status != VL53LMZ_STATUS_OK){
		printf("VL53LMZ CNH add output block failed\n");
		return status;
	}

	status = vl53lmz_send_output_config_and_start(&p_dev);

	   	printf("Started ranging\n");



  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
	   	while (1)

	   	{

	   		   		// __________________ MY CODE _______________
	   		   	    uint8_t buffer[512];
	   		   	    uint8_t *ptr = buffer;
	   		   	    size_t buffer_index = 0;  // To keep track of the actual size of the data

	   		   	    status = vl53lmz_check_data_ready(&p_dev, &isReady);
	   		   	    if (isReady)
	   		   	    {
	   		   	        vl53lmz_get_ranging_data(&p_dev, &Results);

	   		   	        printf("Print data no : %3u\n", p_dev.streamcount);
	   		   	        for (i = 0; i < 64; i++)
	   		   	        {


	   		   	            uint16_t zone = i;
	   		   	            uint16_t distance = Results.distance_mm[VL53LMZ_NB_TARGET_PER_ZONE * i];
                            /*
	   		   	            memcpy(ptr + buffer_index, &zone, sizeof(uint16_t));
	   		   	            buffer_index += sizeof(uint16_t);
	   		   	            memcpy(ptr + buffer_index, &distance, sizeof(uint16_t));
	   		   	            buffer_index += sizeof(uint16_t);
                             */
	   		   	           printf("Zone : %3d, Status : %3u, Distance : %4d mm\n",
	   		   	                   i,
	   		   	                   Results.target_status[VL53LMZ_NB_TARGET_PER_ZONE * i],
	   		   	                   distance);
	   		   	        }

	   		   	        status = vl53lmz_results_extract_block(&p_dev, VL53LMZ_CNH_DATA_IDX, (uint8_t *)cnh_data_buffer, cnh_data_size);
	   		   	        if (status != VL53LMZ_STATUS_OK)
	   		   	        {
	   		   	            printf("ERROR at %s(%d) : vl53lmz_results_extract_block failed : %d\n", __func__, __LINE__, status);
	   		   	            return status;
	   		   	        }

	   		   	        for (agg_id = 0; agg_id < cnh_config.nb_of_aggregates; agg_id++)
	   		   	        {
	   		   	            vl53lmz_cnh_get_block_addresses(&cnh_config,
	   		   	                                            agg_id,
	   		   	                                            cnh_data_buffer,
	   		   	                                            &(p_hist), &(p_hist_scaler),
	   		   	                                            &(p_ambient), &(p_ambient_scaler));

	   		   	            amb_value = ((float)*p_ambient) / (2 << *p_ambient_scaler);

	   		   	            printf("Agg, %2d, Ambient, % .1f, Bins, ", agg_id, amb_value);

	   		   	            for (bin_num = 0; bin_num < cnh_config.feature_length; bin_num++)
	   		   	            {
	   		   	                bin_value = ((float)p_hist[bin_num]) / (2 << p_hist_scaler[bin_num]);
	   		   	                printf("% .1f, ", bin_value);
	   		   	            }
                             /*
	   		   	            uint16_t Agg_id = agg_id;
	   		   	            float ambient = amb_value;
	   		   	            float bins_val = bin_value;

	   		   	            memcpy(ptr + buffer_index, &Agg_id, sizeof(uint16_t)); buffer_index += sizeof(uint16_t);
	   		   	            memcpy(ptr + buffer_index, &ambient, sizeof(float));  buffer_index += sizeof(float);
	   		   	            memcpy(ptr + buffer_index, &bins_val, sizeof(float)); buffer_index += sizeof(float);
                              */
	   		   	            // Now transmit only the actual data in the buffer
	   		   	            //HAL_UART_Transmit(&huart2, sizeof(buffer) , buffer, HAL_MAX_DELAY) ;

	   		   	            printf("\n");
	   		   	        }

	   		   	        loop++;
	   		   	    }

	   		   	    // Wait a few ms to avoid too high polling
	   		   	   // WaitMs(&(p_dev.platform), 5);
	   		   	    HAL_MAX_DELAY;
	   		   	}




}
1 ACCEPTED SOLUTION

Accepted Solutions
RogerM
ST Employee

As John says for now just look at zones which have status == 5.
With regards the range data you are printing out.... in the platform.h file do you have the following line active or commented out?

      #define VL53LMZ_USE_RAW_FORMAT

If this is present the driver returns the raw range value which includes 2 fractional bits ...which means the raw value must be divided by 4 to get the actual range in mm.

Please look at the code within vl53lmz_get_ranging_data() which is conditional on the VL53LMZ_USE_RAW_FORMAT define.   Depending on if this is defined or not it either does, or does not,  convert from "raw" to real values.

View solution in original post

15 REPLIES 15
John E KVAM
ST Employee

you need one other thing in your printout. 

The algo for knowing you have a target is:

if Number_of_targets > 0 AND the target status is either 5, 6, or 9, THEN you have a target.

The return array is NOT cleared before ranging, so there is potentially a lot of junk in it. 

Now if you are still not getting good data, we have a problem.

One test is to use a white sheet of paper. Hold that at 30cm or so. A nice reflective target should give you great results. 

An object as small as your hand should range to about 60 or 70cm, then there are not enough photons returning. 

If that is not giving you good results, give us a picture of your project, maybe I can see something. 

Do you have coverglass that is not optically clear? Do you have any structure in the way?

There is something wrong with the physical setup.

- john


If this or any post solves your issue, please mark them as 'Accept as Solution' It really helps. And if you notice anything wrong do not hesitate to 'Report Inappropriate Content'. Someone will review it.

Hallo  @John E KVAM ,

Thanks for your help. Unfortunately, your suggestions didn’t resolve the issue, and  marking the post as “solution” was a mistake.

To clarify:

  • I don’t have any cover glass or physical obstruction in front of the sensor.

  • The sensor is consistently returning a status of "5", but I’m getting wrong or unreliable distance data.

  • I also can’t access the nb_target_detected field in VL53LMZ_ResultsData, even though I have disabled the VL53LMZ_DISABLE_NB_TARGET_DETECTED macro in my platform.h.

At this point, I’m a bit stuck, so I’ll post my full main.c below for context  maybe I’m missing something obvious. Any help is much appreciated!

 

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2022 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>


/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <string.h>
#include <vl53lmz_api.h>
#include "vl53lmz_plugin_cnh.h"



/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
I2C_HandleTypeDef hi2c1;

UART_HandleTypeDef huart2;
DMA_HandleTypeDef hdma_usart2_tx;

/* USER CODE BEGIN PV */
volatile int IntCount;

// ________ MY CODE _________________
VL53LMZ_Configuration  p_dev ;
uint8_t 				status, loop, isAlive, isReady, i;
	VL53LMZ_ResultsData 	Results;				/* Results data from VL53LMZ */

	VL53LMZ_Motion_Configuration 	cnh_config;		/* Motion Configuration is shared with CNH */

	cnh_data_buffer_t 		cnh_data_buffer;		/* cnh_data_bufer_t is sized to take the largest data transfer  */
													/* possible from the device. If smaller CNH configuration is 	*/
													/* used then cnh_data_buffer size could be make smaller.		*/

	uint32_t 				cnh_data_size;			/* This will be used to record the actual size of CNH data 		*/
													/* generated by the set CNH configuration.						*/

	int agg_id, bin_num;
	float amb_value, bin_value;

	/* variables needed for call to vl53lmz_cnh_get_mem_block_addresses() */
	int32_t					*p_hist = NULL;
	int8_t					*p_hist_scaler = NULL;
	int32_t					*p_ambient = NULL;
	int8_t					*p_ambient_scaler = NULL;

//_______________ MY CODE __________________________________

/* 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_DMA_Init(void);
static void MX_USART2_UART_Init(void);
/* USER CODE BEGIN PFP */
extern int mz_ai_main(void);
/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
	if (GPIO_Pin==INT_C_Pin)
	{
		IntCount++;
	}
}

int check_for_gpio_interrupt(void)
{
	if(IntCount != 0) {
		IntCount = 0;
		return 1;
	}
	return 0;
}



//https://electronics.stackexchange.com/questions/206113/how-do-i-use-the-printf-function-on-stm32
__attribute__((weak)) int __io_getchar(void)
{
	int ch = 0;
    HAL_StatusTypeDef status = HAL_UART_Receive(&huart2, (uint8_t *)&ch, 1, 0xFFFF);
    return (status == HAL_OK ? ch : 0);
}


__attribute__((weak)) int __io_putchar(int ch)
{
    HAL_StatusTypeDef status;
    do {
    	status = HAL_UART_Transmit_DMA(&huart2, (uint8_t *)&ch, 1);
    } while ( status == HAL_BUSY );
    return (status == HAL_OK ? ch : 0);
}

// _read() and _write() copied from STM32 syscalls.c file (which Cube.MX insists on removing from project).
__attribute__((weak)) int _read(int file, char *ptr, int len)
{
	int DataIdx;

	for (DataIdx = 0; DataIdx < len; DataIdx++)
	{
		*ptr++ = __io_getchar();
	}

return len;
}

__attribute__((weak)) int _write(int file, char *ptr, int len)
{
	int DataIdx;

	for (DataIdx = 0; DataIdx < len; DataIdx++)
	{
		__io_putchar(*ptr++);
	}
	return len;
}





// custom function to send a single large block of data to UART via DMA
void wait_for_dma_to_complete( void )
{
    HAL_StatusTypeDef status;
    do {
    	status = HAL_UART_Transmit_DMA(&huart2, NULL, 0);
    } while ( status == HAL_BUSY );
	return;
}

int dma_write_block(char *ptr, int len)
{
    HAL_StatusTypeDef status;
    wait_for_dma_to_complete();
   	status = HAL_UART_Transmit_DMA(&huart2, (uint8_t *)ptr, len);
   	return (status == HAL_OK ? len : 0);;
}


// Code to enable receiving data through the UART: Host->STM32
/*
#define UART_BUFFER_SIZE    2048
volatile char Uart_RXBuffer[UART_BUFFER_SIZE];
char UartComm_RXBuffer[UART_BUFFER_SIZE];
int UartComm_RXSize = 0;
volatile size_t Uart_RxRcvIndex = 0;
volatile uint32_t Uart_nOverrun = 0;
volatile int UartComm_CmdReady = 0;
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	if (Uart_RXBuffer[Uart_RxRcvIndex] == '\r'
				|| Uart_RXBuffer[Uart_RxRcvIndex] == '\n'
				|| Uart_RXBuffer[Uart_RxRcvIndex] == '\x03') //Ctrl-C)
	{

		if (Uart_RXBuffer[Uart_RxRcvIndex] != '\x03') // \x0x3 is Ctrl-c
    		Uart_RXBuffer[Uart_RxRcvIndex] = 0;

		memcpy(UartComm_RXBuffer ,
				(char*)Uart_RXBuffer,
				Uart_RxRcvIndex+1 ); //copy ending 0
        UartComm_RXSize = Uart_RxRcvIndex;
		UartComm_CmdReady = 1;

		Uart_RxRcvIndex = 0;
	}
	else
	{
		if (Uart_RxRcvIndex < UART_BUFFER_SIZE)
		{
			Uart_RxRcvIndex++;
		}
		else
		{
			Uart_RxRcvIndex = 0;
			Uart_nOverrun++;
		}
	}

	HAL_UART_Receive_IT(huart,
					(uint8_t *) &Uart_RXBuffer[Uart_RxRcvIndex],
					1);
}

void UartComm_Restart() {
	HAL_UART_StateTypeDef State;
	UartComm_CmdReady = 0;
    Uart_RxRcvIndex = 0;

    State = HAL_UART_GetState(&huart2);
	if (State != HAL_UART_STATE_BUSY_TX_RX && State != HAL_UART_STATE_BUSY_RX) {
        // arm it
        HAL_UART_Receive_IT(&huart2, (uint8_t *) Uart_RXBuffer, 1);
    }
	UartComm_CmdReady = 0;
}

int UartComm_GetLineIfReceived( char **cmd_str ) {
	if ( UartComm_CmdReady == 0 ) {
		*cmd_str = NULL;
		return 0;
	}
	else {
		*cmd_str = UartComm_RXBuffer;
		return 1;
	}
}
*/
void Reset_Sensor(void)
{
#ifdef GPIO_FOR_LPn_PIN
	/* Set 0 to pin LPn = PB0 */
	HAL_GPIO_WritePin(LPn_GPIO_Port, LPn_Pin, GPIO_PIN_RESET);
#endif

#ifdef GPIO_FOR_PWR_EN
	/* Set 0 to pin PWR_EN = PB0 or PA7 */
	HAL_GPIO_WritePin(PWR_EN_GPIO_Port, PWR_EN_Pin, GPIO_PIN_RESET);
	HAL_Delay(100);

	/* Set 1 to pin PWR_EN */
	HAL_GPIO_WritePin(PWR_EN_GPIO_Port, PWR_EN_Pin, GPIO_PIN_SET);
	HAL_Delay(100);
#endif

#ifdef GPIO_FOR_LPn_PIN
	/* Set 1 to pin LPn */
	HAL_GPIO_WritePin(LPn_GPIO_Port, LPn_Pin, GPIO_PIN_SET);
#endif

	// If I2C master does not support "I2C bus clear" feature, need to toggle I2C_SPI_N pin to release I2C bus
	HAL_GPIO_WritePin(SPI_I2C_N_GPIO_Port, SPI_I2C_N_Pin, GPIO_PIN_RESET);
	HAL_Delay(1);
	HAL_GPIO_WritePin(SPI_I2C_N_GPIO_Port, SPI_I2C_N_Pin, GPIO_PIN_SET);
	HAL_Delay(1);
	HAL_GPIO_WritePin(SPI_I2C_N_GPIO_Port, SPI_I2C_N_Pin, GPIO_PIN_RESET);
	HAL_Delay(1);

	return;
}

/*
void HAL_UART_ErrorCallback(UART_HandleTypeDef * huart) {
    // clear error and  kick of next
    huart->ErrorCode = 0;
    HAL_UART_Receive_IT(huart, (uint8_t *) &Uart_RXBuffer[Uart_RxRcvIndex], Uart_RxRcvIndex);

}
*/
typedef struct {
	uint16_t zone_id [16];
	uint16_t distance[16];
	uint16_t Agg_id[16];
	float ambient[16] ;
	float bins_values[16][24];

} sensor_data;
/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* 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_DMA_Init();
  MX_USART2_UART_Init();
  /* USER CODE BEGIN 2 */
  //UartComm_Restart();

  //__________MY CODE ___________
  Reset_Sensor();
  p_dev.platform.address = VL53LMZ_DEFAULT_I2C_ADDRESS;




 if (status != VL53LMZ_STATUS_OK){
 		printf("vl53lmz_init failed : %d\n");
 		return status;
 	}

	/* (Mandatory) Initialise the VL53LMZ sensor */
	status = vl53lmz_init(&p_dev);
	if(status)
	{
		printf("VL53LMZ ULD Loading failed\n");
		return status;
	}

	printf("VL53LMZ ULD ready ! (Version : %s)\n",
			VL53LMZ_API_REVISION);

	status = vl53lmz_set_resolution(&p_dev, 16);
	status |= vl53lmz_set_ranging_mode(&p_dev, VL53LMZ_RANGING_MODE_AUTONOMOUS);
	status |= vl53lmz_set_ranging_frequency_hz(&p_dev, 5);
	status |= vl53lmz_set_integration_time_ms(&p_dev, 20);
	if(status)
	{
		printf("ERROR - Failed basic configuration sequence, status=%u\n", status);
		return status;
	}

	status = vl53lmz_cnh_init_config( &cnh_config,
											0,		/* StartBin 	*/
											24,		/* NumBins   	*/
											4);	/* SubSample 	*/

	if (status != VL53LMZ_STATUS_OK){
			printf("VL53LMZ CNH init config failed\n");
			return status;
		}

	status = vl53lmz_cnh_create_agg_map( &cnh_config,
												16,				/* Resolution. Must match value used in vl53lmz_set_resolution() */
												0,				/* StartX 		*/
												0,				/* StartY 		*/
												1,				/* MergeX		*/
												1,				/* MergeY		*/
												4,				/* Cols			*/
												4);			/* Rows 		*/

	if (status != VL53LMZ_STATUS_OK){
			printf("VL53LMZ CNH set aggregate map failed\n");
			return status;
		}

	status = vl53lmz_cnh_calc_required_memory( &cnh_config, &cnh_data_size );
	if (status != VL53LMZ_STATUS_OK){
		printf("VL53LMZ CNH calc required memory failed\n");
		if (cnh_data_size < 0){
			printf("Required memory is too high : %d. Maximum is %d!\n", (int)-cnh_data_size, (int)VL53LMZ_CNH_MAX_DATA_BYTES);
		}
		return status;
	}


	/* Send this CNH configuration to the sensor.										*/
	status = vl53lmz_cnh_send_config(&p_dev,&cnh_config);
	if (status != VL53LMZ_STATUS_OK){
		printf("VL53LMZ CNH send config failed\n");
		return status;
	}

	/* First create the standard data upload(output) configuration. 						*/
	status = vl53lmz_create_output_config(&p_dev);
	if (status != VL53LMZ_STATUS_OK){
		printf("VL53LMZ CNH create output config failed\n");
		return status;
	}

	/* Next, add the CNH data block, sized correctly for the configuration we are using. */
	union Block_header cnh_data_bh;
	cnh_data_bh.idx = VL53LMZ_CNH_DATA_IDX;
	cnh_data_bh.type = 4;
	cnh_data_bh.size = cnh_data_size / 4;
	status = vl53lmz_add_output_block(&p_dev, cnh_data_bh.bytes);
	if (status != VL53LMZ_STATUS_OK){
		printf("VL53LMZ CNH add output block failed\n");
		return status;
	}

	status = vl53lmz_send_output_config_and_start(&p_dev);

	   	printf("Started ranging\n");



  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
	   	while (1)

	   	{

	   		   		// __________________ MY CODE _______________

	   		   	    status = vl53lmz_check_data_ready(&p_dev, &isReady);
	   		   	    if (isReady)
	   		   	    {
	   		   	        vl53lmz_get_ranging_data(&p_dev, &Results);

	   		   	        printf("Print data no : %3u\n", p_dev.streamcount);
					  for (i = 0; i < 16; i++)
					  {
						 // uint8_t nb_targets = Results.nb_target_detected[i];
						  uint8_t status = Results.target_status[VL53LMZ_NB_TARGET_PER_ZONE * i];
						  uint16_t distance = Results.distance_mm[VL53LMZ_NB_TARGET_PER_ZONE * i];

						  if (VL53LMZ_NB_TARGET_PER_ZONE > 0 && (status == 5 || status == 6 || status == 9)) {
							  printf("Zone %2d: VALID TARGET! Distance = %4d mm, Status = %d\n", i, distance, status);
						  } else {
							  printf("Zone %2d: No valid target\n", i);
					  }
					 }


	   		   	        status = vl53lmz_results_extract_block(&p_dev, VL53LMZ_CNH_DATA_IDX, (uint8_t *)cnh_data_buffer, cnh_data_size);
	   		   	        if (status != VL53LMZ_STATUS_OK)
	   		   	        {
	   		   	            printf("ERROR at %s(%d) : vl53lmz_results_extract_block failed : %d\n", __func__, __LINE__, status);
	   		   	            return status;
	   		   	        }

	   		   	        for (agg_id = 0; agg_id < cnh_config.nb_of_aggregates; agg_id++)
	   		   	        {
	   		   	            vl53lmz_cnh_get_block_addresses(&cnh_config,
	   		   	                                            agg_id,
	   		   	                                            cnh_data_buffer,
	   		   	                                            &(p_hist), &(p_hist_scaler),
	   		   	                                            &(p_ambient), &(p_ambient_scaler));

	   		   	            amb_value = ((float)*p_ambient) / (2 << *p_ambient_scaler);

	   		   	            printf("Agg, %2d, Ambient, % .1f, Bins, ", agg_id, amb_value);

	   		   	            for (bin_num = 0; bin_num < cnh_config.feature_length; bin_num++)
	   		   	            {
	   		   	                bin_value = ((float)p_hist[bin_num]) / (2 << p_hist_scaler[bin_num]);
	   		   	                printf("% .1f, ", bin_value);
	   		   	            }

	   		   	            printf("\n");
	   		   	        }

	   		   	    }

	   		   	    // Wait a few ms to avoid too high polling
	   		   	   WaitMs(&(p_dev.platform), 10);

	   		   	}
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Configure the main internal regulator output voltage
  */
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLM = 16;
  RCC_OscInitStruct.PLL.PLLN = 336;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4;
  RCC_OscInitStruct.PLL.PLLQ = 7;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}

/**
  * @brief I2C1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_I2C1_Init(void)
{

  /* USER CODE BEGIN I2C1_Init 0 */

  /* USER CODE END I2C1_Init 0 */

  /* USER CODE BEGIN I2C1_Init 1 */
  hi2c1.Init.ClockSpeed = 1000000;  // needs manually copying to line below as MXCube keeps setting to 400KHz

  /* USER CODE END I2C1_Init 1 */
  hi2c1.Instance = I2C1;
  hi2c1.Init.ClockSpeed = 1000000;
  hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
  hi2c1.Init.OwnAddress1 = 0;
  hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
  hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
  hi2c1.Init.OwnAddress2 = 0;
  hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
  hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
  if (HAL_I2C_Init(&hi2c1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN I2C1_Init 2 */

  /* USER CODE END I2C1_Init 2 */

}

/**
  * @brief USART2 Initialization Function
  * @param None
  * @retval None
  */
static void MX_USART2_UART_Init(void)
{

  /* USER CODE BEGIN USART2_Init 0 */

  /* USER CODE END USART2_Init 0 */

  /* USER CODE BEGIN USART2_Init 1 */

  /* USER CODE END USART2_Init 1 */
  huart2.Instance = USART2;
  huart2.Init.BaudRate = 921600;
  huart2.Init.WordLength = UART_WORDLENGTH_8B;
  huart2.Init.StopBits = UART_STOPBITS_1;
  huart2.Init.Parity = UART_PARITY_NONE;
  huart2.Init.Mode = UART_MODE_TX_RX;
  huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart2.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart2) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART2_Init 2 */

  /* USER CODE END USART2_Init 2 */

}

/**
  * Enable DMA controller clock
  */
static void MX_DMA_Init(void)
{

  /* DMA controller clock enable */
  __HAL_RCC_DMA1_CLK_ENABLE();

  /* DMA interrupt init */
  /* DMA1_Stream6_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Stream6_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Stream6_IRQn);

}


/**
  * @brief GPIO Initialization Function
  * @param None
  * @retval None
  */
static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOH_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(SPI_I2C_N_GPIO_Port, SPI_I2C_N_Pin, GPIO_PIN_RESET);

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOA, LD2_Pin|PWR_EN_Pin, GPIO_PIN_RESET);

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(NCS_GPIO_Port, NCS_Pin, GPIO_PIN_RESET);

  /*Configure GPIO pin : SPI_I2C_N_Pin */
  GPIO_InitStruct.Pin = SPI_I2C_N_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(SPI_I2C_N_GPIO_Port, &GPIO_InitStruct);

  /*Configure GPIO pin : INT_C_Pin */
  GPIO_InitStruct.Pin = INT_C_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(INT_C_GPIO_Port, &GPIO_InitStruct);

  /*Configure GPIO pins : LD2_Pin PWR_EN_Pin */
  GPIO_InitStruct.Pin = LD2_Pin|PWR_EN_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /*Configure GPIO pins : LPn_Pin AVDD_EN_Pin */
  GPIO_InitStruct.Pin = LPn_Pin|AVDD_EN_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /*Configure GPIO pin : NCS_Pin */
  GPIO_InitStruct.Pin = NCS_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(NCS_GPIO_Port, &GPIO_InitStruct);

  /*Configure GPIO pin : VDDIO_EN_Pin */
  GPIO_InitStruct.Pin = VDDIO_EN_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(VDDIO_EN_GPIO_Port, &GPIO_InitStruct);

  /* EXTI interrupt init*/
  HAL_NVIC_SetPriority(EXTI4_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(EXTI4_IRQn);

}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

  

When the get data read completes, is the size of the buffer big enough? You've asked for 16 zones with status and distance and perhaps some other stuff, and then you wanted the CNH data. 

	uint16_t zone_id [16];
	uint16_t distance[16];
	uint16_t Agg_id[16];
	float ambient[16] ;
	float bins_values[16][24];

did the amount of data you read come close to what you expected?

And double check to make sure the size of your data buffer aligns with what you asked for. 

(I've seen issues with non-STM32's not being able to read huge buffers.)

The only other time I've seen such an issue it was a buffer sizing issue. 

It bothers me greatly that you cannot get number_of_targets. That's a clue that there is something wrong. 

It's got to be a configuration or buffer sizing issue. 

Can you get the data you want if you comment out the CNH stuff? Getting the target distance is learning to walk, then the CNH could be added after. 

- john


If this or any post solves your issue, please mark them as 'Accept as Solution' It really helps. And if you notice anything wrong do not hesitate to 'Report Inappropriate Content'. Someone will review it.

I initially created a sensor_data struct to help send data over UART, but I’m not using it at the moment, so I’ve commented it out.

I also removed the section responsible for retrieving the CNH data as suggested, but , the issue persists: I continue to receive incorrect or unreliable distance data  from the sensor, even though the ranging status is "5" (which should mean “valid” under certain conditions).

 

you have absolutely got to get the number of targets. If at time 0 there was a valid distance at 20cm with status 5, and at time 1 you moved your hand away, the number of targets would be set to zero, but the status and the distance would NOT be updated or cleared. (I think this is very confusing, but the chip designers decided NOT to clear the buffer before starting a new range.)

until you get this working, leave all the results enabled as in:

// #define VL53L8CX_DISABLE_AMBIENT_PER_SPAD
// #define VL53L8CX_DISABLE_NB_SPADS_ENABLED
// #define VL53L8CX_DISABLE_NB_TARGET_DETECTED
// #define VL53L8CX_DISABLE_SIGNAL_PER_SPAD
// #define VL53L8CX_DISABLE_RANGE_SIGMA_MM
// #define VL53L8CX_DISABLE_DISTANCE_MM
// #define VL53L8CX_DISABLE_REFLECTANCE_PERCENT
// #define VL53L8CX_DISABLE_TARGET_STATUS
// #define VL53L8CX_DISABLE_MOTION_INDICATOR

You are going with 4x4, so it's not that much more data. After getting it working you can eliminate a few. Perhaps:

// #define VL53L8CX_DISABLE_AMBIENT_PER_SPAD
#define VL53L8CX_DISABLE_NB_SPADS_ENABLED
// #define VL53L8CX_DISABLE_NB_TARGET_DETECTED
#define VL53L8CX_DISABLE_SIGNAL_PER_SPAD
#define VL53L8CX_DISABLE_RANGE_SIGMA_MM
// #define VL53L8CX_DISABLE_DISTANCE_MM
// #define VL53L8CX_DISABLE_REFLECTANCE_PERCENT
// #define VL53L8CX_DISABLE_TARGET_STATUS
#define VL53L8CX_DISABLE_MOTION_INDICATOR

but try this. Use the sizeof() function to check the size of your buffer. Make sure that that's the size of the data you are reading. 

I'm reasonably sure those two numbers are not going to match. Your unreliable data might be a result of that.

- john

 


If this or any post solves your issue, please mark them as 'Accept as Solution' It really helps. And if you notice anything wrong do not hesitate to 'Report Inappropriate Content'. Someone will review it.
kgb
Associate III

Hallo @John E KVAM ,

It seems that the problem lies somewhere else. First, I need to explain that I didn’t create a new project from scratch.  Instead, I took the STSW-IMG043_F401  project and i  just  main.c to handle the CNH data based on example_12_cnh( i removed the mz_ai_main function ). Beacuase I couldn’t write a script to interpret the encoded data because it’s quite complex and would probably take me too long to fully understand.

So after trying all your suggestions, I went back to the STSW-IMG043 project. There is a function called print_encoded_frame in the in that project mz_ai_main.c file , which is responsible for encoding the sensor data and printing it. I modified this function slightly so that it prints the data directly without any additional modifications. The incoming data (distance, CNH) was exactly the same as what I was receiving from my modified main.c.

It seems that there’s something else I should do in order to get the correct data, but I’m not sure what it is.

kgb
Associate III

I also resolved the issue with  number_of_target in my main.c  but i am always received a as number of target regardless  of whether i have an obstacle in front of the sensor or not. 

for (int i = 0; i < 16; i++) {
	   		   	      if (Results.nb_target_detected[i] > 0) {
	   		   	          printf("Zone %d: Distance = %d mm, Status = %d , Target_nb = %d\n",
	   		   	                 i,
	   		   	                 Results.distance_mm[i],
	   		   	                 Results.target_status[i],
								 Results.nb_target_detected[i]);
	   		   	      } else {
	   		   	          printf("Zone %d: No target detected.\n", i);
	   		   	      }
	   		   	  }

 

 

An i am getting  this   when i hold my  in front of it :


Zone 0: Distance = 430 mm, Status = 5 , Target_nb = 1

Zone 1: Distance = 444 mm, Status = 5 , Target_nb = 1

Zone 2: Distance = 428 mm, Status = 5 , Target_nb = 1 


And this when  i remove : 


Zone 13: Distance = 6591 mm, Status = 5 , Target_nb = 1

Zone 14: Distance = 6686 mm, Status = 5 , Target_nb = 1

Zone 15: Distance = 6648 mm, Status = 5 , Target_nb = 1

John E KVAM
ST Employee

If you have the Evaluation kit, try running the GUI. This will prove you don't have a hardware issue. 

It's - STSW-IMG041 and I know it's confusing as this is for the VL53L8CX (not CH).

But the CH is a superset of the CX, so it will work fine. 

See what kind of picture that gives you. 

Now we will have proven that the hardware works.

---

when looking at number of targets, you are trying to eliminate the case where you have no target. 

So your choices are target and no target. 

If, in the platform.h file, you have something other than:

#define VL53L8CX_NB_TARGET_PER_ZONE 1U

you can get up to 4 targets. (But I've found 3 and 4 are practically useless. Two targets per zone might help decide where an edge is.) But most people only use one. 

 

But I have no idea how you can get a 6M target. Your hand looks good at 500mm or so, but 6M on a 4M part is wrong. Something is clearly amiss.

 

Would you consider building the code with NO changes and seeing what you get? That should be right. 

Does pointing at your ceiling get you something like 2M? It should.


If this or any post solves your issue, please mark them as 'Accept as Solution' It really helps. And if you notice anything wrong do not hesitate to 'Report Inappropriate Content'. Someone will review it.

Hello @John E KVAM, actually, I am working on a Linux PC, but sometimes I switch to a Windows PC to test certain things (like the https://www.st.com/en/embedded-software/stsw-img043.html for example).

I would like to clarify that I have already used the vl53l8cx_api and my data was perfectly correct, but I need to get the CNH data for a specific purpose, so my problem has nothing to do with the hardware. However, I wanted to test the STSW-IMG041 to reassure myself, and everything works fine.

Regarding my problem, when I flash the STSW-IMG043_F401 (MZ_AI_Kit) directly from my STMIDE and then connect my board to a Windows PC and launch the MZ_AI_EVK without flashing the firmware present in the MZ_AI_EVK, I receive perfectly plausible data on the GUI. I think my problem comes from the fact that I used the IMG03_F401 and just modified the main file to display the data directly and There must be something else I need to pay attention to, but I'm not sure what that is.