You are wasting time reading the output - you set it, so you already know what it is:
for(;;)
{
int out = (timer2Value >= 13) ? GPIO_PIN_SET : GPIO_PIN_RESET ;
HAL_GPIO_WritePin( GPIOA, GPIO_PIN_7, out ) ;
}
If the timing does not then change, then the problem is more likely that your clock is not running at the frequency you think it is.
A more deterministic solution (short of correcting the hardware design), is to set the timer to generate an interrupt at 38000-1 intervals, and toggle the output in the interrupt handler:
void TIM2_IRQHandler()
{
static int out = 0 ;
out = out ? 0 : 1 ;
HAL_GPIO_WritePin( GPIOA, GPIO_PIN_7, out ) ;
}
Or even just:
void TIM2_IRQHandler()
{
HAL_GPIO_TogglePin( GPIOA, GPIO_PIN_7 ) ;
}
If you really want the fastest possible output switching, then you might determine the bitband address of the pin and and toggle that directly:
Given:
__IO uint32_t* getBitBandAddress( volatile const void* address, int bit )
{
__IO uint32_t* bit_address = 0;
uint32_t addr = reinterpret_cast<uint32_t>(address);
// This bit maniplation makes the function valid for RAM
// and Peripheral bitband regions
uint32_t word_band_base = addr & 0xf0000000;
uint32_t bit_band_base = word_band_base | 0x02000000;
uint32_t offset = addr - word_band_base;
// Calculate bit band address
bit_address = reinterpret_cast<__IO uint32_t*>(bit_band_base + (offset * 32u) + (static_cast<uint32_t>(bit) * 4u));
return bit_address ;
}
Then:
__IO uint32_t* gpioA7 = getBitBandAddress( &GPIOA->ODR, 7 ) ;
for(;;)
{
*gpioA7 = (timer2Value >= 13) ;
}
Similarly in an interrupt:
void TIM2_IRQHandler()
{
static __IO uint32_t* gpioA7 = getBitBandAddress( &GPIOA->ODR, 7 ) ;
*gpioA7 = !*gpioA7 ;
}
Though you might choose to initialise gpioA7
externally in the interrupt case.
HAL_GPIO_WritePin
functions, for example through registerDWT_CYCCNT
. I expect that it takes several hundreds of CPU cycles so several us. It might mess your algorithm – Guillaume Petitjean