1. Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.
    Dismiss Notice

Help: 3-phase sine generation lookup-table microcontroller

Discussion in 'AVR' started by abicash, Oct 15, 2013.

  1. abicash

    abicash Member

    Joined:
    Feb 12, 2007
    Messages:
    432
    Likes:
    3
    Hello

    I am using 6 channels of a timer to generate PWM waveforms at 16KHz
    These drive 6 MOSFETs.
    I have a sine table of 32 entries
    0 25 49 73 96 118 139 159 177 193 208 220 231 239 245 249 250 249 245 239 231 220 208 193 177 159 139 118 96 73 49 25

    I have a bridge inverter built as shown below

    R Y B
    R^ Y^ B^

    Upon overflow of the 16KHz timer i refresh the overflow values for each channel
    like this R = Y^ , Y = B^ , B = R^

    I have an offset for 120° phase shift between these , which basically are the
    index + 22 (120°)
    index +12 (240°)
    index (0)

    But this is not working.
    I get cross conduction in all vertical limbs.

    How is this usually done? I understand that the R^ must be out of phase with R and so on but that to happen shouldn't Y^ =R ?

    I have looked and looked at various APP notes from Microchip, AVR and various tutorials but am unable to understand this concept.

    Please someone throw some light
    Help needed desperately
     
  2. misterT

    misterT Well-Known Member Most Helpful Member

    Joined:
    Apr 19, 2010
    Messages:
    2,697
    Likes:
    368
    Location:
    Finland
  3. misterT

    misterT Well-Known Member Most Helpful Member

    Joined:
    Apr 19, 2010
    Messages:
    2,697
    Likes:
    368
    Location:
    Finland
    I wrote a minimal project template for a DDS explained in the video lecture.

    Code (C):

    #include <avr/io.h>
    #include <util/delay.h>
    #include <math.h>
    #include <stdint.h>

    #define F_CPU 16000000 // 16Mhz system clock

    // Sine lookup-table. One full cycle.
    volatile int8_t sineTable[256];

    // Accumulator (signal phase) for Direct Digital Synthesis (DDS)
    volatile uint16_t accumulator;

    // Increment value for DDS. This defines the signal frequency
    volatile uint16_t increment;

    void main(void)
    {
        // Initialize the sine table
        for (int i=0; i<256; i++)
        {
            sineTable[i] = (int8_t)(127.0 * sin(6.283*((float)i)/256.0));
        }

        // TODO 1
        /* Setup 8bit PWM.
           Rest of the code assumes that duty cycle is defined by OCR register. Values [0, 255] */

            // .. initialization omitted

        // TODO 2
        /* Setup interrupt for duty cycle update.
           ISR must execute at constant frequency Fs */

            // .. initialization omitted

        /* Calculate increment for constant sine frequency */
            // increment = (Frequency*(2^16)) / Fs;

        /* Infinite loop */
        for(;;)
        {
        }
    }
    /******************************************************************************/

    /*
    Interrupt service routine executes at constant frequency.
    (sine wave sample frequency). Do not confuse this with pwm frequency.
    */

    ISR()
    {
        accumulator += increment;        // Increment accumulator
        OCR = 128 + sineTable[accumulator>>8]; // Update PWM duty cycle
    }
    /******************************************************************************/
     

    If you want to output 3 sine waves with 120 phase shift, then the ISR becomes something like:
    (You will have to setup 3-channel PWM, of course)

    Code (C):

    /*
    Interrupt service routine executes at constant frequency.
    (sine wave sample frequency). Do not confuse this with pwm frequency.
    */

    ISR()
    {
        accumulator += increment;        // Increment accumulator

        // PWM Channel A 0-phase
        OCRA = 128 + sineTable[accumulator>>8]; // Update PWM duty cycle
        // PWM Channel B 120-phase
        OCRB = 128 + sineTable[(accumulator+21845)>>8]; // Update PWM duty cycle
        // PWM Channel C 240-phase
        OCRC = 128 + sineTable[(accumulator+43691)>>8]; // Update PWM duty cycle
    }
    /******************************************************************************/
     
     
    Last edited: Oct 16, 2013
    • Like Like x 1
  4. dave

    Dave New Member

    Joined:
    Jan 12, 1997
    Messages:
    -
    Likes:
    0


     
  5. Mike odom

    Mike odom Active Member

    Joined:
    Feb 21, 2010
    Messages:
    670
    Likes:
    52
    Location:
    Kansas City, KS, U.S.A.

    The problem is you are operating 180° on a 120° system. All phases are 120° out from each other, so how can you turn one on at the same time as turning one off? They don't zero cross at the same time. Basically, your timing will be divided up into 6 60° blocks. For timing, let's say phase R is our sync. When R is at 0°, R goes on and R^ goes off. At this point, B and Y^ will already be on (y is at -60° going down and B is at +60° going down ). When R reaches 30° (going up), y will be at maximum negative peak . When R reaches 60°, then B will be crossing zero heading down, and B goes off and B^ goes on... at this point you will have R Y^ B^on, etc, changing one every 60°.
     

    Attached Files:

    • TMP.jpg
      TMP.jpg
      File size:
      240.3 KB
      Views:
      633
  6. abicash

    abicash Member

    Joined:
    Feb 12, 2007
    Messages:
    432
    Likes:
    3
    Hello
    misterT : I have been able to generate a single phase sinewave already.For this i o/p a PWM resembling a Full rectified sinewave using the LUT (look up table) shared in my original post.I intend to vary the base frequency of the sinewave.
    My PWM is 16KHz = 62.5us, so 32 x 62.5us = 2ms but i need a 180 degree at 10ms , so i have to somehow convert this 2ms into 10ms.
    I call each LUT value 5 times.If i want a higher frequency, i call each value less times and vice-versa.
    I assumed a could use the same LUT for generating 3-phases by offsetting LUT values to each PWM channel by 120 degrees, for this i changed the TimerOverflowISR thus
    TimerOverflowISR ()
    {
    Firstchannel = sintable(duty);
    Secondchannel = sintable(duty+22); //120deg
    Thirdchannel = sintable(duty+11); //240deg
    .
    . //all diagonal channels copy same values like R= Firstchannel = B^
    .//i have 6 channels , 3 upper and 3 lower

    //clear overflow flaf
    }
    But this scheme has problems, since each limb cross conducts so what i though was that my LUT is wrong.

    Mike odom : Thanks for your reply. You are right. But what should be my LUT? and can you explain at top level what i can do in my scheme ? I have briefly explained to MisterT above.
     
  7. misterT

    misterT Well-Known Member Most Helpful Member

    Joined:
    Apr 19, 2010
    Messages:
    2,697
    Likes:
    368
    Location:
    Finland
    Well, my example code does exactly what you explained here. You can modify the lookup table for "Full rectified sinewave" if you want. The code gives you independent control of the Waveform, PWM frequency, Sine signal frequency and Sine signal Phase.

    I'm not sure what the application is (a motor control?). But, you need to keep your PWM frequency much higher than the sinewave sample frequency (duty cycle update frequency). At least 10 times higher.

    Why you have only 180 degrees LUT? The above code generates only 60 deg and 120 deg phase shift because of that. (Assuming you deal with the negative/positive halves differently when you drive the half-bridges)
    Make your life easier and make a full 360 LUT. The AVR has plenty of memory.
     
    Last edited: Oct 15, 2013
  8. abicash

    abicash Member

    Joined:
    Feb 12, 2007
    Messages:
    432
    Likes:
    3
    Hi misterT
    You are right. This is a Solar controlled motor pump.
    My scheme is tesed on a single phase motor and runs great, changing the V/F ratio to maintain torque on solar voltage variation.
    My PWM update frequency in single phase is 16KHz (=PWM freq) and never runs in problems
    But the problem is when i change the same setup to 3Phases.
    If it is not asking much , can you modify my LUT to accommodate 3 phases from 6 channels?
    or write an algorithm based on my code where i change the setup to 3 phases?

    I am so close and yet so far, and this is giving me sleepless nights :(

    EDIT : I tried 360 deg .I am not able to generate a 360 Degrees LUT since i run in negative values
    0, 49, 96, 139, 177, 208, 231, 245, 250, 245, 231, 208, 177, 139, 96, 49, 0, -49, -96, -139, -177, -208, -231, -245, -250, -245, -231, -208, -177, -139, -96, -49
     
  9. misterT

    misterT Well-Known Member Most Helpful Member

    Joined:
    Apr 19, 2010
    Messages:
    2,697
    Likes:
    368
    Location:
    Finland
    3-phase motor control is a little different from just generating sine waves. I believe you have seen many application notes about this. I don't know how to explain it more simply than the papers at the moment.. I would have to refresh my memory about it and I don't have the time now.
     
    Last edited: Oct 15, 2013
  10. abicash

    abicash Member

    Joined:
    Feb 12, 2007
    Messages:
    432
    Likes:
    3
    Hi misterT
    Thanks for the reply.
    For the moment forget motor control, my basic question was, how to generate 3 phases of sinewaves 120 degrees apart, to drive a 6 transistor bridge?
    Since i can generate 3 waves independently, what i assumed was creating an index in the LUT but this scheme has cross over conduction written all over it.
    Thanks anyways, appreciated!
     
  11. misterT

    misterT Well-Known Member Most Helpful Member

    Joined:
    Apr 19, 2010
    Messages:
    2,697
    Likes:
    368
    Location:
    Finland
    6 transistor bridge is build using 3 half bridges.
    Half bridge is just a high-side and low-side FET (transistor).

    Simplest way to drive this is to drive one half bridge with one pwm channel. When the PWM signal is high the high-side transistor conducts, when the PWM signal is low the low-side transistor conducts. If you have 6 output channels, I assume that you have 3 PWM channels and each channel outputs a complementary pair of signals.

    But, there are many other ways to drive the bridge.. and this is very much application and hardware specific.. so we can't forget the motor. You need to first decide and spec what you are doing and how you are going to do it.. before you can write any code.
     
    Last edited: Oct 15, 2013
  12. abicash

    abicash Member

    Joined:
    Feb 12, 2007
    Messages:
    432
    Likes:
    3
    This is how i am doing it for 3 phases with the LUT for single phase(180 deg), where every overflow each PWM channel increments its index value once plus the offset for the necessary 120 deg phase shift.
    i thought a LOT over this but somehow am not able to generate a 360 deg LUT, or a 270 deg - 90 deg LUT , i guess could solve it.
    Regards motor control, it is an induction motor and this is in open loop V/F, where i do NOT measure speed for correction.
    I have written 100 such LUT in an array, each 1% to 100% and there is another index which takes me to an appropriate index based on an ADC value. This HAS worked in a single phase setup successfully.
    But when i shift to 3 phases :eek:
     
  13. misterT

    misterT Well-Known Member Most Helpful Member

    Joined:
    Apr 19, 2010
    Messages:
    2,697
    Likes:
    368
    Location:
    Finland
    360 deg LUT works perfectly with 8-bit PWM. You just have to scale the values between -127 and 127, so that the values fit into 8-bit variable. See my code how to generate this table.
    The numbers work because of how 2's complement work.


    EDIT: actually I think there might be a bug.. let me look into that.

    EDIT: Yeah, I was wrong with the previous one.. You need to add 128 to each value and then cast to uint8.. Ill fix the code example. (2's complement does not work.)

    EDIT: Fixed the code. I left the table as it was, but added 128 to the sine-value just before updating duty cycle in the ISR.
     
    Last edited: Oct 16, 2013
  14. abicash

    abicash Member

    Joined:
    Feb 12, 2007
    Messages:
    432
    Likes:
    3
    Hi misterT

    Thanks for the effort.
    Question on your comment...
    If my max update is 250, can i run between +250 and -250 and my table width is 32?
    so my LUT is
    {0, 49, 96, 139, 177, 208, 231, 245, 250, 245, 231, 208, 177, 139, 96, 49, 0, -49, -96, -139, -177, -208, -231, -245, -250, -245, -231, -208, -177, -139, -96, -49}
     
  15. misterT

    misterT Well-Known Member Most Helpful Member

    Joined:
    Apr 19, 2010
    Messages:
    2,697
    Likes:
    368
    Location:
    Finland
    - You can have a table like that, sure. But note that the values do not fit in a 8-bit variable.
    - If you have 8-bit PWM, the values need to be between -127 and 127.
    - Pulse width modulation can have a duty cycle from 0 to 100%, so you can't have negative values. So you need to add 127 to all values.

    Some bridge driving schemes use a sign bit and a duty cycle value to determine how to drive the bridge. In pseudo code:

    Code (C):

    if (sineTable[i] >= 0) {
       direction = 1;
       PWM = sineTable[i];

    } else if (sineTable[i] < 0) {
       direction = 0;
       PWM = -sineTable[i];
    }
     
    So, once again your application and specs define what you should do.. There are many ways to do things here and we could talk about the different ways forever.

    I think you should forget the code for now and think about how the overall system should work. What kind of signals you need to drive the bridge correctly. When you figure that out, the coding is relatively easy.
     
  16. misterT

    misterT Well-Known Member Most Helpful Member

    Joined:
    Apr 19, 2010
    Messages:
    2,697
    Likes:
    368
    Location:
    Finland
  17. abicash

    abicash Member

    Joined:
    Feb 12, 2007
    Messages:
    432
    Likes:
    3
    Hi i got what you are saying , i had forgotten that you add 128 at the update.
    Likewise i have changed my table thus
    0, 24, 48, 69, 88, 104, 115, 123, 125, 123, 115, 104, 88, 69, 48, 24, 0, -24, -48, -69, -88, -104, -115, -123, -125, -123, -115, -104, -88, -69, -48, -24

    -125 to +125

    so that i add an offset of 125 to make it at 250 max which would mean a 100% duty at 16KHz
    Does this sound right?
     
  18. misterT

    misterT Well-Known Member Most Helpful Member

    Joined:
    Apr 19, 2010
    Messages:
    2,697
    Likes:
    368
    Location:
    Finland
    Yes. Thats sounds right.
     
  19. abicash

    abicash Member

    Joined:
    Feb 12, 2007
    Messages:
    432
    Likes:
    3
    Hi misterT
    That is great. :)
    Only one more help please..
    am a bit raw with numbers and number math in "c"
    My negative values are represented as 2's complement in the compiler(?) so how to make them so that they do not exceed my 250 count?
    I hope you understand my question?
     
  20. misterT

    misterT Well-Known Member Most Helpful Member

    Joined:
    Apr 19, 2010
    Messages:
    2,697
    Likes:
    368
    Location:
    Finland
    I'm not sure I understand what you mean. When you add the offset of 125 to the table values, then the values should be between 0 and 250.. no problem.
     
  21. abicash

    abicash Member

    Joined:
    Feb 12, 2007
    Messages:
    432
    Likes:
    3
    Actually what i meant was

    sintable[] = { //my LUT}
    Here compiler stores negative values as
    -24 as 232
    -48 as 208
    -69 as 187
    -88 as 168 and so on
     

Share This Page