why are you trying to reinvent the wheel? I haven't used the STM chips but the solution is pretty much standard. No need to use PLLs / change clock frequency, etc. Just use the built in timers. There also usually exists a compare register (I will be extremely surprised if the STM MCUs don't have this, as even the cheapest MCUs have timer compare registers! arduino as an example and their lowest end micros: ATTINY10 have this!). Knowing the clock frequency of the timer register, you set the value at the comparator register, which then causes an interrupt at that set value.
Exactly this! In fact, better than this. I too haven't worked with the STM's but in Microchip PIC's this takes about half a dozen instructions and then it's all done in HARDWARE. It uses a single timer and two CCP modules. No interrupt service routine at all. The first CCP module acts as the preloader for the timer, and the second uses one of its many Compare modes - in this case the "toggle" mode, which toggles its output pin on every match - to generate your output signal. The resulting output frequency is controlled by your selection of prescaler and comparison values. Effectively zero jitter since there's no software in the loop. Frequency accuracy, short and long term, is determined by the MCU's clock source (likely a crystal). 1MHz and down is easily achievable, and in fact you can go above 1MHz easily too.
Seriously, this could hardly be any simpler. No need for external components at all. Half a dozen lines of setup code and this would be off and running, with the MCU idling with zero workload since the hardware would be handling everything.
I share OM222O's astonishment that the STM's would not already have this capability. It's been a fundamental baseline feature of MCU's for years and years. I'm going to download an STM32 spec sheet right now and take a look, just to satisfy my curiosity. Hopefully others who are already familiar with the STM32's can chime in and resolve the question.
EDIT: I grabbed an STM32 spec sheet from
https://www.st.com/resource/en/datasheet/stm32l471re.pdf. There are many devices, this appeared to be a "lesser" one. Generally the peripherals are common across a given family, differing primarily in how many of each type are on the chip, so the specs for a given peripheral in this spec sheet are likely to be common to the same peripheral in other STM32's.
Turning in our hymnals to section 3.32.2 (page 47), it describes "General-purpose timers (TIM2, TIM3, TIM4, TIM5, TIM15, TIM16, TIM17)". I skipped ahead to the description of TIM15, 16, and 17 which reads:
They are general-purpose timers with mid-range features:
They have 16-bit auto-reload upcounters and 16-bit prescalers.
– TIM15 has 2 channels and 1 complementary channel
– TIM16 and TIM17 have 1 channel and 1 complementary channel
All channels can be used for input capture/output compare, PWM or one-pulse mode output.
The timers can work together via the Timer Link feature for synchronization or event chaining.
I've bolded those features that may bear directly on the question at hand. Auto-reload suggests the timers can be configured to repeat at a given, selectable frequency (e.g. they have an internal comparator register). Prescaler suggests a very wide range of frequencies can be derived from the system oscillator. Output compare suggests they can emit a signal when compare occurs. If that can't repeat on every cycle, there's also the one-pulse mode output which suggests it will pulse when compare occurs. That "one-shot" like behavior may then be driven by a second timer, via the Timer Link feature and its suggestively-named event chaining, to repeatedly generate the pulse (and in this mode, you'd be able to use the first timer to set the pulse width while the second controls the frequency, giving you an additional degree of control over the resulting output).
Sounds to me like a solution is waiting in the STM32 hardware, all that's required is some quality time with the spec sheet. Please report back!