STM32F302 VL53L4CX Time-of-Flight (ToF) sensor driver

STM32F302 I2C Library for VL53L4CX  Time-of-Flight (ToF) sensor

Please read Liability Disclaimer and License Agreement CAREFULLY

Before going further please read VL53L4CX datasheet

The STM32F302 has the I2C set up at 400kHz, USART1 Rx and Tx are in DMA mode normal and speed is 9600bps (long wires to ESP32-S3).

The XSHUT pin and interrupt pin are set up as per below code.

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(XSHUT_GPIO_Port, XSHUT_Pin, GPIO_PIN_RESET);

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

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

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

The needed files are listed below, except first 2, all other can be obtained from X-CUBE-TOF1 archive found on ST site.

VL53.c
VL53.h
vl53l4cx.c
vl53l4cx.h
vl53lx_api.c
vl53lx_api.h
vl53lx_api_calibration.c
vl53lx_api_calibration.h
vl53lx_api_core.c
vl53lx_api_core.h
vl53lx_api_debug.c
vl53lx_api_debug.h
vl53lx_api_preset_modes.c
vl53lx_api_preset_modes.h
vl53lx_core.c
vl53lx_core.h
vl53lx_core_support.c
vl53lx_core_support.h
vl53lx_def.h
vl53lx_dmax.c
vl53lx_dmax.h
vl53lx_dmax_private_structs.h
vl53lx_dmax_structs.h
vl53lx_error_codes.h
vl53lx_error_exceptions.h
vl53lx_hist_algos_gen3.c
vl53lx_hist_algos_gen3.h
vl53lx_hist_algos_gen4.c
vl53lx_hist_algos_gen4.h
vl53lx_hist_char.c
vl53lx_hist_char.h
vl53lx_hist_core.c
vl53lx_hist_core.h
vl53lx_hist_funcs.c
vl53lx_hist_funcs.h
vl53lx_hist_map.h
vl53lx_hist_private_structs.h
vl53lx_hist_structs.h
vl53lx_ll_def.h
vl53lx_ll_device.h
vl53lx_nvm.c
vl53lx_nvm.h
vl53lx_nvm_debug.c
vl53lx_nvm_debug.h
vl53lx_nvm_map.h
vl53lx_nvm_structs.h
vl53lx_platform.c
vl53lx_platform.h
vl53lx_platform_init.h
vl53lx_platform_ipp.c
vl53lx_platform_ipp.h
vl53lx_platform_ipp_imports.h
vl53lx_platform_log.c
vl53lx_platform_log.h
vl53lx_platform_user_config.h
vl53lx_platform_user_data.h
vl53lx_platform_user_defines.h
vl53lx_preset_setup.h
vl53lx_register_funcs.c
vl53lx_register_funcs.h
vl53lx_register_map.h
vl53lx_register_settings.h
vl53lx_register_structs.h
vl53lx_sigma_estimate.c
vl53lx_sigma_estimate.h
vl53lx_silicon_core.c
vl53lx_silicon_core.h
vl53lx_tuning_parm_defaults.h
vl53lx_types.h
vl53lx_wait.c
vl53lx_wait.h
vl53lx_xtalk.c
vl53lx_xtalk.h
vl53lx_xtalk_private_structs.h

In VL5.h add the following code

#ifndef VL53_H
#define VL53_H

#ifdef __cplusplus
extern "C" {
#endif

#include "vl53lx_error_codes.h"
#include "vl53lx_api.h"

#define I2C_TIMEOUT			200
#define TIME_BUDGET_US	199238 //200ms
#define TIME_BUDGET_MS	200 //200ms
#define AVG_COUNTER			25
#define CAL_DISTANCE		600 //600mm

/* BSP Common Error codes */
#define BSP_ERROR_NONE                    0
#define BSP_ERROR_NO_INIT                -1
#define BSP_ERROR_WRONG_PARAM            -2
#define BSP_ERROR_BUSY                   -3
#define BSP_ERROR_PERIPH_FAILURE         -4
#define BSP_ERROR_COMPONENT_FAILURE      -5
#define BSP_ERROR_UNKNOWN_FAILURE        -6
#define BSP_ERROR_UNKNOWN_COMPONENT      -7
#define BSP_ERROR_BUS_FAILURE            -8
#define BSP_ERROR_CLOCK_FAILURE          -9
#define BSP_ERROR_MSP_FAILURE            -10
#define BSP_ERROR_FEATURE_NOT_SUPPORTED      -11

/* BSP BUS error codes */

#define BSP_ERROR_BUS_TRANSACTION_FAILURE    -100
#define BSP_ERROR_BUS_ARBITRATION_LOSS       -101
#define BSP_ERROR_BUS_ACKNOWLEDGE_FAILURE    -102
#define BSP_ERROR_BUS_PROTOCOL_FAILURE       -103

#define BSP_ERROR_BUS_MODE_FAULT             -104
#define BSP_ERROR_BUS_FRAME_ERROR            -105
#define BSP_ERROR_BUS_CRC_ERROR              -106
#define BSP_ERROR_BUS_DMA_FAILURE            -107

extern volatile uint8_t ToF_EventDetected;
extern VL53LX_CalibrationData_t calibrationData;

void VL53_Reset();
VL53LX_Error VL53_Init(const uint8_t getDataFirst);
VL53LX_Error VL53_Calibrate();
VL53LX_Error VL53_setCalibration();
VL53LX_Error VL53_getCalibration();
uint16_t VL53_getDistance();

#ifdef __cplusplus
}
#endif

#endif /* VL53_H */

In VL5.c add the following code

#include "VL53.h"
#include "i2c.h"
#include "gpio.h"

#include "vl53lx_api.h"
#include "vl53lx_error_codes.h"
#include "vl53l4cx.h"
const uint8_t VL53_ADDRESS = 0x52;

volatile uint8_t ToF_EventDetected = 0;

VL53L4CX_Object_t myVL53 = {0};
VL53L4CX_RANGING_SENSOR_Drv_t myVL53_Drv = {0};
VL53LX_CalibrationData_t calibrationData = {0};

static int I2C1_Init(void) {
	// The init is don in I2C
  return 0;
}

static int I2C1_DeInit(void) {
	// The deinit is don in I2C
  return 0;
}

static int32_t getTick(void) {
  return HAL_GetTick();
}

static int I2C1_Send(const uint16_t DevAddr, uint8_t *pData, const uint16_t Length) {
  VL53LX_Error ret = VL53LX_ERROR_NONE;
  if(HAL_I2C_Master_Transmit(&hi2c1, DevAddr, pData, Length, I2C_TIMEOUT) != HAL_OK)  {
    if(HAL_I2C_GetError(&hi2c1) != HAL_I2C_ERROR_AF) {
      ret = BSP_ERROR_BUS_ACKNOWLEDGE_FAILURE;
    } else {
      ret =  BSP_ERROR_PERIPH_FAILURE;
    }
  }
  return ret;
}

static int I2C1_Recv(const uint16_t DevAddr, uint8_t *pData, const uint16_t Length) {
	int ret = BSP_ERROR_NONE;
  if(HAL_I2C_Master_Receive(&hi2c1, DevAddr, pData, Length, I2C_TIMEOUT) != HAL_OK) {
    if(HAL_I2C_GetError(&hi2c1) != HAL_I2C_ERROR_AF) {
      ret = BSP_ERROR_BUS_ACKNOWLEDGE_FAILURE;
    } else {
      ret =  BSP_ERROR_PERIPH_FAILURE;
    }
  }
  return ret;
}

static int32_t VL53L4CX_InitData(VL53L4CX_Object_t *pObj) {
	// First RESET the senssor
	VL53_Reset();
	// Set up 
	pObj->IO.Init      = I2C1_Init;
	pObj->IO.DeInit    = I2C1_DeInit;
	pObj->IO.Address   = VL53_ADDRESS;
	pObj->IO.WriteReg  = I2C1_Send;
	pObj->IO.ReadReg   = I2C1_Recv;
	pObj->IO.GetTick   = getTick;
	// Wait for the device to boot
	if(VL53LX_WaitDeviceBooted(pObj) != VL53LX_ERROR_NONE) {
		return VL53L4CX_ERROR;
	}
	// Initialize device data
	if(VL53LX_DataInit(pObj) != VL53LX_ERROR_NONE) {
		return VL53L4CX_ERROR;
	}
	// Initialization successful, set object state
	pObj->IsRanging = 0;
	pObj->IsBlocking = 0;
	pObj->IsContinuous = 0;
	pObj->IsAmbientEnabled = 0;
	pObj->IsSignalEnabled = 0;
	pObj->IsInitialized = 1;

	return VL53L4CX_OK;
}

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
  if(GPIO_Pin == INT_Pin) {
    ToF_EventDetected = 1;
  }
}

void VL53_Reset() {
  HAL_GPIO_WritePin(XSHUT_GPIO_Port, XSHUT_Pin, GPIO_PIN_RESET);
  HAL_Delay(5);
  HAL_GPIO_WritePin(XSHUT_GPIO_Port, XSHUT_Pin, GPIO_PIN_SET);
  HAL_Delay(5);
}

VL53LX_Error VL53_Init(const uint8_t getDataFirst) {
	uint32_t id;
	VL53L4CX_Capabilities_t pCap;
	VL53LX_Error ret = VL53L4CX_InitData(&myVL53);
	//Start by confirming device ID
	if(ret == VL53L4CX_OK) ret = VL53L4CX_ReadID(&myVL53, &id);
	if(ret == VL53L4CX_OK && id == VL53L4CX_ID) ret = VL53L4CX_GetCapabilities(&myVL53, &pCap);
	if(getDataFirst) {
		if(ret == VL53L4CX_OK) ret = VL53LX_GetCalibrationData(&myVL53, &calibrationData);
	}
	if(ret == VL53L4CX_OK) ret =  VL53LX_SetCalibrationData(&myVL53, &calibrationData);
	if(ret == VL53L4CX_OK) ret = VL53LX_SetDistanceMode(&myVL53, VL53LX_DISTANCEMODE_LONG);
	if(ret == VL53L4CX_OK) ret = VL53LX_StopMeasurement(&myVL53);
	// SetUp for higher accuracy
	if(ret == VL53L4CX_OK) ret = VL53LX_set_tuning_parm(&myVL53, VL53LX_TUNINGPARM_PHASECAL_PATCH_POWER, 2);
	if(ret == VL53L4CX_OK) ret = VL53LX_set_tuning_parm(&myVL53, VL53LX_TUNINGPARM_RESET_MERGE_THRESHOLD, 16000);
	if(ret == VL53L4CX_OK) ret = VL53LX_SmudgeCorrectionEnable(&myVL53, VL53LX_SMUDGE_CORRECTION_CONTINUOUS);
	if(ret == VL53L4CX_OK) ret = VL53LX_SetXTalkCompensationEnable(&myVL53, 1);
	if(ret == VL53L4CX_OK) ret = VL53LX_SetOffsetCorrectionMode(&myVL53, VL53LX_OFFSETCORRECTIONMODE_PERVCSEL);
	if(ret == VL53L4CX_OK) ret = VL53LX_SetMeasurementTimingBudgetMicroSeconds(&myVL53, TIME_BUDGET_US);
	// Start to measure
	if(ret == VL53L4CX_OK) ret = VL53L4CX_Start(&myVL53, VL53L4CX_MODE_ASYNC_CONTINUOUS);
	return ret;
}

VL53LX_Error VL53_Calibrate() {
	VL53LX_Error status = VL53LX_ERROR_NONE;
	// 388 bytes in calibrationData, initialized to 0, they will be sent to ESP
	
	// 1. WaitDeviceBooted()
	// 2. DataInit()
	status = VL53L4CX_InitData(&myVL53);
	if(status != VL53LX_ERROR_NONE) {
		return status; // Return immediately if error occurred
	}
	// 3. Perform Reference SPAD (Single Photon Avalanche Diode) Management
	status = VL53LX_PerformRefSpadManagement(&myVL53);
	if(status != VL53LX_ERROR_NONE) {
		return status; // Return immediately if error occurred
	}

	//* 4. Perform Crosstalk Calibration only if SPAD management is successful
	status = VL53LX_PerformXTalkCalibration(&myVL53);
	if(status != VL53LX_ERROR_NONE) {
		return status; // Return immediately if error occurred
	}

	// 5. Perform Offset Calibration only if Crosstalk Calibration is successful
	status = VL53LX_PerformOffsetPerVcselCalibration(&myVL53, CAL_DISTANCE);
	if(status != VL53LX_ERROR_NONE) {
		return status; // Return immediately if error occurred
	}

	// 6. Get Calibration Data only if Offset Calibration is successful
	status = VL53LX_GetCalibrationData(&myVL53, &calibrationData);
	if(status != VL53LX_ERROR_NONE) {
		return status; // Return immediately if error occurred
	}

	// 7. Save the calibration data
	status = VL53LX_SetCalibrationData(&myVL53, &calibrationData);
	// Return the final status, whether success or the first error encountered
	return status;
}

// Called when we get the calibration data from ESP
VL53LX_Error VL53_setCalibration() {
	// Return the final status, whether success or the first error encountered
	return VL53LX_SetCalibrationData(&myVL53, &calibrationData);
}

// Called when we do not get the calibration data from ESP
VL53LX_Error VL53_getCalibration() {
	// Return the final status, whether success or the first error encountered
	return VL53LX_GetCalibrationData(&myVL53, &calibrationData);
}

// Get the measured distance, acll it only when ToF_EventDetected = 1
uint16_t VL53_getDistance() {
	uint16_t distance = 0;
	ToF_EventDetected = 0; // Reset the event detected flag
	VL53LX_Error status = VL53LX_ERROR_NONE;
	static VL53L4CX_Result_t Result; // Static to preserve its value between function calls
	status = VL53L4CX_GetDistance(&myVL53, &Result); // Attempt to get distance measurement
	if(status == VL53LX_ERROR_NONE) { // Proceed only if no error
		//We have only one zone and one target
		distance = Result.ZoneResult[0].Distance[0];
//			for (uint8_t zones = 0; zones < VL53L4CX_MAX_NB_ZONES; zones++) { // Iterate through all zones
//				for (uint8_t targets = 0; targets < Result.ZoneResult[zones].NumberOfTargets; targets++) { // Iterate through all targets within a zone
//					uint16_t distance = Result.ZoneResult[zones].Distance[targets];
//					if(distance > maxDist) { // Check if the current distance is greater than maxDist
//						maxDist = distance; // Update maxDist with the current distance
//					}
//				}
//			}
	}
	return distance; // Return the maximum distance found
}

In main.c add the following code

#include "main.h"
#include "dma.h"
#include "i2c.h"
#include "usart.h"
#include "gpio.h"


#include "VL53.h"

// Sample calibration data including <> and check sum
#ifdef DEBUG
const uint8_t calData[392] = {0x3C, 0x53, 0x22, 0x01, 0xAB, 0xEC, 0xFF, 0xF5, 0xFF, 0xFF, 0xFF, 0x0B, 0x00, 0x06, 0x01, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x1E, 0x78, 0xB3, 0x80, 0x00, 0x80, 0x01, 0x8C, 0x6F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C,
	0x00, 0x02, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x70, 0x03, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4E, 0x28, 0x06, 0x09, 0x28, 0x00, 0x51, 0xBC, 0x4E, 0x10, 0x00, 0x00, 0x03,
	0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x17, 0x00, 0x00, 0x00, 0x12, 0x01, 0x00, 0x00,
	0x4C, 0x27, 0x00, 0x00, 0x45, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x4E, 0x28, 0x06, 0x09, 0x28, 0x00, 0x00, 0x00, 0x51, 0xBC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x4E, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDB, 0x07, 0xE4, 0x07, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x05, 0x00, 0x05, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, 0xF2, 0x00, 0xF3, 0x00, 0xF3, 0x00, 0x01,
	0x10, 0x00, 0x00, 0xC3, 0x1F, 0x00, 0x00, 0x85, 0x2F, 0x00, 0x00, 0x47, 0x3F, 0x00, 0x00, 0x09, 0x4F, 0x00, 0x00, 0xCF, 0x5E, 0x00, 0x00, 0x1F, 0x3E};
#endif
// 388 bytes for calibration, 1 byte for C(alibration), 1 byte checksum, 2 bytes start/end message marker
uint8_t rxBuffer[RX_BUFFER_LEN];

extern volatile uint8_t ToF_EventDetected;
extern VL53LX_CalibrationData_t calibrationData;

extern DMA_HandleTypeDef hdma_usart1_rx;
extern DMA_HandleTypeDef hdma_usart1_tx;

volatile uint8_t txNotComplete = 0;

uint32_t sumDist = 0;
uint8_t cntDist = 0;
uint16_t avgDist = 0;

uint8_t checkSum = 0;
uint8_t crtCommand = 0;

void SystemClock_Config(void);

// Function to generate checksum and place it in the last position of the array
void generateChecksum(uint8_t *array, uint16_t length) {
	checkSum = 0;
	if (length < 3) return; // Ensure there's enough length for start, char, and checksum
	for (uint16_t i = 1; i < length - 1; i++) {
		checkSum += array[i];
	}
	array[length - 1] = checkSum; // Store the checksum in the last position
}

// Function to check if the checksum in the last position matches the calculated checksum
uint8_t checkChecksum(uint8_t *array, uint16_t length) {
	if (length < 3) return 0; // Not a valid structure
	uint8_t checksum = 0;
	for (uint16_t i = 1; i < length - 1; i++) {
		checksum += array[i];
	}
	return checksum == array[length - 1]; // Compare calculated checksum with the stored one
}

void processMessage(const uint16_t msgLen) {
	// If checkSum is OK
	if(checkChecksum(rxBuffer, msgLen -1)) {
		// Do we have the markers in place?
		if((rxBuffer[0] == START_MARKER) && (rxBuffer[msgLen - 1] == END_MARKER)) {
			switch(rxBuffer[1]) {
				case CMD_CALIBRATE:
					crtCommand = CMD_CALIBRATE;
				break;
				case CMD_STORE_CAL:
					crtCommand = CMD_STORE_CAL;
					calibrationData = *(VL53LX_CalibrationData_t *)&rxBuffer[2];
				break;				
			}
		}
	}
}

// DMA transmit complete callback
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart){
	if(huart->Instance == USART1) {
		txNotComplete = 0;
	}
}

// DMA receive complete callback
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
	if(huart->Instance == USART1) {
		//Determine how many items of data have been received
		uint8_t data_length = RX_BUFFER_LEN - __HAL_DMA_GET_COUNTER(huart1.hdmarx);//DMA1_Stream0->NDTR;
		//Stop DMA	
		HAL_UART_DMAStop(&huart1);
		// Shortest messege is <CDDC>
		if(data_length > 5) {
			processMessage(data_length);
		}
		HAL_UART_Receive_DMA(&huart1, (uint8_t *)rxBuffer, RX_BUFFER_LEN);
		__HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_HT);
		__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);

	}
}

// Send messages to ESP
void sendMessage(const uint8_t msgType) {
	uint16_t txLen = 0;
	uint8_t txBuffer[RX_BUFFER_LEN];
	switch(msgType) {
		case RESPONSE_OK:
		case RESPONSE_FAIL:
			txLen = 4;
		break;	
		case RESPONSE_LENGTH:
			txLen = 6;
			*(uint16_t *)&txBuffer[2] = avgDist;
		break;
		case RESPONSE_CAL_DONE:
			txLen = RX_BUFFER_LEN;
			// Put the calibrationData structure in the array
			*(VL53LX_CalibrationData_t *)&txBuffer[2] = calibrationData;
		break;		
	}
	txBuffer[0] = START_MARKER;
	txBuffer[1] = msgType;
	generateChecksum(txBuffer, txLen - 1);
	txBuffer[txLen - 1] = END_MARKER;
	
	uint32_t startTime = HAL_GetTick();
	txNotComplete = 1; // Assume transmission is not complete
	HAL_UART_Transmit_DMA(&huart1, (uint8_t *)txBuffer, txLen);
	while(txNotComplete) {
		// Check for timeout
		if (HAL_GetTick() - startTime > TIMEOUT_SEND) {
			// Timeout occurred, abort transmission
			HAL_UART_AbortTransmit(&huart1);
			// Re-initialize UART
			MX_USART1_UART_Init(); 
			txNotComplete = 0; // Clear the transmission flag to exit the loop
			break; // Exit the loop
		}
	}
}

int main(void)
{

  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_I2C1_Init();
  MX_USART1_UART_Init();
	
	// Allow ESP to BOOT
	HAL_Delay(500);
	// Send a message to ESP32 to let it know that it can send the calibration data
	sendMessage(RESPONSE_OK);

	// Used to get the time needed for calibration = 4.9s
//	#ifdef DEBUG
//	VL53_Calibrate();
//	sendMessage(RESPONSE_CAL_DONE);
//	#endif

	// Simulate a calibration data received not using memcpy
//	for(uint16_t i = 0; i < RX_BUFFER_LEN; i++){
//		rxBuffer[i] = calData[i];
//	}
//	processMessage(RX_BUFFER_LEN);
	
	// Wait to get the calibrarion data from ESP
	uint8_t isTimeOut = 1;
	uint32_t time = HAL_GetTick();
	while(HAL_GetTick() - time < TIMEOUT_ESP) {
		if(crtCommand == CMD_STORE_CAL){
			isTimeOut = 0;
			break;
		}
		HAL_Delay(10);
	}
	// If we do not get anything
	if(isTimeOut) {
		sendMessage(RESPONSE_FAIL);
	} else {
		// Reset the command
		crtCommand = 0;
		// Inform ESP that we got the packet
		sendMessage(RESPONSE_OK);
	}
	// Start VL
	VL53_Init(isTimeOut);

  while (1)
  {
		// Check if a calibration request was issued
		if(crtCommand == CMD_CALIBRATE){
			// If the calibration NOK. Calibration takes about 5sec to complete
			if(VL53_Calibrate() != VL53LX_ERROR_NONE) {
				sendMessage(RESPONSE_FAIL);
			} else {
				// Hard reset the sensor at this point
				sendMessage(RESPONSE_CAL_DONE);
				// Re init the sensor considering that we have calibration data available
				VL53_Init(0);
			}
			crtCommand = 0;
		}
		// Chek if distance data is available
		if (ToF_EventDetected) {
			uint16_t crtDist = VL53_getDistance();
			if(crtDist) { // Check if a valid distance is returned
				sumDist += crtDist;
				cntDist++;
				if(cntDist == AVG_COUNTER) { // Check if we have collected 25 readings
					avgDist = sumDist / AVG_COUNTER; // Calculate the average
					sendMessage(RESPONSE_LENGTH); // Send length to ESP
					sumDist = 0; // Reset the sum
					cntDist = 0; // Reset the counter
				}
			}
		}
  }
}


void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};

  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  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_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  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();
  }
  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1|RCC_PERIPHCLK_I2C1;
  PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2;
  PeriphClkInit.I2c1ClockSelection = RCC_I2C1CLKSOURCE_HSI;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  {
    Error_Handler();
  }
}

void Error_Handler(void)
{
  __disable_irq();
  while (1)
  {
  }
}

Comments powered by CComment

Who’s online

We have 70 guests and no members online