Author Topic: Calculating SPWM values on the fly. Is it possible with my MCU?  (Read 4507 times)

0 Members and 1 Guest are viewing this topic.

Offline Glenn0010Topic starter

  • Regular Contributor
  • *
  • Posts: 214
  • Country: mt
Calculating SPWM values on the fly. Is it possible with my MCU?
« on: October 03, 2022, 04:19:17 pm »
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: [Select]
SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2));  /* set CP10 and CP11 Full Access */
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: [Select]
// 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++;
}
 

Offline eutectique

  • Frequent Contributor
  • **
  • Posts: 390
  • Country: be
Re: Calculating SPWM values on the fly. Is it possible with my MCU?
« Reply #1 on: October 03, 2022, 06:27:19 pm »
Code: [Select]
    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);

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.
« Last Edit: October 03, 2022, 06:31:34 pm by eutectique »
 

Online abyrvalg

  • Frequent Contributor
  • **
  • Posts: 824
  • Country: es
Re: Calculating SPWM values on the fly. Is it possible with my MCU?
« Reply #2 on: October 03, 2022, 06:32:37 pm »
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?
« Last Edit: October 03, 2022, 06:40:17 pm by abyrvalg »
 

Offline eutectique

  • Frequent Contributor
  • **
  • Posts: 390
  • Country: be
Re: Calculating SPWM values on the fly. Is it possible with my MCU?
« Reply #3 on: October 03, 2022, 06:58:33 pm »
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: [Select]
static volatile int32_t cycles = 0;

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

    ... // your code here

    cycles += DWT->CYCCNT;
}

Edit: fixed copy-paste error
« Last Edit: October 03, 2022, 07:03:54 pm by eutectique »
 

Offline lucazader

  • Regular Contributor
  • *
  • Posts: 221
  • Country: au
Re: Calculating SPWM values on the fly. Is it possible with my MCU?
« Reply #4 on: October 03, 2022, 10:24:38 pm »
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.
 

Offline ogden

  • Super Contributor
  • ***
  • Posts: 3731
  • Country: lv
Re: Calculating SPWM values on the fly. Is it possible with my MCU?
« Reply #5 on: October 03, 2022, 10:46:57 pm »
I would like to calculate the PWM values on the fly if possible instead of a lookup table.

Why? Please try to provide all the reasoning behind your requirement. I am asking because most of experienced engineers would pick lookup table indeed - because it is most resource/cost-efficient solution.
 

Online T3sl4co1l

  • Super Contributor
  • ***
  • Posts: 21658
  • Country: us
  • Expert, Analog Electronics, PCB Layout, EMC
    • Seven Transistor Labs
Re: Calculating SPWM values on the fly. Is it possible with my MCU?
« Reply #6 on: October 03, 2022, 10:54:34 pm »
As said above, be very mindful of what exactly you're telling the compiler you want, and always double-check your intentions against the compiled result (assembly listing).

For example, the compiler might infer that those three calls to sinf() have identical arguments, so can be combined.  But this only happens on -O1 or higher (or, which level of O exactly enables that reduction, I don't recall).  And it is prohibited from happening if the arguments are volatile.  In the latter case, consider making a local copy of the variable, then writing back when you're done.  Do whatever atomic read/write or other buffering you need, separately.  But also, if you're repeating a calculation... just... don't do that in the first place? :)

You can also break down the calculation incrementally.  Keep a sin and cos accumulator handy, and multiply them both as I + jQ of a complex number, times a small angle sin(dtheta) + i cos(dtheta).  Renormalize it once in a while (divide by sqrt(I^2+Q^2) or something like that; there's probably a more streamlined way to do it than the full calculation), to account for rounding error, and, there you go.  One register always has sin(t) and the other cos(t).  More info here: https://en.wikipedia.org/wiki/CORDIC

This is especially feasible on integer machines with hardware multiply, where complex multiplication is straightforward.

Tim
Seven Transistor Labs, LLC
Electronic design, from concept to prototype.
Bringing a project to life?  Send me a message!
 

Offline PCB.Wiz

  • Super Contributor
  • ***
  • Posts: 1535
  • Country: au
Re: Calculating SPWM values on the fly. Is it possible with my MCU?
« Reply #7 on: October 04, 2022, 05:07:27 am »
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.
Am I missing something? Is the uC/FPU not fast enough for these calculations?

See above posts for the problems. You can use a pin to time the actual code time.


Can I somehow optimize the code to make it execute more quickly?

Step back a bit, and ask why do you need to re-calc sine every PWM period ?
If you want variable voltage and variable frequency, yes it can help to create a new sine-fit table in RAM for each modulation depth setting, otherwise you need many tables, but you do not need to do that every 10us.
The motor mechanical inertia and control loops are usually in the many-millisecond regions, and fine adjustments can be managed with simple linear interpolation.

 

Offline langwadt

  • Super Contributor
  • ***
  • Posts: 4414
  • Country: dk
Re: Calculating SPWM values on the fly. Is it possible with my MCU?
« Reply #8 on: October 04, 2022, 07:28:48 am »
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.

Even the DSP lib uses a table, https://github.com/ARM-software/CMSIS/tree/master/CMSIS/DSP_Lib/Source/FastMathFunctions
 

Offline Glenn0010Topic starter

  • Regular Contributor
  • *
  • Posts: 214
  • Country: mt
Re: Calculating SPWM values on the fly. Is it possible with my MCU?
« Reply #9 on: October 04, 2022, 07:51:32 am »
Code: [Select]
    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);

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.

Hi

regards to point 1- this was just to test the speed of the calculation, the phase shift would be added later once it was would be working.
2 - I will give this a try and see any perforamcne benfits I get.

3 - yes it would be depending on what switching frequency I chose. I can simplify it further.

Thanks for the reply and help.
 

Offline Glenn0010Topic starter

  • Regular Contributor
  • *
  • Posts: 214
  • Country: mt
Re: Calculating SPWM values on the fly. Is it possible with my MCU?
« Reply #10 on: October 04, 2022, 07:54:26 am »
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?
I can use the LUT but I was wanting to see if tis method is possible to avoid linear interpolation. If it doesn't work I will go back to LUT. Another reason is I want to have a wide range of switching frequency and fundamental so that leads to a lot of interpolation.

So you are right about the negative half wave, this was an error I had carried on from before. However, it works nicely to visualize where one fundamental period has ended on the scope to measure timings. In the proper version I will need to shit it up like you suggested.
 

Offline Glenn0010Topic starter

  • Regular Contributor
  • *
  • Posts: 214
  • Country: mt
Re: Calculating SPWM values on the fly. Is it possible with my MCU?
« Reply #11 on: October 04, 2022, 07:56:13 am »
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: [Select]
static volatile int32_t cycles = 0;

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

    ... // your code here

    cycles += DWT->CYCCNT;
}

Edit: fixed copy-paste error

Thanks so much for this. I always struggled with figuring out how many cycles some code would take and how to figure out how much time has passed for a specific piece of code. This will be very helpfull
 

Offline Glenn0010Topic starter

  • Regular Contributor
  • *
  • Posts: 214
  • Country: mt
Re: Calculating SPWM values on the fly. Is it possible with my MCU?
« Reply #12 on: October 04, 2022, 07:57:54 am »
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.

The thinking for doing it this way is that I want to operate from anywhere between 2 and 100 kHz, therefore, this would require a lot of interpolation at the higher switching frequency.
 

Offline Glenn0010Topic starter

  • Regular Contributor
  • *
  • Posts: 214
  • Country: mt
Re: Calculating SPWM values on the fly. Is it possible with my MCU?
« Reply #13 on: October 04, 2022, 07:58:44 am »
I would like to calculate the PWM values on the fly if possible instead of a lookup table.

Why? Please try to provide all the reasoning behind your requirement. I am asking because most of experienced engineers would pick lookup table indeed - because it is most resource/cost-efficient solution.
As I replied to some other users, The thinking for doing it this way is that I want to operate from anywhere between 2 and 100 kHz, therefore, this would require a lot of interpolation at the higher switching frequency. Unless I am missing something
 

Offline Glenn0010Topic starter

  • Regular Contributor
  • *
  • Posts: 214
  • Country: mt
Re: Calculating SPWM values on the fly. Is it possible with my MCU?
« Reply #14 on: October 04, 2022, 08:02:04 am »
As said above, be very mindful of what exactly you're telling the compiler you want, and always double-check your intentions against the compiled result (assembly listing).

For example, the compiler might infer that those three calls to sinf() have identical arguments, so can be combined.  But this only happens on -O1 or higher (or, which level of O exactly enables that reduction, I don't recall).  And it is prohibited from happening if the arguments are volatile.  In the latter case, consider making a local copy of the variable, then writing back when you're done.  Do whatever atomic read/write or other buffering you need, separately.  But also, if you're repeating a calculation... just... don't do that in the first place? :)

You can also break down the calculation incrementally.  Keep a sin and cos accumulator handy, and multiply them both as I + jQ of a complex number, times a small angle sin(dtheta) + i cos(dtheta).  Renormalize it once in a while (divide by sqrt(I^2+Q^2) or something like that; there's probably a more streamlined way to do it than the full calculation), to account for rounding error, and, there you go.  One register always has sin(t) and the other cos(t).  More info here: https://en.wikipedia.org/wiki/CORDIC

This is especially feasible on integer machines with hardware multiply, where complex multiplication is straightforward.

Tim

Thanks Tim,  I will try a few quicker solutions to this then, if those fail I will try your method. Thanks for the sugggestion
 

Offline Glenn0010Topic starter

  • Regular Contributor
  • *
  • Posts: 214
  • Country: mt
Re: Calculating SPWM values on the fly. Is it possible with my MCU?
« Reply #15 on: October 04, 2022, 08:04:31 am »
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.
Am I missing something? Is the uC/FPU not fast enough for these calculations?

See above posts for the problems. You can use a pin to time the actual code time.


Can I somehow optimize the code to make it execute more quickly?

Step back a bit, and ask why do you need to re-calc sine every PWM period ?
If you want variable voltage and variable frequency, yes it can help to create a new sine-fit table in RAM for each modulation depth setting, otherwise you need many tables, but you do not need to do that every 10us.
The motor mechanical inertia and control loops are usually in the many-millisecond regions, and fine adjustments can be managed with simple linear interpolation.

The only issue I was seeing is that if I want to operate at 100 Hz at 2kHz, that's 20 different values for the PWM if I want to operate at 100 Hz at 100 kHz that's 1000 values for the PWM, and was thinking that is a lot of interpolation that needs to occur and thought it would distort my output.
 

Online abyrvalg

  • Frequent Contributor
  • **
  • Posts: 824
  • Country: es
Re: Calculating SPWM values on the fly. Is it possible with my MCU?
« Reply #16 on: October 04, 2022, 09:15:19 am »
There should be no problem having a big fine-grained table for the highest frequency (that’s <2KB for a 1000-point table of 16-bit CCRx values) and just incrementing the PWM_index in bigger steps at lower frequencies. And, as langwadt pointed already, the math library sinf() is using a LUT+approximation already (with some unknown step, perhaps, less than 1000 points), so you can do it even better - choose the number of points matching your setup, dropping the approximation completely, eliminate all intermediate operations and use direct CCRx values (already clipped/shifted etc).
 

Offline Siwastaja

  • Super Contributor
  • ***
  • Posts: 8168
  • Country: fi
Re: Calculating SPWM values on the fly. Is it possible with my MCU?
« Reply #17 on: October 04, 2022, 09:24:11 am »
Just use large enough look-up table, simply pick the nearest smaller index. No linear interpolation needed.
 

Online T3sl4co1l

  • Super Contributor
  • ***
  • Posts: 21658
  • Country: us
  • Expert, Analog Electronics, PCB Layout, EMC
    • Seven Transistor Labs
Re: Calculating SPWM values on the fly. Is it possible with my MCU?
« Reply #18 on: October 04, 2022, 09:55:36 am »
The only issue I was seeing is that if I want to operate at 100 Hz at 2kHz, that's 20 different values for the PWM if I want to operate at 100 Hz at 100 kHz that's 1000 values for the PWM, and was thinking that is a lot of interpolation that needs to occur and thought it would distort my output.

If you're worried about distortion, well the great thing is you can run through all the numbers ahead of time, in a spreadsheet or whatever, and not wonder at all.  You can prove it.  Not to mention you have much greater analytical tools at hand than you may in the lab: run an FFT on the series?  No problem!  Error from ideal (sin)?  Easily done.  Simulate inductor ripple (say with the aim of compensating for its centerline value)?  Can do!  Anything else, done practically, means you have to build the whole damn circuit, and program the system, AND fix all the bugs that you put in that also made it blow up multiple times, oh and replace the components that died in the process -- and why make so much work for yourself?! :)

And there are other ways to interpolate:

First off, the naive interpolation requires a set of (x, y) points, performs a division (slow!) to find the distance between points, then multiplies by the offset to get the difference.  And some arithmetic to patch up the differences.

Well, if the table is fixed spacing, the division can be reduced to a constant.  That speeds things up greatly.  (Note that division by a constant is equivalent to multiplication by its reciprocal, give or take some shifting to account for the decimal point.)

If you want to minimize the size of the table (say you're short on memory -- note with 32/64kB Flash to spare, you'll have to be quite busy with other functions to be sweating about merely a couple kB!), maybe you store precalculated divisions for arbitrary sized steps, doubling the amount of data to store per point but greatly reducing computational overhead and number of points required (i.e., more points can be clustered closer in regions of rapid change).

Maybe you choose something more nuanced than a linear interpolation.  We can rank types of interpolation by the order of the function used to smooth it.

Zeroeth order is simply taking the nearest point. Pretty gross, right, well, think of it as the rounding error of a conversion table.  It's a resolution thing, you're always giving up something.  You could always pick more points -- potentially as many as you have possible inputs, which isn't even bad if you had say an 8-bit phase accumulator here.

First order is linear: we take the extra bits (maybe our lookup table is 8-bit (256 elements) but our phase accumulator is 16-bit so we take the low byte (remainder)), and use that to interpolate between adjacent elements.  Nice, but if the curve is supposed to be, well, curved in this spot, well, we're missing a lot; the line segment has to cross through that arc segment in order to best-fit to it.  And it can only do that in two points (or very rarely, three or more, only where the curve doubles back on itself).

Second order is quadratic: we record a value for that curvature, and do a quadratic spline interpolation.

Third order is cubic: we record not just the curvature, but the curvature's curvature, as it were.

And so on.  We can generalize this to any order polynomial, and we merely need to store the start/end points of each segment, and the curvature rates (coefficients) in each segment.

In fact, if we have a smooth enough function, we might not need divide it into any points at all.  We can trivially compute the squaring function f(x) = x^2 by just, well, computing the square.  A quadratic spline will fit any range of this curve perfectly; they're equivalent for this purpose, and the same is true of other locally-quadratic-like curves.

Maybe we need a couple points yet, or a couple higher-order terms, to get a better fit.  A circle for example, has the form f(x) = sqrt(r^2 - x^2).  sqrt() is a heavy-weight function, but we know splines fit that shape very well (indeed, perfectly, for parametric quadratic splines, i.e. {x(t), y(t)}; the explicit function y = f(x) has a harder time, however).

As it happens, sin(x) has the form: x - x^3 / 3! + x^5 / 5! + ..., and since the factorial denominator increases quite quickly (compared to small x), we know this function converges quite quickly.  If we're only interested in the range from say -pi to pi, we might only need a handful of terms to solve it -- even for bit-exact accuracy!

Which in fact, is exactly what they do, in most floating point libraries -- as far as I know.  Floats (i.e., ~24 bits accuracy) might need 5 terms or so.

But if you're only feeding say a 16-bit DAC, do you really need the time taken to compute those higher terms?

Or, for a 100kHz PWM counter clocked at even 100MHz, that's still only 10 bits of timing accuracy (granted, some timers support vernier or extended-precision timing features), so it seems unlikely you need anywhere close to even half the accuracy afforded by full floating point precision!

So, there is advantage to be gained by truncating the calculation earlier, taking matters into your own hands.

Also, as it happens, when the sin(x) Taylor series is truncated, the coefficients can be tweaked a bit to achieve a best-fit condition (the Taylor theorem merely equates a function to a polynomial series plus an error term; only if that error term decreases sufficiently fast with the number of terms, will the truncated series serve as an effective approximation, and at that, with error given by the value of that error term!).  When you're computing values from approxmiations like this, the best idea is to just plug everything into a spreadsheet, or MATLAB/Octave, or Python or whatever programming/mathing environment you prefer, and just let a solver (root finder algorithm) search for optimal values.

Anyway, the value of polynomials, for embedded platforms, is the cheapness of multiplication and addition, at least on most.  Even on AVR, I can calculate the 5th order correction for, say, a thermistor transfer curve, with guaranteed worst-case error comparable to the ADC (12 bits ~ 0.05°C), needless to say, greatly outperforming the spec of the thermistor itself (~1% say).  And all this in just 300 cycles or so -- maybe a bit more than you'd want to spend in an ISR (about 15µs on AVR), but also something that can be done, evidently, many thousands of times a second!  And obviously that can be greatly improved on a 32-bit platform like STM32, by both the higher clock frequency and the wider and more efficient operations.

For reference, earlier this year I did a digital control on AVR, where the ISR computes a new timer value at up to 50kHz.  ADC acquisitions are interleaved with timer interrupts, bringing in process values (power supply stuff, so, voltages and currents, also interleaved with housekeeping stuff like temperature measurements).  The control consists of basic DSP operations: low-pass filters and a PID loop.  It's pretty tight on CPU cycles at max frequency (~80% used), but as you can see, even for such a humble platform, real practical DSP work can be done!  Granted, this is an optimized case (hand ASM), but that degree of optimization will not be necessary on an STM32, at least before going to much higher sample rates.

The low-hanging fruit is to just reduce work required at all.  Avoid floating point (fixed point is absolutely worth understanding), simplify whatever math you can, reduce data flows, and finally only then, look into numerical tricks like these, or the last resort, hand-written ASM.

Tim
« Last Edit: October 04, 2022, 10:00:51 am by T3sl4co1l »
Seven Transistor Labs, LLC
Electronic design, from concept to prototype.
Bringing a project to life?  Send me a message!
 

Offline DavidAlfa

  • Super Contributor
  • ***
  • Posts: 5896
  • Country: es
Re: Calculating SPWM values on the fly. Is it possible with my MCU?
« Reply #19 on: October 04, 2022, 10:00:42 am »
Unless you're tight on space, why overcomplicate things up?
A lookup table should be no issue for a modern stm32 mcu with plenty of storage.
I doubt it needs steps finer than 1°, but in any case you only need a lookup table for 90°, the other quadrants are symmetric/complementary.
Also remember the flash needs some access cycles, not sure how the cache works for data constants, you might consider using the CCM ram for storing the table if not getting fast enough.

Another solution would be DMA, so the PWM self-updates without CPU intervention, multiple PWM can be updated at the same time.
You only need to feed 2 buffers (Actually one, but updated in halves) so the CPU can fill the next buffer while the current one is being transferred, removing the crazy 100KHz ISR overhead and reducing it to just 195Hz using 2x512byte buffers.
I played with this some time ago, feeding two pwm channels at 96KHz as a cheap stereo audio DAC to test this feature.
You might want to check it out:
https://github.com/deividAlfa/STM32F411-Black-pill-USB-wav-player
« Last Edit: October 04, 2022, 11:25:49 am by DavidAlfa »
Hantek DSO2x1x            Drive        FAQ          DON'T BUY HANTEK! (Aka HALF-MADE)
Stm32 Soldering FW      Forum      Github      Donate
 

Offline Glenn0010Topic starter

  • Regular Contributor
  • *
  • Posts: 214
  • Country: mt
Re: Calculating SPWM values on the fly. Is it possible with my MCU?
« Reply #20 on: October 04, 2022, 11:27:02 am »
Hi All!

Thanks for your great feedback. So I did some work this morning and got some decent results.

I am able to execute all 3 PWM calculations in 9.12 us. To measure this at the start of the ISR I turn on a pin then turn it off at the end and measure it with a scope. Though this doesn't leave much margin at 100 kHz. I have used the envelope feature on a scope and this seems to be the absolute maximum.

For reference here is the new code. I tried to do as many calculations as possible outside of the ISR.

Code: [Select]
void TIM1_UP_TIM16_IRQHandler(void)
{
TIM1->SR = ~TIM_SR_UIF; // Clear interrupt

GPIOB->BSRR = (1<<2); // turn on

if (PWM_index > nsamples)
{
PWM_index = 1;
}
if (PWM_index_V > nsamples)
{
PWM_index_V = 0;
}
if (PWM_index_W > nsamples)
{
PWM_index_W = 0;
}

PWM_index_V = PWM_index_V+PWM_index;
PWM_index_W = PWM_index_W+PWM_index;

PWM_U = PWM_Value*sinf((PWM_Freq*PWM_index))+PWM_Value;
PWM_V = PWM_Value*sinf((PWM_Freq*PWM_index_V))+PWM_Value;
PWM_W = PWM_Value*sinf((PWM_Freq*PWM_index_W))+PWM_Value;

TIM1->CCR1 = PWM_U;
TIM1->CCR2 = PWM_V;
TIM1->CCR3 = PWM_W;
PWM_index++;
GPIOB->BSRR = (1<<(2+16)); // turn off
}

However, as many of you suggested it looks like this is doing it in a difficult way for no reason.

Therefore like many suggested I will use a look up table of 360 Values and go from there

 

Offline Glenn0010Topic starter

  • Regular Contributor
  • *
  • Posts: 214
  • Country: mt
Re: Calculating SPWM values on the fly. Is it possible with my MCU?
« Reply #21 on: October 04, 2022, 11:46:48 am »
I would also like to add that as I was testing, most of you were correct about 6.28315 being processed as a double. As soon as I put 6.28315f the processing time for one phase calculation went from 6.4 us to 1.88 us.

here is the disassembler view first for without the f and with the f. Is there a resource which states what each instruction does?



 

Offline eutectique

  • Frequent Contributor
  • **
  • Posts: 390
  • Country: be
Re: Calculating SPWM values on the fly. Is it possible with my MCU?
« Reply #22 on: October 04, 2022, 12:03:08 pm »
Is there a resource which states what each instruction does?

Yes, ARM web site has all the TRMs (Technical Reference Manuals), Arm Cortex-M4 Processor Technical Reference Manual including.

Table of processor instructions
FPU instruction set table

You can also use objdump to disassemble the object file and intermix the listing with the source code:
Code: [Select]
arm-none-eabi-objdump -S your_object_file.o
 
The following users thanked this post: Glenn0010

Offline eutectique

  • Frequent Contributor
  • **
  • Posts: 390
  • Country: be
Re: Calculating SPWM values on the fly. Is it possible with my MCU?
« Reply #23 on: October 04, 2022, 12:07:54 pm »
Therefore like many suggested I will use a look up table of 360 Values and go from there

And then a table of 90 values, for 1° resolution, as was already suggested.
 
The following users thanked this post: Glenn0010

Offline Siwastaja

  • Super Contributor
  • ***
  • Posts: 8168
  • Country: fi
Re: Calculating SPWM values on the fly. Is it possible with my MCU?
« Reply #24 on: October 04, 2022, 01:52:09 pm »
I'm assuming you are driving a motor. If so, consider this:

Brushed motors, and simple BLDC motors are driven with full DC bus voltage of either polarity, in typically 6 steps per electrical rotation, i.e., every 60 degrees. And they are mostly just fine, a some torque ripple can be observed.

Now if you choose to spend just 256 bytes of RAM to implement a 8-bit resolution sine table with 256 elements, no interpolation, no "only store one quarter of cycle" tricks - you have 12600% better amplitude resolution, and 4200% better temporal resolution, than those simple brushed or BLDC implementations. It is quite obvious you won't be able to see any further improvement in vibration etc. even if you increase accuracy further. In fact, such budget implementation is already nearly overkill!

And the implementation is trivial: make the 256-step table, and use uint8_t to denote rotor angle so that 0 - 255 maps to 0 - 358.59 degrees. You get natural wrap-around of angles while calculating, in CPU registers, without any if-elses. Practical use for this wrap-around is you can go between sine and cosine by just adding/subtracting 64 (equiv. to 90 degrees) from the index. Then just index the table with this uint8_t angle directly. No range-checking necessary. And the performance is just excellent.

Beware of some C footguns, however, namely signed integer subtraction overflowing is undefined behavior (unsigned is OK, and defined to work as modulo operation as explained above), and integer promotion rules.
« Last Edit: October 04, 2022, 01:55:23 pm by Siwastaja »
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf