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

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 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 "dma.h"
#include "i2c.h"
#include "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "VL53.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 ---------------------------------------------------------*/

/* USER CODE BEGIN PV */
#define AVG_COUNTER		50
// 0 1 2 3 4 5
// < L x x C > // Length message
// < S S >     // Calibration message
// 388 bytes for calibration, 1 byte for C(alibration), 1 byte checksum, 2 bytes start/end message marker
volatile uint8_t rxBuffer[BUFFER_LEN];
// Interrupt from Sensor
extern volatile uint8_t ToF_EventDetected;
// Data structure from sensor
extern VL53LX_CalibrationData_t calibrationData;
// DMA 
extern DMA_HandleTypeDef hdma_usart1_rx;
extern DMA_HandleTypeDef hdma_usart1_tx;
// To know when the Tx is complete
volatile uint8_t txNotComplete = 0;

// When we start the timeout counter
uint32_t startTime = 0;
// Add measured distances to return the average
uint32_t sumDist = 0;
// How many times we add the distance
uint8_t cntDist = 0;
// Average distance
uint16_t avgDist = 0;
// Hold the commad received from ESP
volatile uint8_t crtCommand = 0;

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

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

void startDMA_Rx() {
	HAL_UART_Receive_DMA(&huart1, (uint8_t *)rxBuffer, BUFFER_LEN);
	__HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_HT);
	__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
}
// Function to generate checksum and place it in the last position of the array
void generateChecksum(uint8_t *array, uint16_t length) {
	uint8_t checkSum = 0;
	for (uint16_t i = 1; i < length; i++) {
		checkSum += array[i];
	}
	array[length] = 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(uint16_t length) {
	uint16_t len = length - 2;
	uint8_t checksum = 0;
	for (uint16_t i = 1; i < len; i++) {
		checksum += rxBuffer[i];
	}
	return (checksum == rxBuffer[len]); // Compare calculated checksum with the stored one
}

// 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) {
		HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET);
		//Determine how many items of data have been received
		uint16_t data_length = BUFFER_LEN - __HAL_DMA_GET_COUNTER(huart1.hdmarx);
		//Stop DMA	
		HAL_UART_DMAStop(&huart1);
		// Shortest messege is <XX>
		if(data_length > 3) {
			// If checkSum is OK
			if(checkChecksum(data_length)) {
				// Do we have the markers in place?
				if((rxBuffer[0] == START_MARKER) && (rxBuffer[data_length - 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;				
					}
				}
			}
		}
		// Start DMA and set the interrupts
		startDMA_Rx();
		HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET);
	}
}

// Send messages to ESP
void sendMessage(const uint8_t msgType) {
	uint16_t txLen = 0;
	uint8_t txBuffer[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 = 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 - 2);
	txBuffer[txLen - 1] = END_MARKER;
	
	uint32_t startTime = HAL_GetTick();
	// If transmission is not complete, wait or reset UART1
	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
		}
	}
	txNotComplete = 1;
	HAL_UART_Transmit_DMA(&huart1, (uint8_t *)txBuffer, txLen);
}
/* 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_DMA_Init();
  MX_I2C1_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */

	//Start DMA, Disable half transfer interrupt on Rx and enable IDLE line detection
	startDMA_Rx();
	
	// Allow ESP to BOOT, it takes about 115 ms
	HAL_Delay(150);
	
	// Send a message to ESP32 to let it know that it can send the calibration data
	sendMessage(RESPONSE_OK);

	// 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);
	
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  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 50 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
				}
			}
		}
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

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

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  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();
  }

  /** 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();
  }
  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();
  }
}

/* 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 */

In tm32f3xx_it.c

void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */
  if (USART1->ISR & USART_ISR_IDLE){ // IDLE line detected
    USART1->ICR = USART_ICR_IDLECF;
		HAL_UART_RxCpltCallback(&huart1);
	}
  /* USER CODE END USART1_IRQn 0 */
  HAL_UART_IRQHandler(&huart1);
  /* USER CODE BEGIN USART1_IRQn 1 */

  /* USER CODE END USART1_IRQn 1 */
}

Comments powered by CComment