With embedded C, you'll want to use
<stdint.h> (which is provided by the C compiler) and not
<inttypes.h> (which is provided by the standard C library, and may not be available in freestanding implementations).
For Cortex-M4, there are two good options on calculating the phase offset. First is the 64-bit integer arithmetic T3sl4co1l suggested,
Phase_Offset = ((int64_t)Fout << 32) / Fsw;although I'd use
(uint64_t) and
<stdint.h> instead. The other is to use
float,
Phase_Offset = 4294967296.0f * (float)Fout / (float)Fsw;where the
(float) casts are not strictly necessary, and I only use them to help us humans with reduced cognitive load.
The former approach is exact, and compiles to a
__aeabi_uldivmod() call. On Cortex-M4, the exact implementation depends on the compiler, but is typically implemented using binary division, not hardware division operations. It can be a surprisingly slow operation, but it depends on the values of Fout and Fsw.
The latter approach is limited to 24 bits of precision, but uses the hardware floating-point unit. That is, if Fout < Fsw < 16777216, it is exact. It takes about 35 cycles to run.
The one I'd use, depends on what Fsw is. If I'd use the float approach, I'd also add 0.5f to Phase_Offset before it is (implictly) cast to an integer type, for correct rounding.
(Note, Phase_Offset is a misleading name; consider something like Phase_Step instead.)
So I have done as you suggested to no avail. I was already using the buffered CCR1
Double-check, please.
If CCR1 is not auto-loaded from the buffered value when the PWM cycle restarts, then the symptoms match: at a low enough PWM value, the counter has advanced past the assigned value, and will not trigger.
You can verify this by replacing your function with
// interrupt occurs at switching frequency
void TIM1_UP_TIM16_IRQHandler(void)
{
TIM1->SR = ~TIM_SR_UIF;
TIM1->CCR1 = 51;
}
and seeing if you get any PWM output on the scope. Increment the value (51, above) until you do; the idea is to find the smallest number that you can reliably see the PWM output on the scope.
You then add a small delay just before the TIM1->CCR1 line.
If that makes the PWM again disappear on the scope, you are not using a buffered CCR1.
If even a quarter-of-PWM-period delay makes no change, you are using a buffered CCR1.