Wednesday, February 13, 2013

Demystifying The Use of Table Pointer in SPWM - Application in Sine Wave Inverter


I have previously written quite a few articles on sinusoidal pulse width modulation (SPWM). I've discussed about how to generate the sine table, how to implement it, how to practically generate the SPWM signals (with example code) and also how to implement feedback with simple sine table manipulation with table pointer instead of complex PID control. All these methods have one thing in common regarding the implementation - use of the sine table and its control with the table pointer. Whether you use or implement feedback or not, the table pointer is used to access and retrieve values from the sine table.


Before reading or going through this article, I suggest you go through these first:




It took quite a while for me to understand exactly how the table pointer works in this case – to retrieve data from the sine table and feed it to the PWM module and generate the required output 50Hz frequency (you can use any frequency but my requirement is 50Hz). I had come across the method and its explanation when coding for the dsPIC33 microcontroller while I was attempting to make a sine wave inverter using the dsPIC33. After a lot of research and thinking, I could finally implement it for PIC16.

While many have seen my posted codes and explanations regarding sinusoidal pulse width modulation (SPWM), some people have requested me to explain how the table pointer in the interrupt works. Remembering my difficult experience with this, I decided to write up this article to help all of you who are struggling with this to help clear your doubts and make you understand exactly how it works so that one can implement SPWM with a sine table with any number of table values and for any desired output frequency.

Let’s take a look at the code line by line. And I’ll explain it all. Keep in mind that the target microcontroller is a PIC16F684 running off an oscillator frequency of 16MHz. So, if you’re attempting to “port” the code to any other microcontroller keep in mind that the registers will/may be different from those in the PIC16F684.


//----------------------------------------------------------------------------------------
//Programmer: Syed Tahmid Mahbub
//Target Microcontroller: PIC16F684
//Compiler: mikroC PRO for PIC (Can easily port to any other compiler)
//-----------------------------------------------------------------------------------------


unsigned char sin_table[32]={0,25,49,73,96,118,137,
159,177,193,208,220,231,239,245,249,250,249,245,
239,231,220,208,193,177,159,137,118,96,73,49,25};


unsigned int TBL_POINTER_NEW, TBL_POINTER_OLD, TBL_POINTER_SHIFT, SET_FREQ;
unsigned int TBL_temp;
unsigned char DUTY_CYCLE;

void interrupt(){
     if (TMR2IF_bit == 1){
        TBL_POINTER_NEW = TBL_POINTER_OLD + SET_FREQ;
        if (TBL_POINTER_NEW < TBL_POINTER_OLD){
           CCP1CON.P1M1 = ~CCP1CON.P1M1; //Reverse direction of full-bridge
        }
        TBL_POINTER_SHIFT = TBL_POINTER_NEW >> 11;
        DUTY_CYCLE = TBL_POINTER_SHIFT;
        CCPR1L = sin_table[DUTY_CYCLE];
        TBL_POINTER_OLD = TBL_POINTER_NEW;
        TMR2IF_bit = 0;
     }
}

void main() {
     SET_FREQ = 410;
     TBL_POINTER_SHIFT = 0;
     TBL_POINTER_NEW = 0;
     TBL_POINTER_OLD = 0;
     DUTY_CYCLE = 0;
     ANSEL = 0; //Disable ADC
     CMCON0 = 7; //Disable Comparator
     PR2 = 249;
     TRISC = 0x3F;
     CCP1CON = 0x4C;
     TMR2IF_bit = 0;
     T2CON = 4; //TMR2 on, prescaler and postscaler 1:1
     while (TMR2IF_bit == 0);
     TMR2IF_bit = 0;
     TRISC = 0;
     TMR2IE_bit = 1;
     GIE_bit = 1;
     PEIE_bit = 1;
    
     while(1);
}
//-------------------------------------------------------------------------------------


Here's the circuit diagram (the hardware portion of SPWM implementation):



Fig. 1 - Circuit Diagram (Click on image to enlarge it)



For the MOSFET drivers, you can use the common high-low side drivers – IR2110. For a thorough tutorial on using the IR2110, check out:

Another tutorial (this one regarding low side MOSFET drivers):



Now, back to the software side of things. The registers responsible for the automatic updating of the duty cycle are SET_FREQ, TBL_POINTER_SHIFT, TBL_POINTER_NEW, TBL_POINTER_OLD and DUTY_CYCLE. So, I’ll get to this a little later. Let me deal with the rest first.

Setting ANSEL to 0 selects the ADC-associated pins as digital and this is done since the ADC isn’t required for this program, and this frees up the pins multiplexed to the ADC so that they can be used as digital IO lines. Setting CMCON0 to 7 does the same thing, just for the comparator instead of for the ADC.

PORTC bits 0 to 5 are all made input at first. CCP1CON is set to 0x4C. This sets the ECCP mode to “PWM Mode” with P1A, P1B, P1C and P1D set active-high. Timer 2 is turned on and a polling check is done to check if Timer 2 has overflowed or not. When Timer 2 overflows, the interrupt flag is cleared and PORTC bits are selected as output pins. Timer 2 interrupt, global interrupt and peripheral interrupt are enabled.

Now the program just loops in the infinite endless while loop. So, the program now just does nothing – but execute the interrupt when it occurs. Since PR2=249, the time period is 62.5us. I assume you can do the math. So, an interrupt occurs every 62.5us.

Now on to the main part of this code – the interrupt. Every 62.5us the interrupt service routine is “entered” (if you think of it like that in terms of program “flow”) and executed.

In the main() function, I had assigned the value of 410 to SET_FREQ. SET_FREQ determines the output frequency of the sine wave, which in our case here is 50Hz. You’ll soon see how.

In the interrupt, the variable TBL_POINTER_NEW is updated – every 62.5us it is increased by 410. TBL_POINTER_NEW is a 16-bit variable and at the beginning of program execution has a value of 0. So, after the first interrupt it holds 410, after the second interrupt 820, after the third 1230 and so on. After 159 interrupts, TBL_POINTER_NEW holds 65190. So, at the next interrupt, TBL_POINTER_NEW overflows and holds 64.

The interrupt occurs every 62.5us. At each interrupt TBL_POINTER_NEW is increased by 410. At the 160th interrupt, TBL_POINTER_NEW overflows, just as it does the 320th interrupt, the 480th interrupt and so on.

Initially TBL_POINTER_NEW holds 0 and on subsequent interrupts, TBL_POINTER_NEW holds 410, 820, 1230, 1640, 2050, 2460, 2870, 3280, 3690, 4100 and so on.

TBL_POINTER_SHIFT right-shifts TBL_POINTER_NEW eleven times and stores that value. Right shifting 11 times is the same as dividing by 211 (211 = 2048) – just more efficient. When the microcontroller starts up, TBL_POINTER_SHIFT holds 0 and on subsequent interrupts, TBL_POINTER_SHIFT holds 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3 …..  and so on. Now, the trend is that TBL_POINTER_SHIFT holds the same value for 5 consecutive interrupts – go on, you can do the math. Why 5 times? We’ll see that a little later.

After TBL_POINTER_NEW is shifted 11 times, DUTY_CYCLE is assigned the resultant 5-bit value. This acts as – or rather is – the table pointer and the required value is retrieved off the sine table. This value is assigned to CCPR1L, thus setting the appropriate duty cycle.

Now let’s see why TBL_POINTER_SHIFT is needed to be incremented every 5 interrupts and how we’ve done that.

Our frequency is 50Hz – time period is 20ms. A half cycle takes 10ms. Recall that the sine table used is only for half a cycle. So, the 32 values must be called such that they make up the half cycle. The interrupt service routine is executed each 62.5us and so, retrieving all the values from the sine table and using them to update the duty cycle takes a total time of 62.5us * 32 = 2000us (assuming each value is retrieved/called once). That’s 2ms. But our half cycle is 10ms – 5 times larger than what we have now. So, we increase the time five folds. How? By calling each value from the table 5 times instead of only once. So, the time involved is now 32 * 62.5us * 5 = 10000us = 10ms.

This calculation we’ve just done is related to the frequency – 50Hz desired frequency and thus 10ms half cycle. I’ve shown this “backward” to explain why this has been chosen but remember that the microcontroller doesn’t know you want 50Hz frequency. The microcontroller doesn’t know that the desired time is 10ms.

So, now you know the answer to why I’ve called each sine table value 5 times: to ensure that the sine table that has 32 values occupies the entire 10ms. Now, how did I make it repeat 5 times? By setting SET_FREQ to 410. You might be wondering how this works. Well, it works this way.

SET_FREQ = 410. Each interrupt, TBL_POINTER_NEW is increased by 410. Every 5 interrupts, TBL_POINTER_NEW is increased by 2050 (compared to the initial value). 211 = 2048. Since TBL_POINTER_SHIFT divides TBL_POINTER_NEW by 2048, when TBL_POINTER_NEW increases 5*410 times, TBL_POINTER_SHIFT increases once. So, the number of repeats (5 in this case) is equal to the number of interrupts it takes for TBL_POINTER_SHIFT to increase by one, which is equal to the number of times it takes for SET_FREQ to equal or cross 211 (=2048). Since SET_FREQ = 410, the number of times to cross 2048 is 5 and that is the number of times each table value is called. So, the table pointer is incremented every 5 interrupts. Thus SET_FREQ determines the frequency. If we had set SET_FREQ to 200, the number of times to cross 2048 would be 11, as 200*10 = 2000 (less than 2048) but 200*11 = 2200 (more than 2048). Thus each sine table value would be called 11 times – the table pointer would be incremented every 11 interrupts. The output time period of the sine wave would then be 2 * 32 * 62.5us * 11 = 44000us = 44ms. The output frequency would thus be 22.7 Hz instead of the 50Hz we have now.

SET_FREQ can be calculated as {65536/ (32 * 5)} = 409.6 = 410 rounded off to the nearest integer. That’s [216/{(Number of sine table values) * (Number of times each value is to be called)}].

I’ve talked about SET_FREQ, TBL_POINTER_NEW, TBL_POINTER_SHIFT and right shifting eleven times. Now you may ask why eleven times. Why not 5 or 10 or 12 or any other value? The reason is that we have a sine table with 32 values. 32 = 25. Shifting a 16-bit variable eleven times to the right leaves us with a 5-bit value – one between 0 and 31. These 5 bits are the upper most (most significant) 5 bits. This 5-bit value is the sine table pointer. This works in conjunction with the number of sine table values and the value of SET_FREQ to set or determine the output sine wave frequency. If we had 64 sine table values, we would right-shift TBL_POINTER_NEW 10 times instead of 11 so that the shifting operation results in a 6-bit value. 26 = 64 and that is the number of sine table values we have – the table pointer would have a value between 0 and 63.

At the end of this tutorial, I have covered an example. You should follow the example and I’m sure things will be clear by then (I know that the amount of information presented thus far is overwhelming and difficult to grasp!).

In the interrupt, after the duty cycle is set, TBL_POINTER_OLD is assigned the value of TBL_POINTER_NEW. When TBL_POINTER_NEW is first assigned 410, TBL_POINTER_OLD holds 0. The 11-bit shifting is done. The duty cycle is set and then TBL_POINTER_OLD is set. So, the TBL_POINTER_OLD update trails TBL_POINTER_NEW update. So, every interrupt until TBL_POINTER_NEW overflows, TBL_POINTER_NEW is greater than TBL_POINTER_OLD.

When TBL_POINTER_NEW = 64370 and the ISR is to be executed, TBL_POINTER_OLD also holds 64370. TBL_POINTER_NEW is increased to 64780 and then the sine table value is called and TBL_POINTER_OLD is then updated to 64780. The next interrupt, TBL_POINTER_NEW is increased to 65190 and the “if condition” is again false since at that stage TBL_POINTER_OLD holds 64780 – TBL_POINTER_NEW > TBL_POINTER_OLD. Then at the end of the ISR, TBL_POINTER_OLD is assigned 65190. And now comes the interesting part. TBL_POINTER_NEW now holds 65190 and TBL_POINTER_OLD holds 65190. 410 is to added to TBL_POINTER_OLD and TBL_POINTER_OLD overflows to hold 64. Now, TBL_POINTER_NEW (which holds 64) is less than TBL_POINTER_OLD (which holds 65190) and the if condition is true and P1M1 bit of CCP1CON is inverted. This inverts the direction of the full-bridge drive. When P1A and P1D were being driven previously, P1B and P1C will be now be driven and vice versa. By inverting the direction of the full-bridge drive, we are carrying out the next half cycle with the same duty cycle values and sequence, but in the opposite direction – as is necessary (think AC waveform and opposite half cycle). This happens every (32*5 = 160) interrupts – when all the values of the table have each been called 5 times. Since TBL_POINTER_OLD then has a small value again, since it overflowed, TBL_POINTER_SHIFT will then be equal to 0, meaning that the table pointer has restarted from zero and the SPWM starts over again. So, TBL_POINTER_SHIFT, on subsequent interrupts has the values: 0,0,0,0,1,1,1,1,1,2,2,2,2,2,3,3,3,3,3,………..30,30,30,30,30,31,31,31,31,31,0,0,0,0,0,1,1,1,1,1,……. And so on.

Now that I’ve explained how it all works (I have a hunch you haven’t fully grasped everything yet), let’s see how you can make necessary modifications to suit your purpose (and make sure you grasp it all properly).

Now let’s consider a situation where we use 20kHz instead of 16kHz, have 64 sine table values and a sine wave frequency of approximately 30Hz.

We would set the number of shifts to 10 instead of 11 so that the shifting operation results in a six-bit value: 26 = 64, since we have 64 sine table values.

For 20kHz frequency, the time period is 50us. 50us * 64 = 3200us (= 3.2ms). Time period for 40Hz is 25ms – half a cycle is thus 12.5ms. As calculated above, the entire calling of the sine table, if each value is called once, takes a total time of 3.2ms. That’s much less than the required 12.5ms and so, each sine table value should be called more than once. Calling each value four times means a total time of 12.8ms, which is close to 12.5ms (the required calculated time). So, each value is to be called four times. The frequency is (1/{0.0128*2})Hz = 39.1Hz – slightly off our target 40Hz.

Earlier, I had mentioned:
SET_FREQ = [216/{(Number of sine table values) * (Number of times each value is to be called)}]
So, in this case, it’ll be SET_FREQ = [216/{64*4}] = 256.

Now to verify this.

SET_FREQ = 256. 256* 3 = 768 (less than 210). 256 * 4 = 1024 (equal to 210). So, each 4 interrupts, the value of the sine table pointer will increase by 1.

So now we have:
SET_FREQ = 256;
TBL_POINTER_SHIFT = TBL_POINTER_NEW >> 10;


And that’s it. It’s not too difficult once you grab it. The main part of the interrupt is 7 lines only! And it's taken me 6 pages to explain it! And I hope I’ve helped you understand it clearly so now you can edit my code to your requirement or even write a new code from scratch! Let me know your comments and feedback! Happy coding!


80 comments:

  1. Hi im Hema (PG scholar), for my project i am in need of 3 PWM channels.so i chose pic16f777a, but it is not available in proteus software. what shall i do?

    ReplyDelete
    Replies
    1. please help me .
      How i can use this code for pic16f88 ??

      Delete
    2. You can't use this for PIC16F88 because PIC16F88 does not have ECCP module. You will have to make large modifications and do without the ECCP module, relying heavily on software.

      Regards,
      Tahmid.

      Delete
    3. Hi hema,

      If PROTEUS simulation is a must, then you must change your microcontroller since, as you know, PIC16F777A is not available in PROTEUS.

      Here are some microcontrollers that are available in PROTEUS and have 3x ECCP modules:

      PIC18F6527
      PIC18F6622
      PIC18F6627
      PIC18F6628
      PIC18F6722
      PIC18F6723
      PIC18F8527
      PIC18F8622
      PIC18F8627
      PIC18F8722

      These dsPIC33 microcontrollers are available in PROTEUS have Motor Control modules that you can make use of (if you can use dsPIC33, I highly recommend them):

      dsPIC33FJ12MC201
      dsPIC33FJ12MC202
      dsPIC33FJ16MC304
      dsPIC33FJ32MC202
      dsPIC33FJ32MC204

      Hope this helps!

      Regards,
      Tahmid.

      Delete
  2. @ Anonymous,

    I have written an article regarding the generation of sine wave without ECCP module - using only one CCP module. I have used PIC16F877A which has only CCP modules. Like PIC16F877A, PIC16F88 doesn't have any ECCP module. But PIC16F88 does have a CCP module which you can use to generate the sine wave using my program/method with slight modification as required to port it to PIC16F88.

    View the article here:

    Sine Wave Generation without ECCP - Using single CCP Module of PIC16F877A
    http://tahmidmc.blogspot.com/2013/02/generation-of-sine-wave-without-eccp_16.html

    Regards,
    Tahmid.

    ReplyDelete
  3. thank you very much for your help

    ReplyDelete
    Replies
    1. I'm glad to have helped.

      I wish you success in your project!

      Regards,
      Tahmid.

      Delete
  4. Please where did u set the value of PR2 in the code. Aw do I make it work in proteus sim

    ReplyDelete
    Replies
    1. I have set PR2 to 249 in the code.

      Regards,
      Tahmid.

      Delete
  5. I cant see any PR2 settings in the code and when I run the simulation, I dont see anything on the oscilloscope.

    ReplyDelete
    Replies
    1. I have set PR2 to 249 in the code. Check the outputs at PIC pins P1A, P1B, P1C and P1D. Ensure that you have built the program successfully and that you have set the correct configuration settings.

      If you upload your Proteus file, I can take a look.

      Regards,
      Tahmid.

      Delete
  6. Hi Tahmid
    If I am corect set frq for 60Hz is 492
    All rest is the same

    I like to tray make 60Hz inverter

    ReplyDelete
    Replies
    1. Yes, that's correct. SET_FREQ = 492 for 60Hz.

      Regards,
      Tahmid.

      Delete
    2. hi, tahmid how did it came out 492 for 60hz? whats the formula?

      Delete
  7. Thanks Tahmid

    I like to use PIC16F616 for it suply voltage 2-15v.
    If you look at data for the chip you'll see that it has internal oscillator of 4MHz.
    Please help

    ReplyDelete
    Replies
    1. The supply voltage is up to 5V, not 15V. I'm sure you already know that and it was a typo on your part.

      For applications where timing is critical, it is better not to use the internal oscillator. Use an external crystal oscillator or similar. You'll (usually) get better accuracy, precision and lower drift with changing external factors, such as temperature, etc.

      Regards,
      Tahmid.

      Delete
  8. I am hoping to drive mosfets directly from PIC if posible .
    Minimal part count sg3525 to drive ferrite transformer PIC to chop for 60Hz 120V for my windmill project.
    Your help is great so far

    ReplyDelete
    Replies
    1. Thanks.

      Use a driver such as TC427 to drive the MOSFET directly from the PIC.

      However, where possible, I recommend using dedicated PWM controllers such as SG3525 as they reduce program complexity and make control (using the PWM controller) rather simple.

      I hope that answers your question.

      Regards,
      Tahmid.

      Delete
  9. This comment has been removed by the author.

    ReplyDelete
    Replies
    1. Sory PIC16HV616.
      As I can see it is the same as PIC16F684
      Thanks for replaying

      Delete
  10. Hi Tahmid,

    I am trying to make a sine wave inverter using dsPIC33FJ16GS504, please let me know the procedure of generating sine wave with this pic, what factors to consider and all.

    Regards,

    ReplyDelete
    Replies
    1. The factors to consider are, if not the same, similar. The difference will lie in the implementation.

      Regards,
      Tahmid.

      Delete
  11. Dear Tahmid

    I've run your code: sine by PIC16F684. But the last place on the oscillators.

    I want send Email to you, but I have not your email.
    I send link (files : oxilo.JPG and invert.rar) : http://www.4shared.com/account/home.jsp#dir=z5tArTzu
    Can you repair?
    My email : mr.danghoangtung@gmail.com
    Help me.
    Thanks Tahmid
    Bests Regard
    Tung

    ReplyDelete
  12. Hi Tahmid,

    thanks for explaining the above but why cant the same result be gained by simply incrementing one variable and using it to point to the sine values sequentially then resetting that variable when it becomes equal to the number of values? I have loaded and understood your code and method but can't understand why this simpler method will not produce the same results. When I run my code in Proteus it only shows the middle few values/pulses then flat for the rest of the signal. Is the code "falling over it's self" because it's not using large numbers or could it be a fault in Proteus? Could really do with some advice on this as I can't find any obvious fault in my code. I'm waiting for an oscilloscope to be delivered (which I needed any way) so I can determine whether it is a fault in the simulation software but when I run your code it simulates fine.

    Regards,

    Dale

    ReplyDelete
    Replies
    1. Do you mean to say that you're going to have all the values in the sine table and don't want to repeatedly call one value? But instead leave that to the sine table?

      Upload what you've done so far. I'd like to take a look.

      Regards,
      Tahmid.

      Delete
  13. hi tahmid, can you show me how to generate code for multicarrier signal.For example, sine signal is compared with four carrier signals?

    hope you can help..

    ReplyDelete
    Replies
    1. Why do you require comparing sine signal with four carrier signals? Why is the multicarrier signal approach required?

      Delete
  14. Hello Tahmid,

    I got error CMCON0 = 7 undeclared identifier when build to PIC16F690, Can I remove this without affecting operation of the given codes or function? seems build successful if I comment it out...

    hope for your reply.

    regards,

    ReplyDelete
    Replies
    1. Remove that line and instead write:

      CM1CON0 = 0;
      CM2CON0 = 0;


      The PIC16F690 has 2 analog comparators and thus the change is required. Consult the datasheet for further details.

      Hope this helps!

      Regards,
      Tahmid.

      Delete
  15. sir can u help me to make a adjustable frequency just a switch from ports to change SET_FREQ = 492;
    to 3 other set of frequencies?

    ReplyDelete
    Replies
    1. The 3 frequencies will have three corresponding values of SET_FREQ. You will just need to change SET_FREQ to the required value to get your required frequency. The article here explains how to calculate the value of SET_FREQ for different frequencies. If you have any further questions, feel free to ask!

      Regards,
      Tahmid.

      Delete
  16. hi Tahmid, can i use sg3525/tl494 pwm for chopper transformer and after that i convert it to dc volt and then use your above h-bridge circuit for output as in china inverters or apc use????
    design become like this 12v -> chopper transformer -> 280v ac now convert it in 280v dc -> and convert in Ac for load dirctly on h-bridge ...

    ReplyDelete
    Replies
    1. Yes you can do this. That's how high frequency inverters work.

      Regards,
      Tahmid.

      Delete
  17. sir please tell what will be the value of set frequency with 80 or 90 samples and frequency 50HZ

    ReplyDelete
    Replies
    1. Please go through this article thoroughly. I've covered this in this tutorial. If, after reading, you have doubts or specific comments, feel free to ask.

      Regards,
      Tahmid.

      Delete
  18. Sir please can you let me know where the error is in my calculations for SET_Freq and PR2 because I am using a Quartz of 4MHz and wondering a switching signal of 20KHz and then controlling H-bridge which gives at the output 50Hz;for that I determined as follow the following values:
    1.PR2=((1/PWM_Period)/(1/Fosc)*4*1)-1 So I found:((1/20000Hz)/(1/4000000Hz)*4*1)-1)=49
    2.SET_Freq=293; SET_FREQ = [65536/{(Number of sine table values) * (Number of times each value is to be called)}];I am using 32 values in the sine table and I saw that at 50Hz the period =20ms;its half is 10ms and then at 20KHz ,the period is 50us so;50us*32=1600us (=1.6ms) for completing a half cycle of 10ms calling 32 values each one has to be called 7 times;thus 1.6ms*7=11.2 approximately equals 10ms.

    So SET_Freq=(65536/(32*7))=292.57 so I took SET_Freq=293.the problem I have is that my circuit at the pins of PIC I am not getting 50Hz but 14.76Hz;can you please tell me where I am wrong?Thanks for your helpful blogs.

    ReplyDelete
  19. slam bai i am awais from pakistan and i have assigned the project swmp with output uupto 380 volts plz tell me how can i use ir 2101 for mosfet driving and connection with ferrite core transformer i am using the tl 494 pwm controller

    ReplyDelete
    Replies
    1. What is swmp? Did you mean SPWM?

      Does your output need to be adjustable?

      Describe your specifications in greater detail.

      Regards,
      Tahmid.

      Delete
    2. http://sandysplash.blogspot.in/

      Delete
  20. thanks in advance brother reply plz

    ReplyDelete
  21. Hi Tahmid

    can i get variable frequency if i change SET_FREQ value continuously?

    ReplyDelete
    Replies
    1. Yes, you can alter the frequency by altering the value of SET_FREQ.

      Regards,
      Tahmid.

      Delete
  22. Nice Post!! pretty informative..thanks for providing such a nice post.
    China Inverter

    ReplyDelete
  23. Hi Tahmid,

    That's excellent explanation of sine generation.
    Could you please explain the feedback loop?
    suppose we generate 230V from SPWM, how do we maintain the voltage on no-load to full-load condition?
    Thanks in advance.

    ReplyDelete
    Replies
    1. Thank you for the compliments.

      What I did for feedback was use a "variable" sine table. Basically the sine table had a set of values for different duty cycles and loaded the required set of values depending on the output volatge and if it needed to be increased or decreased.

      Take a look at this:

      http://tahmidmc.blogspot.com/2012/11/feedback-in-sine-wave-inverter-pic16f.html

      Regards,
      Tahmid.

      Delete
  24. Really nice blog!! I am glad to read your post, pretty informative..thanks for providing such a nice post.
    China Inverter

    ReplyDelete
  25. Hi Tahmid

    I have generated a sinewave with a single PWM pin on a microcontroller.
    Across the PWM pins(after AND gate) if i connect a RC filter, i get a good sinewave.
    But now i connect this to an H bridge with driver(which is working from another inverter) i see lots of problems.
    1)Cross conduction, even after adding 0 at both ends)
    2)crooked sinewave
    What could this be? Is it that, in the ISR updates are slower than overflow period of 62.5us?.Although my controller is running at 8MHz.
    i checked that the ISR requires close to 37usec.How can the code run then?

    ReplyDelete
  26. Hello Tahmid great article

    Can you write a tutorial to generate 3 Phase waves using similar method?

    ReplyDelete
  27. I have built the circuit but my transistors burnt at output.what do i do?

    ReplyDelete
  28. Hello

    I am trying the single phase LUT with different index pointers to generate a 3 phase PWM.
    i use
    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

    and generate 3 PWMs at 0, 120deg and 240deg with differing indexes.
    But i find that drives in same limbs cross conduct.
    How is this normally done? can you please help me?
    I have a 6-channel timer to generate a 16KHz PWM on all 6 channels

    ReplyDelete
  29. hello mr tahmid....can this program run for pic18F4431...i need to do project for 3 phase spwm to run induction motor...thank for ur advise mr tahmid...

    ReplyDelete
  30. Can you share me the full schematic of the system is not true sine inverter. I needed it. You send her into luankdt01@gmail.com address. Thank you very much.

    ReplyDelete
  31. Hi tahimid,
    I am doing my mtech thesis on transformerless inverter for pv system. I am planning to use PIC for generating PWN signals (SPWM method). Since I am a beginner can you give me instructions to start...

    ReplyDelete
  32. hi Tahmid, i'm doing a project about modulation & demodulation ASK signal use pic 16f887.In demodulation circuit, i use ADC of pic to decoder the original signal (the original signal is a char 8 bit EX:''10101010 '') but i can't do it. Can you help me? Thank you so much!

    ReplyDelete
  33. I actually added your blog to my favorites and will look forward for more updates. Great Job, Keep it up.

    ReplyDelete
  34. Hi
    What happens when you have like this: a 1024 point sine table for [0..pi/2] you want 50 Hz for output frequency and have a PWM frequency of 1500 Hz? I get that the total time would be larger then even the 20ms period
    Thanks in advanced

    John

    ReplyDelete
  35. Hello,

    Have made ​​several attempts to implement this code using a PIC18F4550 but did not get any satisfactory result (I have no experience with the MikroC compiler). You could edit the code to use this pic, compile and send to me the files on it (design. mcppi and. hex)?

    Thanks in advance!

    Lenilson

    ReplyDelete
  36. Hi
    I have to generate SPWM for 3 phase inverter .But with Your logic the number of sine values should always be 2 raised to some value then how will I be able to generate 120 degree out of phase signals?Please do reply

    ReplyDelete
  37. Hello Tamihd:

    I know as mikroC program so I can not fully understand the whole development given here:

    1 Tomas 32 ​​values ​​(sine table with PR2 + 1 = 249 and Tpwm= 62.5 us)
    2 The half cycle of the sine wave of 50 Hz is 10 ms

    Then these data values ​​must have 160 (10ms / 62.5 us) but there are only 32 values​​. This means that the 32 values ​​are repeated 5 times in the 10 ms

    Question 1 Since no representing the repetitive values ​​in each of the true value of energy stored in each of them, it does not distort the output sine wave output filter requiring a larger LC ?.

    Question 2: To design the ferrite transformer which is the frequency used ?.

    Question 3 could rethink this development considering the 160 values ​​within 10 ms and stop using pointers?.

    José

    ReplyDelete
  38. hello Tahmid ,
    your articles are really helpful.I have a doubt .

    how does the implementation of Spwm in practically differ from that of silmulations??
    1)If i want to change the number of pulses per half cycle in SPWM say around 12 or 30 and my reference signal is 50Hz sine, then the pwm frequency comes around in Hz and for this the value of PR register exceeds the max value it can hold of 256.how to deal with this

    2)Also Another doubt is that should the sine table values be taken according to the number of output pulses we can need
    (generation and implementation of sine table)

    3)how to use Timer interrupts to send the value as many times as we want to make sure that the output frequency is 50hz

    ReplyDelete
  39. This comment has been removed by the author.

    ReplyDelete
  40. Tahmid: I can generate SPWM code for 60 Hz using a PIC16F874 but I cannot generate any code outside of the ISR. Does this interupt program use all the processor time or do I have something wrong in my interupt?

    ReplyDelete
  41. Hi Tahmid,
    I build this inventor on H bridge povered on 325VDC, I have one question is normal output after LC filtering not sine wave, but square wave ? Once connected to the load in output, output is sine wave it is normally ?

    ReplyDelete
  42. Hello Tahmid,

    I combined a pic16F690 + a hip4081 + a brigde made of 4 irfp064's + 4 extra super fast shotkey's protect the bridge ( i know the fets have their own shotkeys already inside the package ) but it's just to be sure they can handle the generated currents. The mos gate's are protected by 15v zeners to prevent overvoltage ( with is normally not needed in a 12V system but you never know ...) I adjusted the original code as you explained above to shut down the CM1CON0 and the CM2CON0. The problem. It doesn't work and i do not have a scope to look at the generated signals. However: my multimeter does measure frequency and pwm duty, so i can see the 50hz low side drive signals and the 7 - 8 khz high side signals. So the code does work and the chip is programmed as it should. But that's all i can see with inferiour measurement equipment. Strange thing is that the 4081 ( unlike the 4080) wants his input tied to ground to be enabled. ( i tested the setup with 2 leds and just some wires ) So my guess was that the 4081 inverts the pwm input from the pic and thus 0 commes out as 255 and vice verca. Witch would generate a mirrored sine. I could have inverted the pwm with a cd4*** not gate but that requires yet another chip. If you use a processor to do the job i think that is just a very stupid plan. So if the driver inverts the signal i should just invert the pwm values before i feed it to the driver stage to get the correct pwm at the output. So i inverted your list ( 255, 230,206, ... ) and i puched that into the driver stage. But than again it refused to work like it shoud. I placed 2 leds into the bridge to visualy look at what is happening inside. What is see is that the leds are not blinking very equaly and in a kind of semi random from of way. But like i said i don't have a scope to look at what is really happening inside the bridge. I may have overlooked something but i don't see where that could be? Can you make a guess what i could try to make it work? I feel stupid to ask this but maybe you have an obvious sollution that i just dont see for the moment ... I'm not that familiar with pic's and i plan to move your code inside a 8051 type of micro. Witch i understand much better than pic's. But to start with i would like to see your setup work before i move it to my micro of choise ...

    Kind Regards,

    Tom

    ReplyDelete
  43. hi , Thanks for your helpful post, but please from what you know that the maximum ECCP frequency is 20 Khz , please help because i thik it 's more than 200 Khz

    ReplyDelete
  44. Hi Tamhid:

    Can you tell me about the filter you used for producing pure AC wave from SPWM.

    ReplyDelete
  45. Hi Tamhid:

    Can you tell me about the filter you used for producing pure AC wave from SPWM.

    ReplyDelete
  46. Is this circuit applicable for inverting 12 volt dc voltage to 220 volt ac voltage.

    ReplyDelete
  47. //----------------------------------------------------------------------------------------
    //Programmer: Syed Tahmid Mahbub
    //Target Microcontroller: PIC16F684
    //Compiler: mikroC PRO for PIC (Can easily port to any other compiler)
    //-----------------------------------------------------------------------------------------

    unsigned char sin_table[32]={0,25,49,73,96,118,137,
    159,177,193,208,220,231,239,245,249,250,249,245,
    239,231,220,208,193,177,159,137,118,96,73,49,25};


    unsigned int TBL_POINTER_NEW, TBL_POINTER_OLD, TBL_POINTER_SHIFT, SET_FREQ;
    unsigned int TBL_temp;
    unsigned char DUTY_CYCLE;

    void interrupt(){
    if (TMR2IF_bit == 1){
    TBL_POINTER_NEW = TBL_POINTER_OLD + SET_FREQ;
    if (TBL_POINTER_NEW < TBL_POINTER_OLD){
    CCP1CON.P1M1 = ~CCP1CON.P1M1; //Reverse direction of full-bridge
    }
    TBL_POINTER_SHIFT = TBL_POINTER_NEW >> 11;
    DUTY_CYCLE = TBL_POINTER_SHIFT;
    CCPR1L = sin_table[DUTY_CYCLE];
    TBL_POINTER_OLD = TBL_POINTER_NEW;
    TMR2IF_bit = 0;
    }
    }

    void main() {
    SET_FREQ = 410;
    TBL_POINTER_SHIFT = 0;
    TBL_POINTER_NEW = 0;
    TBL_POINTER_OLD = 0;
    DUTY_CYCLE = 0;
    ANSEL = 0; //Disable ADC
    CMCON0 = 7; //Disable Comparator
    PR2 = 249;
    TRISC = 0x3F;
    CCP1CON = 0x4C;
    TMR2IF_bit = 0;
    T2CON = 4; //TMR2 on, prescaler and postscaler 1:1
    while (TMR2IF_bit == 0);
    TMR2IF_bit = 0;
    TRISC = 0;
    TMR2IE_bit = 1;
    GIE_bit = 1;
    PEIE_bit = 1;

    while(1);
    }
    //-------------------------------------------------------------------------------------

    HEX MEIN KOI CNVERT KR DE
    PLZZ
    FRIENDZZZZZZZZZZZZZZ

    ReplyDelete
  48. Thanks for a wonderful post....spwm waveforms are generated...but I have not been able to debug your code...please help.

    ReplyDelete
  49. Tahmid what are the frequencies of P1A,P1B to P1D For 50hz frequency

    ReplyDelete
  50. never Mind Answering..... for the BENEFIT OF OTHERS....P1A AND P1C on an Oscilloscope shows 50hz....P1B AND P1D show roughly 16khz..... but you'd see a varying duty cycle..... Regards.

    ReplyDelete
  51. How to exactly match inverter frequency to grid in grid tied application? Any one?

    ReplyDelete
  52. hi Tahmid ,tanks a lot
    What is the equivalent of registers PR2 and CCPR1L in micro controller avr?

    ReplyDelete
  53. Can this program be used for 3 phase inverter, with 6 igbts....how?

    ReplyDelete
  54. Hi Tahmid. Your articles are really great.
    Idonot know why i obtain a sine wave amplitude of 6V on my oscilloscope in proteus after supplying my H-bridge with 12V.

    ReplyDelete
  55. Hi Tamid,
    I've build a H-bridge circuit in Proteus but it shown some error when I run the simulation but I couldn't find out which part did I built wrng.

    ReplyDelete
  56. The error states that "Time step too small" and "problem node #v:q4:f1#branch" but my circuit does not have this branch.

    ReplyDelete
  57. Hi Tahmid, very illustrative examples, how can I do if I have a bipolar power source (+) & (-) in the hv side? should I connect the (-) to common earth in order to have a same circuit reference?

    ReplyDelete