2023-07-07
04:52 AM
- last edited on
2023-07-14
12:42 AM
by
Lina_DABASINSKA
Hello everyone,
currently we are experimenting with the STM32F103R8T and it's timers.
We are trying to toggle Port A5 with about 500kHz using a timer.
We are (by hardware) in need to toggle exactly pin A5 although there is no AF related to a Timer.
What we have been trying is to use the formula update_frequ = SysClk/((PRSC+1)*(ARR+1)).
For toggling with an output of 500kHz we need 1Mhz updatefrequency.
(PRSC+1)*(ARR+1) = 64Mhz/1MHz, so a possible solution should be: ARR = 63, PSC=0,
which doesnt give the desired output, but an all time low.
By testing with ARR=63 and PSC=9-or other way around, (which should result in 100kHz updatefrequ or 50kHz Outputfrequ) we found the timer working correctly.
If we try to change the values of ARR and PSC to acommodate for the factor of ten (desired Updatefrequency 1Mhz) we are not getting the desired Output.
We are using internal clock with 8MHz, scaled to 64MHz Sysclock, which we proved to be okay via MCO by oscilloscope. settings for the timer are as follows:
Have a good day.
2023-07-07 05:57 AM - edited 2023-07-07 06:04 AM
Hello @teppichlichtinnovations, thank you for posting,
In your case, you want an output frequency of 500KHz and by using the formula : Output Frequency = Update frequency / (ARR+1)
ARR = (1MHz/500KHz)-1 which is 1! However, this short-width pulse won't be suitable ofc for your application
But also, by choosing ARR=64, keep in mind that with PSC=0, the timer clock frequency is equal to the system clock frequency which is not the best condition even for power consumption!
Instead, try using a higher value such as 127, and using the same formula you used: PSC = System clock frequency / (Update frequency * (ARR + 1))) - 1 which gives you PSC = 500-1
Hope that helps!
To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
2023-07-07 06:22 AM
We tried your suggestion, it worked, but it results in 1kHz as the math suggests. Anyway we need 1Mhz-updatefrequency and when we try for example ARR=15 and PSC=39 we get 100kHz Updatefrequency, which doesnt fit the math....
any suggestions how to reach 1Mhz?
2023-07-10 12:20 AM
Good morning @Sarra.S ,
unfortunately we were still not able to solve the timing problem.
Perhaps a little more information: Our aim is to reach a timer-update-frequency of 1 Mhz.
What we actually do:
int main(void)
{
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_TIM3_Init();
HAL_TIM_Base_Start_IT(&htim3);
while (1)
{
}
}
* @brief System Clock Configuration
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_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_DIV2;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL16;
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 TIM3 Initialization Function
*/
static void MX_TIM3_Init(void)
{
/* USER CODE BEGIN TIM3_Init 0 */
/* USER CODE END TIM3_Init 0 */
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
/* USER CODE BEGIN TIM3_Init 1 */
/* USER CODE END TIM3_Init 1 */
htim3.Instance = TIM3;
htim3.Init.Prescaler = 15;
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.Period = 39;
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
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();
}
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 */
/* USER CODE END TIM3_Init 2 */
}
/**
* @brief GPIO Initialization Function
*/
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOA_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
/*Configure GPIO pin : PA5 */
GPIO_InitStruct.Pin = GPIO_PIN_5;
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);
}
/* USER CODE BEGIN 4 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim->Instance == TIM3)
{
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
}
}
/* 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 */
which...however results in 50kHz on the Outputpin.
Any hint or help would be appreciated very much.
Thank you!
2023-07-10 04:05 AM
64 cycles per ISR may be marginally viable, but you have to write the the ISR yourself, Cube/HAL won't cut it. Inline asm would be better, C would require highest level of optimization and even then may be not the optimal choice. And even if it would work, it will consume most of the computing power.
Consider changing hardware.
Using timer-triggered-DMA transferring appropriate values to GPIO_BSRR might be another viable option.
JW
2023-07-10 06:29 AM
Hi @waclawek.jan and @Sarra.S ,
thank you for your input. May i ask, where the 64 cycles per ISR come from? How do you calculate that? (May be it's a dumb question, we're just at the very beginning).
Our Hardware actually can't be changed.
Do you have an idea of how fast we could get using HAL and the ISR? The maximum, we reached is 50kHz, which seems to be quite low for us.
We will think about the timer-triggered-DMA-thing, but probably need to read and learn a lot for it 🙂
Thank you.
2023-07-10 07:23 AM
> May i ask, where the 64 cycles per ISR come from?
If you want to execute an ISR every 64 clock cycles, then the ISR execution can't last longer than that.
> How do you calculate that?
It's not easy to calculate the ISR duration or execution of any piece of code, but to start, ISR entry on Cortex-M3 takes 12 cycles and exit takes another 12 cycles; and then generally one to couple of cycles per instruction.
> Do you have an idea of how fast we could get using HAL and the ISR? The maximum, we reached is 50kHz, which seems to be quite low for us.
Try enabling compiler optimization, but don't hold your breath (don't have too much expectations). Cube is not written for efficiency, it's written to impress you how easily can you generate "usual" code with a couple of clicks. You are now in the "not usual" territory.
Did you read the article I've linked to above?
JW
PS. PA5 is SPI1_SCK; if you set SPI to Master and Rx-Only, you'll see continuous clocks on SPI1_SCK. However, due to the dumb GPIO control scheme in the ancient 'F1xx, enabling SPI1 may have consequences on other pins which belong to SPI1, if you want to use them as AF.