1MHz output compare
also answered on micromouseonline.com
The problem is that the value you add to the CR4 register is very small. By the time the code has run, the counter has already passed the new compare value and has to go all the way around again before you get a trigger. Thus the output frequency will be about ((42000000/(65536+42))/2 = 320Hz or so.
You are effectively asking the code to update the register within 1us and there are several statements before you even test the OC4 interrupt.
The highest frequency I could get with your code and no optimisation was about 140kHz with TIM4_CCR4_Val = 150. even with higher levels of optimisation and a bit of minor tweaking of the code, I could not get a significantly higher frequency with all four channels running. With only one channel running and all the optimisation, I could get a 385kHz output frequency (interrupts at twice that of course). When you add a second or more channels, sooner or later the interrupts will interfere with each other and you will miss the critical timing for the fastest pulse. there will also be some jitter in the others.
I do not believe it is possible to get the channels of a single timer to output pulse trains at different frequencies without using the interrupt and so your maximum frequency is going to be limited by how fast you can respond to that interrupt.
So – I would expect that, at a clock frequency of 84MHz, you cannot reasonably expect more than about 140kHz from a single channel and then only if the other channels are at much lower frequencies.
If you only care about the frequency and can live with narrow pulses, you can set the timer mode to Timing only:
TIM4_OCInitStructure.TIM_OCMode = TIM_OCMode_Timing;
And, in the interrupt handler, pulse the pin directly.
if (TIM_GetITStatus(TIM4, TIM_IT_CC4) != RESET) {
TIM_ForcedOC4Config(TIM4,TIM_ForcedAction_Active);
TIM_ClearITPendingBit(TIM4, TIM_IT_CC4);
uhCapture = TIM_GetCapture4(TIM4);
TIM_SetCompare4(TIM4, uhCapture + TIM4_CCR4_Val);
TIM_ForcedOC4Config(TIM4,TIM_ForcedAction_InActive);
}
With only one channel active, I can then get up to 300kHz but enabling more channels will upset it again because the overhead of setting/clearing the pin takes more time and there will be considerable jitter.
I had not looked into this before and, I have to say, I am disappointed that the STM32 timers cannot do better than this. Perhaps I have missed something.