Sine Wave Generation and Implementation using dsPIC33FJ
description
Transcript of Sine Wave Generation and Implementation using dsPIC33FJ
Syed Tahmid Mahbub
Sine Wave Generation and Implementation using dsPIC33FJ
Sine Wave Generation and Implementation using dsPIC33FJ – Syed Tahmid Mahbub
2
2
Image Sources:
Fig. 1 - dsPIC33FJ12GP202 datasheet
Fig. 2 - dsPIC33F Reference Manual – Output Compare Module
Fig. 3 - Generated using MATLAB
Fig. 4 - Screenshot of my software “Smart Sine”
Fig. 5 - Drawn by me
Fig. 6 - Drawn by me
Fig. 7 - Drawn by me
Fig. 8 - Simulation result obtained by me
Fig. 9 - Simulation result obtained by me
Sine Wave Generation and Implementation using dsPIC33FJ – Syed Tahmid Mahbub
3
3
Introduction
Sine wave generation is extremely important in power electronics. It finds applications in many circuits,
the most common ones being sine wave DC-AC inverters and AC motor control circuits. I have previously
covered sine wave generation control using SPWM based on the PIC (with or without ECCP module) and
the AVR microcontrollers. Here I’ll talk about the implementation of SPWM using a dsPIC33FJ series
microcontroller. The specific microcontroller I’ll use is the dsPIC33FJ12GP202. This microcontroller is
available in a 28-pin prototype-friendly PDIP package, making it easy to prototype; the large pin count
also leaves a lot of pins free for other use. That is primarily why I chose this microcontroller. The
microcontroller is certainly more than powerful enough for the application.
While I have used the dsPIC33FJ12GP202 microcontroller, the same concepts can be ported to other
dsPIC microcontrollers, or even any other capable microcontroller, of course with some necessary
changes.
The principle of SPWM is quite simple and I’ll go through the entire process of implementing SPWM to
generate sine wave using the dsPIC33FJ12GP202. I have divided this tutorial into 6 parts:
1. Explanation of the use of the dsPIC33FJ12GP202 Output Compare Module in PWM mode
(without fault detection, as this isn’t necessary for this simple application here)
2. Generation of the Sine Table
3. The code
4. Detailed explanation of the code, especially the sine wave generation control part
5. Circuit Configuration
6. Simulation Results
Sine Wave Generation and Implementation using dsPIC33FJ – Syed Tahmid Mahbub
4
4
Explanation of the use of the dsPIC33FJ12GP202 Output Compare Module in PWM mode
The Output Compare Module uses one of two 16-bit timers, Timer 2 and Timer 3. The Output Compare
Module compares the value of the selected timer with the output compare registers OCxR and OCxRS.
The Output Compare Module changes the state of the output pin when there is a match between the
timer value and the output compare register value, and also at the end of the period.
The Output Compare Module has quite a lot of modes in which it can be used, but here I’m using only
the PWM mode (without fault protection).
The dsPIC33FJ12GP202 has 2 Output Compare Modules. It is extremely useful to have 2 compare
modules as you will see in the sine wave generation implementation below.
Sine Wave Generation and Implementation using dsPIC33FJ – Syed Tahmid Mahbub
5
5
Here’s the Output Compare X Control Register, along with the description of the bits, (where X = 1 for
Output Compare Module 1 or X = 2 for Output Compare Module 2):
Fig. 1 – OCxCON (Output Compare x Control Register)
The bits description above clearly explains the function of the bits of the OCxCON register. You should
notice that, with fault pin disabled, PWM mode is selected when OCM<2:0> is set to 6 (110 in binary
equals 6 in decimal, 0x06 in hexadecimal).
Sine Wave Generation and Implementation using dsPIC33FJ – Syed Tahmid Mahbub
6
6
Now let’s go on to how the PWM mode in the Output Compare Module works.
As you know by now, the Output Compare Module can use either Timer 2 or Timer 3 as the time base.
Which timer is used is configured by the OCTSEL bit (bit 3) of the OCxCON register. Setting OCTSEL to 1
uses the Timer 3, whereas clearing OCTSEL to 0 uses the Timer 2.
The timer starts from zero and increments on every clock until it reaches the value of the Period Register
(PRy, where y = 2 for Timer 2 and y = 3 for Timer 3). When the period value is reached (when value of
timer equals value of the Period Register), the timer is reset and starts incrementing once again. The
timer can be clocked using the internal clock source (Fosc/2) or a synchronized external clock source
applied at the TxCK pin. In our circuit, we need not use any external clock and we use the internal clock
source. Do remember that the internal clock frequency is not fixed at Fosc/2 and can be adjusted by
changing the timer prescale value.
If the timer overflow interrupt is enabled, a timer overflow interrupt will be generated when the value
of the timer equals the value of the Period Register PRy. Again, this timer will be either Timer 2 or Timer
3, as selected by the configuration of the OCTSEL bit in the output compare control Register OCxCON.
Sine Wave Generation and Implementation using dsPIC33FJ – Syed Tahmid Mahbub
7
7
Now, let’s look at the how we’ll set the value of PRy. PRy is related to the PWM period and PWM
frequency by the following equations:
𝑃𝑊𝑀 𝑝𝑒𝑟𝑖𝑜𝑑 = 𝑃𝑅𝑦 + 1 ⋅ 𝑇𝑐𝑦 ⋅ 𝑇𝑀𝑅𝑦 𝑃𝑟𝑒𝑠𝑐𝑎𝑙𝑒 𝑉𝑎𝑙𝑢𝑒
𝑃𝑊𝑀 𝑓𝑟𝑒𝑞𝑢𝑒𝑛𝑐𝑦 =1
𝑃𝑊𝑀 𝑝𝑒𝑟𝑖𝑜𝑑
So, rearranging:
𝑃𝑅𝑦 = (𝑃𝑊𝑀 𝑝𝑒𝑟𝑖𝑜𝑑)
𝑇𝑐𝑦 ⋅ (𝑇𝑀𝑅𝑦 𝑃𝑟𝑒𝑠𝑐𝑎𝑙𝑒 𝑉𝑎𝑙𝑢𝑒)− 1 =
𝑓𝑐𝑦
𝑓𝑝𝑤𝑚 ⋅ (𝑇𝑀𝑅𝑦 𝑃𝑟𝑒𝑠𝑐𝑎𝑙𝑒 𝑉𝑎𝑙𝑢𝑒)− 1
So, you can set the PWM frequency by setting PRy. That’s good. Now how do we set the duty cycle? The
PWM duty cycle is set by the value of the OCxR register. However, in PWM mode, the OCxR register is
read-only. It cannot be written to. So, how do we set the PWM duty cycle? By using the OCxRS register.
The OCxRS register acts as a shadow register for the OCxR register. This prevents glitches in the PWM
output. Whenever the timer is reset, ie the timer rolls over, the value of the OCxRS register is loaded
onto the OCxR register. So, by setting the value of the OCxRS register, we are setting the value of the
OCxR register and thus setting the PWM duty cycle. So, you might think that we don’t need to deal with
the OCxR register. Well, we do. We should set the value of the OCxR register before enabling PWM
mode because this initial value of OCxR will set the initial duty cycle of the PWM – the duty cycle of the
first pulse. Usually, we start with zero duty cycle and so it’s common to have OCxR cleared to zero
before the PWM mode is enabled. That’s also what I’ve done in the code.
So when the PWM mode is enabled, the OCx pin is:
Driven high if the value of OCxR is non-zero.
Driven low if the value of OCxR is zero.
When the timer is enabled, it starts incrementing until its value equals that of its Period Register. The
value of OCxR is constantly compared with the value of the timer. When a match occurs, the OCx pin is
driven low. On a timer roll-over, the value of the OCxRS register is loaded into the OCxR register. The
OCx pin is then:
Driven high if the value of OCxR is non-zero.
Driven low if the value of OCxR is zero.
Sine Wave Generation and Implementation using dsPIC33FJ – Syed Tahmid Mahbub
8
8
The PWM duty cycle is specified by writing to the OCxRS register. The duty cycle value can be written at
any time, but the duty cycle value is not latched onto the OCxR register until timer Reset on a period
match. This provides a double buffer for the PWM duty cycle and is essential for glitch-free PWM
operation.
Some important boundary parameters of the PWM duty cycle include:
• If the duty cycle register, OCxR, is loaded with 0000h, the OCx pin remains low (0% duty cycle)
• If the OCxR register is greater than PRy (Timer Period register), the pin remains high (100% duty cycle)
• If the OCxR register is equal to PRy, the OCx pin is low for one time base count value and high for all
other count values
The PWM resolution depends on PWM frequency and the timer clock frequency. The timer clock is
derived from the internal clock (FCY) divided by a programmable prescaler.
Sine Wave Generation and Implementation using dsPIC33FJ – Syed Tahmid Mahbub
9
9
The mode of operation is explained clearly by this diagram:
Fig. 2 – PWM Mode Operation
Sine Wave Generation and Implementation using dsPIC33FJ – Syed Tahmid Mahbub
10
10
Generation of the Sine Table
So now, let’s talk about sinusoidal pulse width modulation a bit. We want to generate a sine wave
digitally – using square waves. When digitally producing sine wave, we do so by using a fixed number of
square wave pulses. The larger the number, the cleaner the sine wave. The duty cycles of the continuous
pulses vary sinusoidally. If you don’t get this now, don’t worry; the following explanations will clear it up
for you. For example’s sake, let’s say that we are using 10 samples – 10 square wave pulses per sine
wave half-cycle. Do bear in mind that usually, for a clean output, we’ll use more pulses per half-cycle,
usually at least 32.
So we have y=sin(x); x varies between 0° to 360° or, in radians, 0 to 2π. Now, let’s concentrate on the
positive half-cycle. The negative half-cycle will have the same pulses in the opposite direction. Since we
want to use 10 pulses per half-cycle, and the half-cycle is from 0° to 180°, we have an interval equal to
18°. So, we’re using 18° steps. So the pulses will be sent at 0°, 18°, 36° and so on. The values we need
are:
1. sin(0°) = 0 2. sin(18°) = 0.31 3. sin(36°) = 0.59 4. sin(54°) = 0.81 5. sin(72°) = 0.95 6. sin(90°) = 1 7. sin(108°) = 0.95 8. sin(126°) = 0.81 9. sin(144°) = 0.59 10. sin(162°) = 0.31
Notice that we don’t take sin(180°) as this value will be called in the next half-cycle, at the beginning,
when sin(0°) = 0.
Sine Wave Generation and Implementation using dsPIC33FJ – Syed Tahmid Mahbub
11
11
Now that we know how to find the values, we have to scale them to something meaningful. We know
that:
1. sin(0°) = 0% 2. sin(18°) = 31% 3. sin(36°) = 59% 4. sin(54°) = 81% 5. sin(72°) = 95% 6. sin(90°) = 100% 7. sin(108°) = 95% 8. sin(126°) = 81% 9. sin(144°) = 59% 10. sin(162°) = 31%
100% is at the amplitude value – at 90°. This will equal the Period Register (or less if you want, but this
will be the maximum value). Let’s say that the carrier frequency of the SPWM is 25kHz and the
dsPIC33FJ12GP202 is run from a 20MHz crystal oscillator. The carrier frequency is the frequency of the
square wave pulses that will be sent, that, upon filtering, will represent a sine wave. I’ve explained
below about why I chose 25kHz as the carrier frequency.
From the equation given:
𝑃𝑅𝑦 = (𝑃𝑊𝑀 𝑝𝑒𝑟𝑖𝑜𝑑)
𝑇𝑐𝑦 ⋅ (𝑇𝑀𝑅𝑦 𝑃𝑟𝑒𝑠𝑐𝑎𝑙𝑒 𝑉𝑎𝑙𝑢𝑒)− 1 =
𝑓𝑐𝑦
𝑓𝑝𝑤𝑚 ⋅ (𝑇𝑀𝑅𝑦 𝑃𝑟𝑒𝑠𝑐𝑎𝑙𝑒 𝑉𝑎𝑙𝑢𝑒)− 1
𝑃𝑅𝑦 = 10 ∗ 106
25000 ⋅ 1− 1 = 399
We know that when OCxRS = PRy, the duty cycle is 100%. OCxRS is related to PRy linearly. So, if OCxRS is
half of PRy, the duty cycle is 50%, and so on.
Sine Wave Generation and Implementation using dsPIC33FJ – Syed Tahmid Mahbub
12
12
So, considering that the table values correspond to the duty cycles, the sine table:
1. sin(0°) = 0 2. sin(18°) = 0.31 3. sin(36°) = 0.59 4. sin(54°) = 0.81 5. sin(72°) = 0.95 6. sin(90°) = 1 7. sin(108°) = 0.95 8. sin(126°) = 0.81 9. sin(144°) = 0.59 10. sin(162°) = 0.31
can be written as below, where the values represent the value to be stored in OCxRS:
1. sin(0°) = 0 * (PRy + 1) 2. sin(18°) = 0.31 * (PRy + 1) 3. sin(36°) = 0.59 * (PRy + 1) 4. sin(54°) = 0.81 * (PRy + 1) 5. sin(72°) = 0.95 * (PRy + 1) 6. sin(90°) = 1 * (PRy + 1) 7. sin(108°) = 0.95 * (PRy + 1) 8. sin(126°) = 0.81 * (PRy + 1) 9. sin(144°) = 0.59 * (PRy + 1) 10. sin(162°) = 0.31 * (PRy + 1)
We have calculated PRy as being equal to 399. So, our table is:
1. sin(0°) = 0 * (PRy + 1) = 0 * 400 = 0 2. sin(18°) = 0.31 * (PRy + 1) = 0.31 * 400 = 124 3. sin(36°) = 0.59 * (PRy + 1) = 0.59 * 400 = 236 4. sin(54°) = 0.81 * (PRy + 1) = 0.81 * 400 = 324 5. sin(72°) = 0.95 * (PRy + 1) = 0.95 * 400 = 380 6. sin(90°) = 1 * (PRy + 1) = 1 * 400 = 400 7. sin(108°) = 0.95 * (PRy + 1) = 0.95 * 400 = 380 8. sin(126°) = 0.81 * (PRy + 1) = 0.81 * 400 = 324 9. sin(144°) = 0.59 * (PRy + 1) = 0.59 * 400 = 236 10. sin(162°) = 0.31 * (PRy + 1) = 0.31 * 400 = 124
That is our sine table: [0, 124, 236, 324, 380, 400, 380, 324, 236, 124]
Sine Wave Generation and Implementation using dsPIC33FJ – Syed Tahmid Mahbub
13
13
This is what I meant previously when I said that the duty cycles are changed sinusoidally. If you plot the
values of the sine table and draw a graph, you’ll see a sine wave shape. The more points you take, the
smoother the wave will be.
I’ll show that here. Here is a graph of the resultant graph of the sine table points plotted.
Fig. 3 –Table points forming a sine wave
How do continuous pulses with sinusoidally varying duty cycles generate a sine wave? You know that
the duty cycle controls the output voltage. When the output signal is filtered, the output voltages at
different points vary sinusoidally as the duty cycle values vary sinusoidally, and the output voltage is
proportional to the duty cycle. So, due to this, the output voltage observed will also be sinusoidal.
Notice the sinusoidal-ish shape obtained with just 10 values! The more values you’ll use the smoother
the wave will be.
Sine Wave Generation and Implementation using dsPIC33FJ – Syed Tahmid Mahbub
14
14
Let’s find the sine table for our program. The carrier frequency is 25kHz. I selected 25kHz for two
reasons:
1. It is above 20kHz. So, being beyond the audible range, audible noise will not be generated.
2. The switching frequency is large enough to require a reasonably small inductor and capacitor for
filtering. At the same time, the switching frequency is not too large that there will be huge
switching losses.
For the PWM mode, I have used Timer 2 as the time base. So the Period Register is PR2. As calculated
above, PR2 equals 399. For a really smooth sine wave, I chose 256 points per half-cycle.
It would be way too much hassle trying to calculate so many values by hand. So what I did was, I made
the software “Smart Sine” and I use that for calculating tables. I found the above sine table using the
“Smart Sine” software. Here’s a screenshot showing the generation of the sine wave table mentioned
above. For more information about “Smart Sine” and/or to download “Smart Sine” visit my blog or go to
this link:
http://tahmidmc.blogspot.com/2012/10/smart-sine-software-to-generate-sine.html
Fig. 4 – Generating sine table with “Smart Sine”
Sine Wave Generation and Implementation using dsPIC33FJ – Syed Tahmid Mahbub
15
15
The sine table for both half-cycles is:
{
0, 5, 10, 15, 20, 25, 29, 34, 39, 44, 49, 54, 59, 64, 68, 73, 78, 83, 88, 92, 97, 102,
107, 111, 116, 121, 125, 130, 135, 139, 144, 149, 153, 158, 162, 167, 171, 175, 180,
184, 189, 193, 197, 201, 206, 210, 214, 218, 222, 226, 230, 234, 238, 242, 246, 250,
254, 258, 261, 265, 269, 272, 276, 279, 283, 286, 290, 293, 296, 300, 303, 306, 309,
312, 315, 318, 321, 324, 327, 330, 333, 335, 338, 341, 343, 346, 348, 350, 353, 355,
357, 359, 362, 364, 366, 368, 370, 371, 373, 375, 377, 378, 380, 381, 383, 384, 386,
387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 396, 397, 398, 398, 399, 399, 399,
400, 400, 400, 400, 400, 400, 400, 400, 400, 399, 399, 399, 398, 398, 397, 396, 396,
395, 394, 393, 392, 391, 390, 389, 388, 387, 386, 384, 383, 381, 380, 378, 377, 375,
373, 371, 370, 368, 366, 364, 362, 359, 357, 355, 353, 350, 348, 346, 343, 341, 338,
335, 333, 330, 327, 324, 321, 318, 315, 312, 309, 306, 303, 300, 296, 293, 290, 286,
283, 279, 276, 272, 269, 265, 261, 258, 254, 250, 246, 242, 238, 234, 230, 226, 222,
218, 214, 210, 206, 201, 197, 193, 189, 184, 180, 175, 171, 167, 162, 158, 153, 149,
144, 139, 135, 130, 125, 121, 116, 111, 107, 102, 97, 92, 88, 83, 78, 73, 68, 64, 59,
54, 49, 44, 39, 34, 29, 25, 20, 15, 10, 5,
0, 5, 10, 15, 20, 25, 29, 34, 39, 44, 49, 54, 59, 64, 68, 73, 78, 83, 88, 92, 97, 102,
107, 111, 116, 121, 125, 130, 135, 139, 144, 149, 153, 158, 162, 167, 171, 175, 180,
184, 189, 193, 197, 201, 206, 210, 214, 218, 222, 226, 230, 234, 238, 242, 246, 250,
254, 258, 261, 265, 269, 272, 276, 279, 283, 286, 290, 293, 296, 300, 303, 306, 309,
312, 315, 318, 321, 324, 327, 330, 333, 335, 338, 341, 343, 346, 348, 350, 353, 355,
357, 359, 362, 364, 366, 368, 370, 371, 373, 375, 377, 378, 380, 381, 383, 384, 386,
387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 396, 397, 398, 398, 399, 399, 399,
400, 400, 400, 400, 400, 400, 400, 400, 400, 399, 399, 399, 398, 398, 397, 396, 396,
395, 394, 393, 392, 391, 390, 389, 388, 387, 386, 384, 383, 381, 380, 378, 377, 375,
373, 371, 370, 368, 366, 364, 362, 359, 357, 355, 353, 350, 348, 346, 343, 341, 338,
335, 333, 330, 327, 324, 321, 318, 315, 312, 309, 306, 303, 300, 296, 293, 290, 286,
283, 279, 276, 272, 269, 265, 261, 258, 254, 250, 246, 242, 238, 234, 230, 226, 222,
218, 214, 210, 206, 201, 197, 193, 189, 184, 180, 175, 171, 167, 162, 158, 153, 149,
144, 139, 135, 130, 125, 121, 116, 111, 107, 102, 97, 92, 88, 83, 78, 73, 68, 64, 59,
54, 49, 44, 39, 34, 29, 25, 20, 15, 10, 5
}
Why both half-cycles? That’ll be clear once we look at my code on the next page.
Sine Wave Generation and Implementation using dsPIC33FJ – Syed Tahmid Mahbub
16
16
The Code
//----------------------------------------------------------------
//Programmer: Syed Tahmid Mahbub
//Compiler: mikroC PRO for dsPIC v5.0.1
//Target dsPIC: dsPIC33FJ12GP202
//Program for sine wave generation using SPWM
//----------------------------------------------------------------
const int sin_table[512] =
{
0, 5, 10, 15, 20, 25, 29, 34, 39, 44, 49, 54, 59, 64, 68, 73,
78, 83, 88, 92, 97, 102, 107, 111, 116, 121, 125, 130, 135, 139,
144, 149, 153, 158, 162, 167, 171, 175, 180, 184, 189, 193, 197,
201, 206, 210, 214, 218, 222, 226, 230, 234, 238, 242, 246, 250,
254, 258, 261, 265, 269, 272, 276, 279, 283, 286, 290, 293, 296,
300, 303, 306, 309, 312, 315, 318, 321, 324, 327, 330, 333, 335,
338, 341, 343, 346, 348, 350, 353, 355, 357, 359, 362, 364, 366,
368, 370, 371, 373, 375, 377, 378, 380, 381, 383, 384, 386, 387,
388, 389, 390, 391, 392, 393, 394, 395, 396, 396, 397, 398, 398,
399, 399, 399, 400, 400, 400, 400, 400, 400, 400, 400, 400, 399,
399, 399, 398, 398, 397, 396, 396, 395, 394, 393, 392, 391, 390,
389, 388, 387, 386, 384, 383, 381, 380, 378, 377, 375, 373, 371,
370, 368, 366, 364, 362, 359, 357, 355, 353, 350, 348, 346, 343,
341, 338, 335, 333, 330, 327, 324, 321, 318, 315, 312, 309, 306,
303, 300, 296, 293, 290, 286, 283, 279, 276, 272, 269, 265, 261,
258, 254, 250, 246, 242, 238, 234, 230, 226, 222, 218, 214, 210,
206, 201, 197, 193, 189, 184, 180, 175, 171, 167, 162, 158, 153,
149, 144, 139, 135, 130, 125, 121, 116, 111, 107, 102, 97, 92, 88,
83, 78, 73, 68, 64, 59, 54, 49, 44, 39, 34, 29, 25, 20, 15, 10, 5,
0, 5, 10, 15, 20, 25, 29, 34, 39, 44, 49, 54, 59, 64, 68, 73,
78, 83, 88, 92, 97, 102, 107, 111, 116, 121, 125, 130, 135, 139,
144, 149, 153, 158, 162, 167, 171, 175, 180, 184, 189, 193, 197,
201, 206, 210, 214, 218, 222, 226, 230, 234, 238, 242, 246, 250,
254, 258, 261, 265, 269, 272, 276, 279, 283, 286, 290, 293, 296,
300, 303, 306, 309, 312, 315, 318, 321, 324, 327, 330, 333, 335,
338, 341, 343, 346, 348, 350, 353, 355, 357, 359, 362, 364, 366,
368, 370, 371, 373, 375, 377, 378, 380, 381, 383, 384, 386, 387,
388, 389, 390, 391, 392, 393, 394, 395, 396, 396, 397, 398, 398,
399, 399, 399, 400, 400, 400, 400, 400, 400, 400, 400, 400, 399,
399, 399, 398, 398, 397, 396, 396, 395, 394, 393, 392, 391, 390,
389, 388, 387, 386, 384, 383, 381, 380, 378, 377, 375, 373, 371,
370, 368, 366, 364, 362, 359, 357, 355, 353, 350, 348, 346, 343,
341, 338, 335, 333, 330, 327, 324, 321, 318, 315, 312, 309, 306,
303, 300, 296, 293, 290, 286, 283, 279, 276, 272, 269, 265, 261,
258, 254, 250, 246, 242, 238, 234, 230, 226, 222, 218, 214, 210,
206, 201, 197, 193, 189, 184, 180, 175, 171, 167, 162, 158, 153,
149, 144, 139, 135, 130, 125, 121, 116, 111, 107, 102, 97, 92, 88,
83, 78, 73, 68, 64, 59, 54, 49, 44, 39, 34, 29, 25, 20, 15, 10, 5
};
Sine Wave Generation and Implementation using dsPIC33FJ – Syed Tahmid Mahbub
17
17
sbit MOSA at LATB2_bit;
sbit MOSC at LATB3_bit;
//D at LATB0_bit;
//B at LATB1_bit;
unsigned int Result;
int PWM_Scaling = 399; //25kHz
int Frequency = 131; //50Hz
unsigned int Phase;
int TBL_ID;
void T2Int() org 0x0022{ //Timer 2 overflow interrupt
Phase = Phase + Frequency;
Result = Phase >> 7;
TBL_ID = sin_table[Result];
if (Result < 256){ //A and D on
OC2RS = 0;
MOSC = 0;
OC1RS = TBL_ID;
MOSA = 1;
}
else{ //B and C on
OC1RS = 0;
MOSA = 0;
OC2RS = TBL_ID;
MOSC = 1;
}
T2IF_bit = 0;
}
void main() {
LATB = 0;
TRISB = 0; //All PORTB output
AD1PCFGL = 0x3F; //All digital
PR2 = PWM_Scaling; //Set Frequency by setting Period Register
//PR2 since I'll be using Timer 2
OC1CON = 0; //Disable compare module
OC1R = 0; //Initial duty cycle = 0
OC1RS = 0;
OC1CON = 0x0006; //Keep running in idle mode, Time base is TMR2,
//PWM mode with fault pin disabled
OC2CON = 0;
OC2R = 0; //Initial duty cycle = 0
OC2RS = 0;
OC2CON = 0x0006;
RPOR0 = 0x1213; //RP0 - OC1, RP1 - OC2
Sine Wave Generation and Implementation using dsPIC33FJ – Syed Tahmid Mahbub
18
18
SR = 0; //CPU priority interrupt level 0
T2IF_bit = 0; //Clear TMR2 interrupt flag
T2IP_2_bit = 1;
T2IP_1_bit = 1;
T2IP_0_bit = 1; //TMR2 interrupt priority 7
T2IE_bit = 1; //Enable TMR2 interrupt
T2CON = 0x8000; //TMR2 on, prescaler 1
while (1){ //Infinite loop – Nothing to do now
}
} //End of code
Sine Wave Generation and Implementation using dsPIC33FJ – Syed Tahmid Mahbub
19
19
Explanation of the Code
I’ve added comments to every line in the main() function to make it self-explanatory. I’ll have to explain
the interrupt and I’ll do that here.
Here’s the interrupt code:
void T2Int() org 0x0022{ //Timer 2 overflow interrupt
Phase = Phase + Frequency;
Result = Phase >> 7;
TBL_ID = sin_table[Result];
if (Result < 256){ //A and D on
OC2RS = 0;
MOSC = 0;
OC1RS = TBL_ID;
MOSA = 1;
}
else{ //B and C on
OC1RS = 0;
MOSA = 0;
OC2RS = TBL_ID;
MOSC = 1;
}
T2IF_bit = 0;
}
The interrupt is generated at the end of every PWM cycle. That is when the value of Timer 2 equals the
value of the Period Register PR2. The PWM frequency is 25kHz. So the PWM period is equal to
(1/25000)s = 40µs. So, the interrupt service routine is carried out every 40µs. 1 50Hz half cycle is 10ms.
So in one half-cycle, the ISR is carried out (10000/40) times = 250 times. 0x0022 is the interrupt vector
for the TMR2 overflow interrupt.
The value of the register “Frequency” sets the frequency of the output sine wave. Okay, so let’s go on to
explain the interrupt. “Phase” is a 16-bit register. Every interrupt, the value of “Phase” is increased by
the value that equals “Frequency”.
Every 40µs, the value of “Phase” is increased by 131. Initially, “Phase” has a value of 0 and every 40µs,
“Phase” is increased by 131. So, initially “Phase” equals 0; after the first interrupt “Phase” equals 131;
Sine Wave Generation and Implementation using dsPIC33FJ – Syed Tahmid Mahbub
20
20
after the second interrupt “Phase” equals 262; and so on. After “Phase” is incremented by 131 every
interrupt, it is then divided by 128 (>>7 is the same as dividing by 27). So every time “Phase” is increased
by 131, “Result” is incremented by 1. “Result” is the table pointer. After 499 interrupts, “Phase” holds
65369. On the next interrupt, “Phase” overflows. So on the 500th interrupt “Phase” overflows, and
“Result” then holds 0. So, “Result” takes values from 0 to 499. It acts as the table pointer to the sine
table. The corresponding value is retrieved from the table and stored in “TBL_ID”.
This value is then assigned to the required duty cycle register. Now comes the tricky (and interesting)
part. The first 256 values (when the table pointer will have a value from 0 to 255) correspond to one
half-cycle. The next 256 values (when the table pointer will have a value from 256 to 511) correspond to
the opposite half-cycle. I’ve used both Output Compare Modules in PWM here. The two Output
Compare Modules drive opposite MOSFETs, thereby “reversing” the direction of current through the
load/transformer. Notice also that two MOSFETs are SPWM-ed at 25kHz, while the other two MOSFETs
are turned on and off at 50Hz.
When the first 256 values are retrieved from the sine table, Output Compare Module 1 is used to drive
the output, while the Output Compare Module 2 has a duty cycle of 0%, ie it is off. Similarly when the
next 256 values are retrieved from the sine table, Output Compare Module 2 is used to drive the output,
while the Output Compare Module 1 has a duty cycle of 0%, ie it is off. To understand this in the context
of the circuit, refer to the “Circuit Configuration” section below.
Now, if you want to make changes to the code, here’s how to calculate the different parameters.
“Phase” is a 16-bit register. When you change the number of sine table entries, you need to change the
number of times “Phase” is right-shifted before being stored in “Result”. The number of times “Phase” is
right-shifted before being stored in “Result” is equal to:
16 − log2(𝑁𝑜. 𝑜𝑓 𝑠𝑖𝑛𝑒 𝑡𝑎𝑏𝑙𝑒 𝑒𝑛𝑡𝑟𝑖𝑒𝑠)
In our program, this was equal to:
16 − log2 512 = 16 − 9 = 7
And that is what I used. Just giving you an example.
Sine Wave Generation and Implementation using dsPIC33FJ – Syed Tahmid Mahbub
21
21
If you want to change the carrier frequency, you have to adjust the Period Register (PRy). I’ve already
shown you how to calculate the value of the Period Register (PRy).
Now, if you want to change the frequency of the output sine wave, you need to change the value of the
register “Frequency”. “Frequency” is related to the output sine wave frequency and the carrier
frequency by the relationship:
"𝐹𝑟𝑒𝑞𝑢𝑒𝑛𝑐𝑦" = 216 ∗ (𝑂𝑢𝑡𝑝𝑢𝑡 𝑠𝑖𝑛𝑒 𝑤𝑎𝑣𝑒 𝑓𝑟𝑒𝑞𝑢𝑒𝑛𝑐𝑦)
(𝐶𝑎𝑟𝑟𝑖𝑒𝑟 𝑓𝑟𝑒𝑞𝑢𝑒𝑛𝑐𝑦)
For our program, this was:
Frequency = 216 ∗ 𝑂𝑢𝑡𝑝𝑢𝑡 𝑠𝑖𝑛𝑒 𝑤𝑎𝑣𝑒 𝑓𝑟𝑒𝑞𝑢𝑒𝑛𝑐𝑦
𝐶𝑎𝑟𝑟𝑖𝑒𝑟 𝑓𝑟𝑒𝑞𝑢𝑒𝑛𝑐𝑦 =
65536 ∗ 50
25000= 131.072 ≈ 131
So now that I’ve explained the code, let’s look at the circuit configuration.
Sine Wave Generation and Implementation using dsPIC33FJ – Syed Tahmid Mahbub
22
22
Circuit Configuration
Fig. 5 – Circuit Configuration for the dsPIC33FJ12GP202
This is how the dsPIC33FJ12GP202 is configured. The configuration is a typical configuration for the
dsPIC33FJ12GP202 and follows the guidelines mentioned in the datasheet (check “RECOMMENDED
MINIMUM CONNECTION” in the dsPIC33FJ12GP202 datasheet).
C1 should be between 4.7µF and 10µF. C1 is the filter capacitor for the internal voltage regulator. 6.8µF
is a good value lying safely in the middle of the range. C2, C3 and C4 are decoupling capacitors and
should be placed as close to the microcontroller as possible.
Sine Wave Generation and Implementation using dsPIC33FJ – Syed Tahmid Mahbub
23
23
Fig. 6 – MOSFET Configuration section
I’ll just talk about the operation of the circuit a little bit. Go back to the code and look again at the
interrupt. You’ll notice that when QD is SPWM-ed, QA is kept on, whereas QB and QC are kept off.
Similarly when QB is SPWM-ed, QC is kept on, whereas QA and QD are kept off.
After the first 256 values from the sine table are called, the direction of the output is to be reversed
(remember I said this before too?). For the first 256 sine table calls (when table pointer = 0 to 255), QD
is SPWM-ed and QA is kept on while QB and QC are kept off. Then for the next 256 sine table calls (when
table pointer = 256 to 511), QB is SPWM-ed and QC is kept on while QA and QD are kept off. This
essentially reverses the direction of current through the “OUTPUT”. This is the direction reversion I was
talking about. Do keep in mind that this is a full-bridge converter circuit and that the MOSFETs will
require high-low side drive (QA and QC will require high-side MOSFET drive while QB and QD will require
low-side MOSFET drive).
Another point to note is the “OUTPUT” labeled in the circuit configuration shown above. This will either
be a step-up transformer or your output load. If you’re using a step-up transformer, you usually don’t
need an inductor for filtering and the filter capacitor is usually placed at the secondary of the
Sine Wave Generation and Implementation using dsPIC33FJ – Syed Tahmid Mahbub
24
24
transformer. If you’re not using a transformer and are feeding the output to your load, then you must
use an LC filter to smooth out the resulting SPWM-ed square wave output to a pure sine wave output.
Below I show three common output (filter) stages used between the bridge output and the load.
Fig. 7 – Common Output (Filtering) Stages
So now let’s see the simulation results on the next page.
Sine Wave Generation and Implementation using dsPIC33FJ – Syed Tahmid Mahbub
25
25
Simulation Results
Here are the drive signals:
Fig. 6 – SPWM drive signals
Here is the output sine wave:
Fig. 7 – Generated Output Sine Wave
Drive Signals
Yellow – Drive signal to QA
Green – Drive signal to QD
Pink – Drive signal to QC
Blue – Drive signal to QB
-----------------------------------------
SPWM Frequency: 25kHz
Output Sine Wave after
filtration: this same output
shape should be obtained using
an LC filter at the bridge output.
Simulation uses an RC filter at
the microcontroller switching
outputs for demonstration.
------------------------------------------
Sine Wave Frequency: 50Hz
Sine Wave Generation and Implementation using dsPIC33FJ – Syed Tahmid Mahbub
26
26
Conclusion
The method of sinusoidal pulse width modulation (SPWM) and generating a sine wave output from
these signals is not too difficult if you understand the concepts behind these. The extremely powerful
dsPIC33FJ series of microcontrollers can be used to gain complete control over the SPWM signals
generation and also further control of the overall circuit. I have tried to explain thoroughly the
functioning and programming of the PWM mode of the Output Compare Module of the
dsPIC33FJ12GP202. I have tried to discuss in detail the generation of the sine table to be used for SPWM
and have provided a brief look at my software “Smart Sine” which I’m sure will aid you in your sine table
generation. I have provided the code/program I have used alongside detailed description of the code, as
well as the circuit configuration, output (filter) stage configuration and finally, simulation results of the
presented code. I hope that the tutorial/article that I have prepared and presented here will be of use to
those who are interested in applying the (seemingly difficult) concept of SPWM to generate sine wave
outputs in (not restricted to, but especially suitable for) power electronics applications, such as
inverters.
Feel free to leave your comments and feedback and do make sure that you regularly visit my blog
(www.tahmidmc.blogspot.com) as I try to frequently update it with new (and hopefully useful)
information. If you have any suggestions or questions regarding “Sine Wave Generation and
Implementation using dsPIC33FJ” or even regarding my blog, feel free to post them in the “Comments”
section below.
___________________________________________
Syed Tahmid Mahbub
Sine Wave Generation and Implementation using dsPIC33FJ – Syed Tahmid Mahbub
27
27
Reference and Related Documents
1. dsPIC33FJ12GP202 datasheet:
http://ww1.microchip.com/downloads/en/DeviceDoc/70264E.pdf
2. dsPIC33F Reference Manual – Output Compare section:
http://ww1.microchip.com/downloads/en/DeviceDoc/70209A.pdf
3. “Generation and Implementation of Sine Wave Table”:
http://tahmidmc.blogspot.com/2011/01/generation-and-implementation-of-sine.html
4. “Smart Sine – Software to generate sine table”:
http://tahmidmc.blogspot.com/2012/10/smart-sine-software-to-generate-sine.html
5. “Demystifying the Use of Table Pointer in SPWM – Application in Sine Wave Inverter”:
http://tahmidmc.blogspot.com/2013/02/demystifying-use-of-table-pointer-in.html