2025-03-04 4:57 AM - last edited on 2025-03-04 5:22 AM by mƎALLEm
Hi, I tried to read signal from ultrasonic parking unit by capturing PWM input. Signal has one start pulse 530 Hz width (1.87 ms) and a sequence with 0 and 1 (9.942 kHz and 4,97 kHz) period between pulses sequences is about 193 ms.
I use STM32F103 blue pill board with external 8Mhz quartz oscillator.
My clock config:
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
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();
}
}
My Timer configuration:
static void MX_TIM3_Init(void)
{
/* USER CODE BEGIN TIM3_Init 0 */
/* USER CODE END TIM3_Init 0 */
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_SlaveConfigTypeDef sSlaveConfig = {0};
TIM_IC_InitTypeDef sConfigIC = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
/* USER CODE BEGIN TIM3_Init 1 */
/* USER CODE END TIM3_Init 1 */
htim3.Instance = TIM3;
htim3.Init.Prescaler = 0;
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.Period = 65535;
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim3) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_IC_Init(&htim3) != HAL_OK)
{
Error_Handler();
}
sSlaveConfig.SlaveMode = TIM_SLAVEMODE_RESET;
sSlaveConfig.InputTrigger = TIM_TS_TI1FP1;
sSlaveConfig.TriggerPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
sSlaveConfig.TriggerPrescaler = TIM_ICPSC_DIV1;
sSlaveConfig.TriggerFilter = 0;
if (HAL_TIM_SlaveConfigSynchro(&htim3, &sSlaveConfig) != HAL_OK)
{
Error_Handler();
}
sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
sConfigIC.ICFilter = 0;
if (HAL_TIM_IC_ConfigChannel(&htim3, &sConfigIC, TIM_CHANNEL_1) != HAL_OK)
{
Error_Handler();
}
sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_FALLING;
sConfigIC.ICSelection = TIM_ICSELECTION_INDIRECTTI;
if (HAL_TIM_IC_ConfigChannel(&htim3, &sConfigIC, TIM_CHANNEL_2) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM3_Init 2 */
HAL_TIM_IC_Start_IT(&htim3, TIM_CHANNEL_2);
/* USER CODE END TIM3_Init 2 */
}
Capture callback:
#define RADAR_FRONT_START_PULSE 18000 // Hz
#define RADAR_REAR_START_PULSE 19000 // Hz
#define RADAR_HIGH_PULSE 5000 // Hz
#define RADAR_LOW_PULSE 10000 // Hz
#define RADAR_PULSE_DEVIATION 2000 // Hz
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if (!CHECK_RADAR_ON) return;
if(htim -> Instance == TIM3 && htim -> Channel == HAL_TIM_ACTIVE_CHANNEL_2)
{
HandleRearRadarPulses(htim);
}
if(htim -> Instance == TIM2 && htim -> Channel == HAL_TIM_ACTIVE_CHANNEL_2)
{
HandleFrontRadarPulses(htim);
}
}
void HandleRearRadarPulses(TIM_HandleTypeDef *htim)
{
static int8_t index = 32;
static int8_t start_cpatured = 0;
static uint32_t captured_pulses = 0;
uint16_t packet = 0;
uint32_t pulse = 0;
pulse = SystemCoreClock / (HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2));
if (IS_REAR_START_PULSE(pulse))
{
start_cpatured = 1;
index = 32;
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_SET);
return;
}
if (start_cpatured){
if (IS_HIGH_PULSE(pulse)) captured_pulses |= (1 << index);
if (index == 0) {
rear_min_distance = 255;
for (int i=0; i<4; i+=1) {
packet = (captured_pulses & (255 << (RADAR_PACKET_LENGTH * i))) >> (RADAR_PACKET_LENGTH * i);
rear_sensors[i] = packet;
if (packet < rear_min_distance) rear_min_distance = packet;
}
captured_pulses = 0;
start_cpatured = 0;
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_RESET);
}
index --;
}
}
Main problem is to catch start pulse on this config. To work as expected I used to reduce width of start pulse from 530 Hz to 19 kHz to be able to catch it. For example, using timer on black pill STM32F4 with 32 bit AutoRload Register start pulse was captured with 530 Hz.
To detect correct package detection I also set pin state once start pulse was captured and reset after complete package reception.
Is it possible to catch such kind of signals with 16 bit Counter Period (AutoRload Register) with correct start pulse width (530 Hz) or problem with different thing?
If I correctly understand that first pulse tried to capture 2 times because of its width 1.87 ms, as timer capture period is about 0.9 ms (Counter_Period / F clock -> 65535 / 72 Mhz = 0.9 ms).
Thanks in advice!
Solved! Go to Solution.
2025-03-04 6:29 AM - edited 2025-03-04 11:32 AM
Hi,
>Is it possible to catch such kind of signals with 16 bit Counter Period (AutoRload Register) with correct start pulse width (530 Hz) or problem with different thing?
Yes, no problem. Just use prescaler, maybe :71 , to set the timer to count on 1us clock.
Then 65k gives a range up to 65ms to capture and still good resolution to check 100 or 200 us long pulse coming.
2025-03-04 6:29 AM - edited 2025-03-04 11:32 AM
Hi,
>Is it possible to catch such kind of signals with 16 bit Counter Period (AutoRload Register) with correct start pulse width (530 Hz) or problem with different thing?
Yes, no problem. Just use prescaler, maybe :71 , to set the timer to count on 1us clock.
Then 65k gives a range up to 65ms to capture and still good resolution to check 100 or 200 us long pulse coming.
2025-03-05 5:00 AM - edited 2025-03-05 5:14 AM
Thanks for your reply! Your comment makes me reconsider my idea and refactor code to work with time directly.
Before I successfully setup TIM4 for sending CAN frames in calculated timings but in case of PWM input I stuck in a ARR aspect and somehow cannot change point of view.
As a result, I set ARR to 72-1 and check each pulse by time. Works like a charm!) Thank you!
#define RADAR_START_PULSE 1880 // ms
#define RADAR_HIGH_PULSE 200 // ms
#define RADAR_LOW_PULSE 100 // ms
#define RADAR_PULSE_DEVIATION 20 // ms
# define IS_HIGH_PULSE(var) (RADAR_HIGH_PULSE + RADAR_PULSE_DEVIATION >= var && RADAR_HIGH_PULSE - RADAR_PULSE_DEVIATION <= var)
# define IS_START_PULSE(var) (RADAR_START_PULSE + RADAR_PULSE_DEVIATION >= var && RADAR_START_PULSE - RADAR_PULSE_DEVIATION <= var)
void HandleFrontRadarPulses(TIM_HandleTypeDef *htim)
{
static int8_t index = 32;
static int8_t start_cpatured = 0;
static uint32_t captured_pulses = 0;
uint32_t pulse = 0;
uint16_t packet = 0;
pulse = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2);
if (IS_START_PULSE(pulse))
{
start_cpatured = 1;
index = 32;
return;
}
if (start_cpatured){
if (IS_HIGH_PULSE(pulse)) captured_pulses |= (1 << index);
if (index == 0) {
front_min_distance = 255;
for (int i=0; i<4; i+=1) {
packet = (captured_pulses & (255 << (RADAR_PACKET_LENGTH * i))) >> (RADAR_PACKET_LENGTH * i);
front_sensors[i] = packet;
if (packet < front_min_distance) front_min_distance = packet;
}
captured_pulses = 0;
start_cpatured = 0;
}
index --;
}
}
But one thing stay unresolved for me, how can I get this width from time ticks?
Let's say I have pulse 101 uS time long and one tick is equal to 1uS. How I can get width of impulse = 9.885 kHz?
2025-03-05 5:13 AM
>how can I get this width from time ticks?
Its no "width" , its just the frequency. (xxx * exp -1 ) ->
f = 1/time = 1/101(us) = 1/101 * 10exp6 = 9900.99 (your 9.9 kHz then )
"width" of pulse is 101 us.
2025-03-05 5:29 AM
Now it's clear for me. Thank you!