Subversion Repositories Code-Repo

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
333 Kevin 1
#include "PWM.h"
2
#include "INTERRUPTS.h"
3
 
4
static volatile uint8_t computedFrequency = 0;
5
static volatile uint8_t computedDutyCycleHigh_UpperByte = 0;
6
static volatile uint8_t computedDutyCycleHigh_LowerBits = 0;
7
static volatile uint8_t computedDutyCycleLow_UpperByte = 0;
8
static volatile uint8_t computedDutyCycleLow_LowerBits = 0;
9
static volatile uint8_t savedDutyCycleHigh = PWM_DEFAULT_HIGH_CYCLE;
10
static volatile uint8_t savedDutyCycleLow = PWM_DEFAULT_LOW_CYCLE;
11
static volatile uint16_t savedPattern = 0xAAAA;
12
 
13
void PWM_Init() {
14
    // Initialize CCP1 / Timer 2
15
    CCP1_TRIS = 1;  // PWM output starts disabled
16
    CCP1CONbits.P1M = 0b00;     // Single output, P1A modulated only
17
    CCP1CONbits.CCP1M = 0b1100; // PWM Mode, P1A active-high, P1B active-high
18
    PIR1bits.TMR2IF = 0;        // Clear Timer 2 interrupt flag
19
    TMR2 = 0x0;
20
 
21
    Set_PWM_Frequency(PWM_DEFAULT_FREQ);
22
    Set_PWM_Duty_Cycle(PWM_DEFAULT_HIGH_CYCLE, PWM_DEFAULT_LOW_CYCLE);
23
}
24
 
25
void Set_PWM_Frequency(uint32_t frequency) {
26
    // Timer 2 clocked at FOSC/4 (20 Mhz)
27
    // Prescaler 1:1 = minimum frequency of 19,532 Hz
28
    // Prescaler 1:4 = minimum frequency of 4,883 Hz
29
    // Prescaler 1:16 = minimum frequency of 1,221 Hz
30
    // Prescaler 1:64 = minimum frequency of 306 Hz
31
 
32
    // PWM Period = [PR2 + 1] * 4 * TOSC * Prescale
33
    //            = [PR2 + 1] * 4 * (1/FOSC) * Prescale
34
    //            = ([PR2 + 1] * 4 * Prescale) / FOSC
35
    // PWM Freq = 1/(PWM Period)
36
    //          = 1/(PR2 + 1) * 1/4 * FOSC * 1/Prescale)
37
    //          = FOSC / ([PR2 + 1] * 4 * Prescale)
38
    // PR2 = (FOSC / [(PWM Freq) * 4 * Presccale]) - 1
39
 
40
    uint8_t preScaleValue;
41
    if (frequency > 19532) {
42
        preScaleValue = 1;
43
        T2CONbits.T2CKPS = 0b00;
44
    } else if (frequency > 4883) {
45
        preScaleValue = 4;
46
        T2CONbits.T2CKPS = 0b01;
47
    } else if (frequency > 1221) {
48
        preScaleValue = 16;
49
        T2CONbits.T2CKPS = 0b10;
50
    } else {
51
        preScaleValue = 64;
52
        T2CONbits.T2CKPS = 0b11;
53
    }
54
 
55
    uint32_t tmp = frequency * 4 * preScaleValue;
56
    computedFrequency = (_XTAL_FREQ / tmp) - 1;
57
 
58
    // Updated duty cycle
59
    Set_PWM_Duty_Cycle(savedDutyCycleHigh, savedDutyCycleLow);
60
}
61
 
62
void Set_PWM_Duty_Cycle(uint8_t highPercent, uint8_t lowPercent) {
63
    // Duty cycle specified by 10 bit value in CCPR1L:DC1B<1:0>
64
    savedDutyCycleHigh = highPercent;
65
    savedDutyCycleLow = lowPercent;
66
 
67
    // Compute values to store in register
68
    uint32_t highValue = (computedFrequency + 1) * 4;
69
    highValue *= highPercent;
70
    highValue /= 100;
71
    computedDutyCycleHigh_LowerBits = highValue & 0x3;
72
    computedDutyCycleHigh_UpperByte = (highValue >> 2) & 0xFF;
73
 
74
    uint32_t lowValue = (computedFrequency + 1) * 4;
75
    lowValue *= lowPercent;
76
    lowValue /= 100;
77
    computedDutyCycleLow_LowerBits = lowValue & 0x3;
78
    computedDutyCycleLow_UpperByte = (lowValue >> 2) & 0xFF;
79
}
80
 
81
void Set_PWM_Pattern(uint16_t pattern) {
82
    savedPattern = pattern;
83
}
84
 
85
void PWM_Transmit_Pattern() {
86
    // Set PWM frequency pre-computed values
87
    PR2 = computedFrequency;
88
 
89
    // Set duty cycle to 0%
90
    CCP1CONbits.DC1B = 0b00;
91
    CCPR1L = 0x00;
92
 
93
    // Start timer and wait for it to rollover to latch duty cycle value
94
    T2CONbits.TMR2ON = 1;
95
    while (!PIR1bits.TMR2IF);
96
    PIR1bits.TMR2IF = 0;
97
    CCP1_TRIS = 0;
98
 
99
    // Bit 15
100
    if (savedPattern & 0x8000) {
101
        CCP1CONbits.DC1B = computedDutyCycleHigh_LowerBits;
102
        CCPR1L = computedDutyCycleHigh_UpperByte;
103
    } else {
104
        CCP1CONbits.DC1B = computedDutyCycleLow_LowerBits;
105
        CCPR1L = computedDutyCycleLow_UpperByte;
106
    }
107
    while (!PIR1bits.TMR2IF);
108
    PIR1bits.TMR2IF = 0;
109
 
110
    /* The above section of code disassembles to the following assembly code
111
     * According to the instruction set table, this should take 22 cycles to execute
112
     * 22 cycles corresponds to a maximum of ~227.272 kHz PWM frequency
113
     * If higher PWM frequency is needed, DC1B can be omitted for lower duty cycle accuracy
114
    !    if (pattern & 0x8000) {
115
    0x26: BTFSS 0x72, 0x7
116
    0x27: GOTO 0x34
117
    !        CCP1CONbits.DC1B = computedDutyCycleHigh_LowerBits;
118
    0x28: MOVLB 0x0
119
    0x29: MOVF computedDutyCycleHigh_LowerBits, W
120
    0x2A: MOVWF 0x73
121
    0x2B: SWAPF 0x73, F
122
    0x2C: MOVLB 0x5
123
    0x2D: MOVF CCP1CON, W
124
    0x2E: XORWF 0x2F3, W
125
    0x2F: ANDLW 0xCF
126
    0x30: XORWF 0x2F3, W
127
    0x31: MOVWF CCP1CON
128
    !        CCPR1L = computedDutyCycleHigh_UpperByte;
129
    0x32: MOVF computedDutyCycleHigh_UpperByte, W
130
    0x33: GOTO 0x41
131
    !    } else {
132
    !        CCP1CONbits.DC1B = computedDutyCycleLow_LowerBits;
133
    0x34: MOVLB 0x0
134
    0x35: MOVF computedDutyCycleLow_LowerBits, W
135
    0x36: MOVWF 0x73
136
    0x37: SWAPF 0x73, F
137
    0x38: MOVLB 0x5
138
    0x39: MOVF CCP1CON, W
139
    0x3A: XORWF 0x2F3, W
140
    0x3B: ANDLW 0xCF
141
    0x3C: XORWF 0x2F3, W
142
    0x3D: MOVWF CCP1CON
143
    !        CCPR1L = computedDutyCycleLow_UpperByte;
144
    0x3E: MOVLB 0x0
145
    0x3F: MOVF computedDutyCycleLow_UpperByte, W
146
    0x40: MOVLB 0x5
147
    0x41: MOVWF CCPR1
148
    !    }
149
    !    while (!PIR1bits.TMR2IF);
150
    0x42: MOVLB 0x0
151
    0x43: BTFSS PIR1, 0x1
152
    0x44: GOTO 0x42
153
    !    PIR1bits.TMR2IF = 0;
154
    0x45: BCF PIR1, 0x1
155
 
156
     * If DC1B is ignored, the disassembly is as follows:
157
     * According to the instruction set table, this should take 14 cycles to execute
158
     * 14 cycles corresponds to a maximum of ~357.142 kHz PWM frequency
159
    !    // Bit 15
160
    !    if (pattern & 0x8000) {
161
    0x26: BTFSS 0x72, 0x7
162
    0x27: GOTO 0x2A
163
    !        CCPR1L = computedDutyCycleHigh_UpperByte;
164
    0x28: MOVF computedDutyCycleHigh_UpperByte, W
165
    0x29: GOTO 0x2C
166
    !    } else {
167
    !        CCPR1L = computedDutyCycleLow_UpperByte;
168
    0x2A: MOVLB 0x0
169
    0x2B: MOVF computedDutyCycleLow_UpperByte, W
170
    0x2C: MOVLB 0x5
171
    0x2D: MOVWF CCPR1
172
    !    }
173
    !    while (!PIR1bits.TMR2IF);
174
    0x2E: MOVLB 0x0
175
    0x2F: BTFSS PIR1, 0x1
176
    0x30: GOTO 0x2E
177
    !    PIR1bits.TMR2IF = 0;
178
    0x31: BCF PIR1, 0x1
179
    */
180
 
181
    // Bit 14
182
    if (savedPattern & 0x4000) {
183
        CCP1CONbits.DC1B = computedDutyCycleHigh_LowerBits;
184
        CCPR1L = computedDutyCycleHigh_UpperByte;
185
    } else {
186
        CCP1CONbits.DC1B = computedDutyCycleLow_LowerBits;
187
        CCPR1L = computedDutyCycleLow_UpperByte;
188
    }
189
    while (!PIR1bits.TMR2IF);
190
    PIR1bits.TMR2IF = 0;
191
 
192
    // Bit 13
193
    if (savedPattern & 0x2000) {
194
        CCP1CONbits.DC1B = computedDutyCycleHigh_LowerBits;
195
        CCPR1L = computedDutyCycleHigh_UpperByte;
196
    } else {
197
        CCP1CONbits.DC1B = computedDutyCycleLow_LowerBits;
198
        CCPR1L = computedDutyCycleLow_UpperByte;
199
    }
200
    while (!PIR1bits.TMR2IF);
201
    PIR1bits.TMR2IF = 0;
202
 
203
    // Bit 12
204
    if (savedPattern & 0x1000) {
205
        CCP1CONbits.DC1B = computedDutyCycleHigh_LowerBits;
206
        CCPR1L = computedDutyCycleHigh_UpperByte;
207
    } else {
208
        CCP1CONbits.DC1B = computedDutyCycleLow_LowerBits;
209
        CCPR1L = computedDutyCycleLow_UpperByte;
210
    }
211
    while (!PIR1bits.TMR2IF);
212
    PIR1bits.TMR2IF = 0;
213
 
214
    // Bit 11
215
    if (savedPattern & 0x0800) {
216
        CCP1CONbits.DC1B = computedDutyCycleHigh_LowerBits;
217
        CCPR1L = computedDutyCycleHigh_UpperByte;
218
    } else {
219
        CCP1CONbits.DC1B = computedDutyCycleLow_LowerBits;
220
        CCPR1L = computedDutyCycleLow_UpperByte;
221
    }
222
    while (!PIR1bits.TMR2IF);
223
    PIR1bits.TMR2IF = 0;
224
 
225
    // Bit 10
226
    if (savedPattern & 0x0400) {
227
        CCP1CONbits.DC1B = computedDutyCycleHigh_LowerBits;
228
        CCPR1L = computedDutyCycleHigh_UpperByte;
229
    } else {
230
        CCP1CONbits.DC1B = computedDutyCycleLow_LowerBits;
231
        CCPR1L = computedDutyCycleLow_UpperByte;
232
    }
233
    while (!PIR1bits.TMR2IF);
234
    PIR1bits.TMR2IF = 0;
235
 
236
    // Bit 9
237
    if (savedPattern & 0x0200) {
238
        CCP1CONbits.DC1B = computedDutyCycleHigh_LowerBits;
239
        CCPR1L = computedDutyCycleHigh_UpperByte;
240
    } else {
241
        CCP1CONbits.DC1B = computedDutyCycleLow_LowerBits;
242
        CCPR1L = computedDutyCycleLow_UpperByte;
243
    }
244
    while (!PIR1bits.TMR2IF);
245
    PIR1bits.TMR2IF = 0;
246
 
247
    // Bit 8
248
    if (savedPattern & 0x0100) {
249
        CCP1CONbits.DC1B = computedDutyCycleHigh_LowerBits;
250
        CCPR1L = computedDutyCycleHigh_UpperByte;
251
    } else {
252
        CCP1CONbits.DC1B = computedDutyCycleLow_LowerBits;
253
        CCPR1L = computedDutyCycleLow_UpperByte;
254
    }
255
    while (!PIR1bits.TMR2IF);
256
    PIR1bits.TMR2IF = 0;
257
 
258
    // Bit 7
259
    if (savedPattern & 0x0080) {
260
        CCP1CONbits.DC1B = computedDutyCycleHigh_LowerBits;
261
        CCPR1L = computedDutyCycleHigh_UpperByte;
262
    } else {
263
        CCP1CONbits.DC1B = computedDutyCycleLow_LowerBits;
264
        CCPR1L = computedDutyCycleLow_UpperByte;
265
    }
266
    while (!PIR1bits.TMR2IF);
267
    PIR1bits.TMR2IF = 0;
268
 
269
    // Bit 6
270
    if (savedPattern & 0x0040) {
271
        CCP1CONbits.DC1B = computedDutyCycleHigh_LowerBits;
272
        CCPR1L = computedDutyCycleHigh_UpperByte;
273
    } else {
274
        CCP1CONbits.DC1B = computedDutyCycleLow_LowerBits;
275
        CCPR1L = computedDutyCycleLow_UpperByte;
276
    }
277
    while (!PIR1bits.TMR2IF);
278
    PIR1bits.TMR2IF = 0;
279
 
280
    // Bit 5
281
    if (savedPattern & 0x0020) {
282
        CCP1CONbits.DC1B = computedDutyCycleHigh_LowerBits;
283
        CCPR1L = computedDutyCycleHigh_UpperByte;
284
    } else {
285
        CCP1CONbits.DC1B = computedDutyCycleLow_LowerBits;
286
        CCPR1L = computedDutyCycleLow_UpperByte;
287
    }
288
    while (!PIR1bits.TMR2IF);
289
    PIR1bits.TMR2IF = 0;
290
 
291
    // Bit 4
292
    if (savedPattern & 0x0010) {
293
        CCP1CONbits.DC1B = computedDutyCycleHigh_LowerBits;
294
        CCPR1L = computedDutyCycleHigh_UpperByte;
295
    } else {
296
        CCP1CONbits.DC1B = computedDutyCycleLow_LowerBits;
297
        CCPR1L = computedDutyCycleLow_UpperByte;
298
    }
299
    while (!PIR1bits.TMR2IF);
300
    PIR1bits.TMR2IF = 0;
301
 
302
    // Bit 3
303
    if (savedPattern & 0x0008) {
304
        CCP1CONbits.DC1B = computedDutyCycleHigh_LowerBits;
305
        CCPR1L = computedDutyCycleHigh_UpperByte;
306
    } else {
307
        CCP1CONbits.DC1B = computedDutyCycleLow_LowerBits;
308
        CCPR1L = computedDutyCycleLow_UpperByte;
309
    }
310
    while (!PIR1bits.TMR2IF);
311
    PIR1bits.TMR2IF = 0;
312
 
313
    // Bit 2
314
    if (savedPattern & 0x0004) {
315
        CCP1CONbits.DC1B = computedDutyCycleHigh_LowerBits;
316
        CCPR1L = computedDutyCycleHigh_UpperByte;
317
    } else {
318
        CCP1CONbits.DC1B = computedDutyCycleLow_LowerBits;
319
        CCPR1L = computedDutyCycleLow_UpperByte;
320
    }
321
    while (!PIR1bits.TMR2IF);
322
    PIR1bits.TMR2IF = 0;
323
 
324
    // Bit 1
325
    if (savedPattern & 0x0002) {
326
        CCP1CONbits.DC1B = computedDutyCycleHigh_LowerBits;
327
        CCPR1L = computedDutyCycleHigh_UpperByte;
328
    } else {
329
        CCP1CONbits.DC1B = computedDutyCycleLow_LowerBits;
330
        CCPR1L = computedDutyCycleLow_UpperByte;
331
    }
332
    while (!PIR1bits.TMR2IF);
333
    PIR1bits.TMR2IF = 0;
334
 
335
    // Bit 0
336
    if (savedPattern & 0x0001) {
337
        CCP1CONbits.DC1B = computedDutyCycleHigh_LowerBits;
338
        CCPR1L = computedDutyCycleHigh_UpperByte;
339
    } else {
340
        CCP1CONbits.DC1B = computedDutyCycleLow_LowerBits;
341
        CCPR1L = computedDutyCycleLow_UpperByte;
342
    }
343
    while (!PIR1bits.TMR2IF);
344
    PIR1bits.TMR2IF = 0;
345
 
346
    // Set next duty cycle to 0% (idle line low)
347
    CCP1CONbits.DC1B = 0b00;
348
    CCPR1L = 0x00;
349
 
350
    // Wait for timer to rollover, then turn off timer
351
    while (!PIR1bits.TMR2IF);
352
    PIR1bits.TMR2IF = 0;
353
    T2CONbits.TMR2ON = 0;
354
    TMR2 = 0x0;
355
}