Electronics > Microcontrollers

Calculating SPWM values on the fly. Is it possible with my MCU?

(1/10) > >>

Glenn0010:
Hi,

I'm working on a project to generate a 3phase sinusoidal pwm.

F_fundemnetal = 0.1 - 100 Hz

F_sw = 1-100 kHz.

I would like to calculate the PWM values on the fly if possible instead of a lookup table. I am generating an ISR every time TIM1 overflows and am doing my calculations in there.

I'm using STM32F302R8.

IT works fine at 10 kHz, however I have been struggling to get it to work at 100 kHz with more than one phase calculation. I think there is not enough time for the calculations of the following code.

As far as I'm aware, the FPU should do each of these calculations in 14 clock cycles (running at 72 MHz) so that should be plenty of time to do it even at 100 kHz.

In keil I have enabled the floating point hardware to use single precision in the options for target 1 menu. Then when I am initializing the clocks, I should be enabling the FPU with the following command.


--- Code: ---SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2));  /* set CP10 and CP11 Full Access */
--- End code ---

At this point I'm guessing the FPU is doing the calculations but I am not sure on how to verify this.

Am I missing something? Is the uC/FPU not fast enough for these calculations? Can I somehow optimize the code to make it execute more quickly?


--- Code: ---// interrupt occurs at switching frequency
void TIM1_UP_TIM16_IRQHandler(void)
{
TIM1->SR = ~TIM_SR_UIF; // Clear interrupt

if (PWM_index >= nsamples)
{
PWM_index = 1;
}

PWM_U = MaxPWM_value*sinf((6.28315/nsamples)*PWM_index);
  PWM_V = MaxPWM_value*sinf((6.28315/nsamples)*PWM_index);
  PWM_W = MaxPWM_value*sinf((6.28315/nsamples)*PWM_index);

if (PWM_U <= 0)
{
PWM_U = 0;
}
if (PWM_V <= 0)
{
PWM_V = 0;
}
if (PWM_W <= 0)
{
PWM_W = 0;
}
// //Duty Cycles
TIM1->CCR1 = PWM_U;
TIM1->CCR2 = PWM_V;
TIM1->CCR3 = PWM_W;

PWM_index++;
}
--- End code ---

eutectique:

--- Quote from: Glenn0010 on October 03, 2022, 04:19:17 pm ---
--- Code: ---    PWM_U = MaxPWM_value*sinf((6.28315/nsamples)*PWM_index);
    PWM_V = MaxPWM_value*sinf((6.28315/nsamples)*PWM_index);
    PWM_W = MaxPWM_value*sinf((6.28315/nsamples)*PWM_index);

--- End code ---

--- End quote ---

Just some obvious points:

1. You are doing 3 calculations instead of 1 for no apparent reason.

2. 6.28315 is double, while 6.28315f is float. In the worst case, compiler will generate a call to double division, then a call to double multiplication, then a call to conversion from double to float. Disassemble the function and examine the code.

3. (6.28315f / nsamples) should be a constant, as I would expect. In fact, is it?

Edited clarification: call to double division is a function call, not an FPU instruction. The same applied to multiplication and d2f conversion.

abyrvalg:
Cortex-M4 FPU doesn’t support sinf(), it is done in software (and in much more than 14 cycles for sure). Why don’t you like LUT approach? You can build a pretty small table, like several KB, and use linear approximation, sine is pretty smooth.

Edit: also, are you sure about stripping the negative half-wave? What are you driving with that? Wouldn’t it be better to shift everything up? Or even use some smarter thing like an SVPWM?

eutectique:
You can see how many cycles your code takes. Fire one interrupt and examine the variable.

Beware of compiler-generated prologue and epilogue though, they will fall out of the cycle measurement. It is possible that FP context is saved/restored, among other registers. Again, see the assembly.


--- Code: ---static volatile int32_t cycles = 0;

void TIM1_UP_TIM16_IRQHandler(void)
{
    cycles -= DWT->CYCCNT;

    ... // your code here

    cycles += DWT->CYCCNT;
}
--- End code ---

Edit: fixed copy-paste error

lucazader:
Why not just pre-compute a lookup table and then reference this. the F302R8 has both plenty of flash/ram to be able to do this effectively and efficiently.

This way you can also precompute the table with the correct values for your max timer value.
Saves a whole bunch of execution time.

Navigation

[0] Message Index

[#] Next page

There was an error while thanking
Thanking...
Go to full version
Powered by SMFPacks Advanced Attachments Uploader Mod