Sinusoidal_6015.c


1
//---------------------------------------------------------------------
2
//
3
//               Software License Agreement
4
//
5
// The software supplied herewith by Microchip Technology Incorporated 
6
// (the ?Company?) for its PICmicro® Microcontroller is intended and 
7
// supplied to you, the Company?s customer, for use solely and 
8
// exclusively on Microchip PICmicro Microcontroller products. The 
9
// software is owned by the Company and/or its supplier, and is 
10
// protected under applicable copyright laws. All rights are reserved. 
11
//  Any use in violation of the foregoing restrictions may subject the 
12
// user to criminal sanctions under applicable laws, as well as to 
13
// civil liability for the breach of the terms and conditions of this 
14
// license.
15
//
16
// THIS SOFTWARE IS PROVIDED IN AN ?AS IS? CONDITION. NO WARRANTIES, 
17
// WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED 
18
// TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 
19
// PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT, 
20
// IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR 
21
// CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
22
//
23
//---------------------------------------------------------------------
24
//  File:    sinusoidal_6015.c
25
//
26
//  Written By:  Jorge Zambada, Microchip Technology
27
// 
28
// The following files should be included in the MPLAB project:
29
//
30
//    sinusoidal_6015.c  -- Main source code file
31
//    SVM.c          -- Space Vector Modulation file
32
//    SVM.h            
33
//    p30f6015.gld      -- Linker script file
34
//---------------------------------------------------------------------
35
36
#include "p30f6015.h"
37
#include "svm.h"
38
39
//--------------------------Device Configuration------------------------ 
40
_FOSC(FRC_PLL8 & CSW_FSCM_OFF);
41
_FWDT(WDT_OFF);
42
_FBORPOR(PBOR_OFF & BORV27 & PWRT_16 & MCLR_DIS & PWMxH_ACT_HI & PWMxL_ACT_HI & RST_IOPIN);
43
_FGS(GSS_OFF & GWRP_OFF);
44
_FBS(NO_BOOT_RAM & NO_BOOT_EEPROM & NO_BOOT_CODE & WR_PROTECT_BOOT_OFF);
45
_FSS(NO_SEC_RAM & NO_SEC_EEPROM & NO_SEC_CODE & WR_PROT_SEC_OFF);
46
_ICD(ICS_PGD);
47
48
//----------------------------------------------------------------------
49
50
//   Hurst Motor Terminals | MC LV PICDEM Board Connection
51
// -----------------------|---------------------------------
52
//  Ground Phase ---------|-- G
53
//  Phase Red    ---------|-- M1
54
//  Phase Black  ---------|-- M2
55
//  Phase White  ---------|-- M3
56
//  Hall White   ---------|-- HA
57
//  Hall Brown   ---------|-- HB
58
//  Hall Green   ---------|-- HC
59
60
typedef signed int SFRAC16;  
61
62
//#define CLOSED_LOOP      // if defined the speed controller will be enabled //dis 29.10.2023
63
#define  PHASE_ADVANCE    // for extended speed ranges this should be defined
64
65
#define FCY  20000000   // xtal = 5Mhz; PLLx16 -> 20 MIPS
66
#define FPWM 20000     // 20 kHz, so that no audible noise is present.
67
#define _10MILLISEC   10  // Used as a timeout with no hall effect sensors
68
                         // transitions and Forcing steps according to the
69
                         // actual position of the motor
70
#define _100MILLISEC 1000 // after this time has elapsed, the motor is
71
                         // consider stalled and it's stopped
72
73
// These Phase values represent the base Phase value of the sinewave for each
74
// one of the sectors (each sector is a translation of the hall effect sensors
75
// reading 
76
#define PHASE_ZERO   57344
77
#define PHASE_ONE  ((PHASE_ZERO + 65536/6) % 65536)
78
#define PHASE_TWO  ((PHASE_ONE + 65536/6) % 65536)
79
#define PHASE_THREE  ((PHASE_TWO + 65536/6) % 65536)
80
#define PHASE_FOUR  ((PHASE_THREE + 65536/6) % 65536)
81
#define PHASE_FIVE  ((PHASE_FOUR + 65536/6) % 65536)
82
83
#define MAX_PH_ADV_DEG 60  // This value represents the maximum allowed phase
84
                           // advance in electrical degrees. Set a value from
85
                           // 0 to 60. This value will be used to calculate
86
                           // phase advance only if PHASE_ADVANCE is defined
87
88
// This is the calculation from the required phase advance to the actual
89
// value to be multiplied by the speed of the motor. So, if PHASE_ADVANCE is
90
// enabled, a certain amount of shit angle will be added to the generated
91
// sine wave, up to a maximum of the specified value on MAX_PH_ADV_DEG. This
92
// maximum phase shift will be present when the MeasuredSpeed variable is a 
93
// fractional 1.0 (for CW) or -1.0 (for CCW).
94
#define MAX_PH_ADV     (int)(((float)MAX_PH_ADV_DEG / 360.0) * 65536.0)
95
96
#define HALLA  1  // Connected to RB3
97
#define HALLB  2  // Connected to RB4
98
#define HALLC  4  // Connected to RB5
99
#define CW  0    // Counter Clock Wise direction
100
#define CCW  1    // Clock Wise direction                                                               //03.04.2024
101
#define SWITCH_S2  (!PORTCbits.RC14) // Push button S2
102
103
// Period Calculation
104
// Period = (TMRClock * 60) / (RPM * Motor_Poles)
105
// For example>
106
// Motor_Poles = 10
107
// RPM = 6000 (Max Speed)
108
// Period = ((20,000,000 / 64) * 60) / (6000 * 10) = 312.5
109
// RPM = 60 (Min Speed)
110
// Period = ((20,000,000 / 64) * 60) / (60 * 10) = 31250
111
112
#define MINPERIOD  156  // For 6000 max rpm and 10 poles motor // vorher 312 29.10.2023
113
#define MAXPERIOD  51250  // For 60 min rpm and 10 poles motor  //31250
114
115
// Use this MACRO when using floats to initialize signed 16-bit fractional 
116
// variables
117
118
#define SFloat_To_SFrac16(Float_Value)  \
119
        ((Float_Value < 0.0) ? (SFRAC16)(32768 * (Float_Value) - 0.5) \
120
        : (SFRAC16)(32767 * (Float_Value) + 0.5))
121
122
void InitADC10(void);  // Initialization of ADC used for Speed Command
123
void InitMCPWM(void);  // Initialization for PWM at 20kHz, Center aligned, 
124
                        // Complementary mode with 500 ns of deadtime
125
void InitTMR1(void);  // Initialization for TIMER1 used for speed control 
126
                        // and motor stalled protection
127
void InitTMR3(void);  // Initialization for TIMER3 used as a timebase 
128
                        // for the two input capture channels
129
void InitUserInt(void);  // This function initializes all ports 
130
                        // (inputs and outputs) for the application
131
void InitICandCN(void);  // Initializes input captures and change notification, 
132
                        // used for the hall sensor inputs
133
void RunMotor(void);  // This function initializes all variables 
134
                        // and interrupts used for starting and running 
135
                        // the motor
136
void StopMotor(void);  // This function clears all flags, and stops anything
137
                        // related to motor control, and also disables PWMs
138
void SpeedControl(void);     // This function contains all ASM and C operations
139
                             // for doing the PID Control loop for the speed
140
void ForceCommutation(void); // When motor is to slow to generate interrupts 
141
                             // on halls, this function forces a commutation
142
void ChargeBootstraps(void); // At the begining of the motor operation, the 
143
                             // bootstrap caps are charged with this function
144
145
// Constants used for properly energizing the motor depending on the 
146
// rotor's position
147
const int PhaseValues[6] =
148
{PHASE_ZERO, PHASE_ONE, PHASE_TWO, PHASE_THREE, PHASE_FOUR, PHASE_FIVE}; 
149
150
// In the sinewave generation algorithm we need an offset to be added to the
151
// pointer when energizing the motor in CCW. This is done to compensate an
152
// asymetry of the sinewave
153
int PhaseOffset = 4100;
154
155
// Flags used for the application
156
struct 
157
{
158
  unsigned MotorRunning  :1;  // This bit is 1 if motor running
159
  unsigned unused      :15;
160
}Flags;
161
162
163
unsigned int Phase;  // This variable is incremented by the PWM interrupt
164
                    // in order to generate a proper sinewave. Its value
165
                    // is incremented by a value of PhaseInc, which
166
                    // represents the frequency of the generated sinewave
167
signed int PhaseInc; // Delta increments of the Phase variable, calculated 
168
                     // in the TIMER1 interrupt (each 1 ms) and used in 
169
                     // the PWM interrupt (each 50 us)
170
signed int PhaseAdvance; // Used for extending motor speed range. This value
171
                         // is added directly to the parameters passed to the
172
                         // SVM function (the sine wave generation subroutine)
173
unsigned int HallValue;   // This variable holds the hall sensor input readings
174
unsigned int Sector;  // This variables holds present sector value, which is 
175
                      // the rotor position
176
unsigned int LastSector; // This variable holds the last sector value. This 
177
                         // is critical to filter slow slew rate on the Hall
178
                         // effect sensors hardware
179
unsigned int MotorStalledCounter = 0; // This variable gets incremented each 
180
                                      // 1 ms, and is cleared everytime a new
181
                                      // sector is detected. Used for 
182
                                      // ForceCommutation and MotorStalled 
183
                                      // protection functions
184
185
// This array translates the hall state value read from the digital I/O to the
186
// proper sector.  Hall values of 0 or 7 represent illegal values and therefore
187
// return -1.
188
char SectorTable[] = {-1,4,2,3,0,5,1,-1};
189
190
unsigned char Current_Direction;  // Current mechanical motor direction of 
191
                                    // rotation Calculated in halls interrupts
192
unsigned char Required_Direction;  // Required mechanical motor direction of 
193
                                    // rotation, will have the same sign as the
194
                  // ControlOutput variable from the Speed 
195
                                    // Controller
196
  
197
// Variables containing the Period of half an electrical cycle, which is an 
198
// interrupt each edge of one of the hall sensor input
199
unsigned int PastCapture, ActualCapture, Period; 
200
// Used as a temporal variable to perform a fractional divide operation in 
201
// assembly
202
SFRAC16 _MINPERIOD = MINPERIOD - 1;
203
204
SFRAC16 MeasuredSpeed, RefSpeed;  // Actual and Desired speeds for the PID 
205
                            // controller, that will generate the error
206
SFRAC16 ControlOutput = 0;  // Controller output, used as a voltage output, 
207
                            // use its sign for the required direction
208
209
// Absolute PID gains used by the controller. Position form implementation of 
210
// a digital PID. See SpeedControl subroutine for details
211
SFRAC16 Kp = SFloat_To_SFrac16(0.1);   // P Gain  //0,1
212
SFRAC16 Ki = SFloat_To_SFrac16(0.01);  // I Gain   //0,01
213
SFRAC16 Kd = SFloat_To_SFrac16(0.000); // D Gain  //0,000
214
215
// Constants used by the PID controller, since a MAC operation is used, the 
216
// PID structure is changed (See SpeedControl() Comments)
217
SFRAC16 ControlDifference[3] \
218
        __attribute__((__space__(xmemory), __aligned__(4)));
219
SFRAC16 PIDCoefficients[3]   \
220
        __attribute__((__space__(ymemory), __aligned__(4)));
221
222
// Used as a temporal variable to perform a fractional divide operation in 
223
// assembly
224
SFRAC16 _MAX_PH_ADV = MAX_PH_ADV;
225
226
/*********************************************************************
227
  Function:        void __attribute__((__interrupt__)) _T1Interrupt (void)
228
229
  PreCondition:    The motor is running and is generating hall effect sensors
230
                   interrupts. Also, the actual direction of the motor used
231
                   in this interrupt is assumed to be previously calculated.
232
 
233
  Input:           None.
234
235
  Output:          None.
236
237
  Side Effects:    None.
238
239
  Overview:        In this ISR the Period, Phase Increment and MeasuredSpeed
240
                   are calculated based on the input capture of one of the
241
                   halls. The speed controller is also called in this ISR
242
                   to generate a new output voltage (ControlOutput). The 
243
                   Phase Advance is calculated based on the maximum allowed
244
                   phase advance (MAX_PH_ADV) and the actual speed of the 
245
                   motor. The last thing done in this ISR is the forced 
246
                   commutation, which happens each time the motor doesn't
247
                   generate a new hall interrupt after a programmed period 
248
                   of time. If the timeout for generating hall ISR is too much
249
                   (i.e. 100 ms) the motor is then stopped.
250
251
  Note:            The MeasuredSpeed Calculation is made in assembly to take 
252
                   advantage of the signed fractional division.
253
********************************************************************/
254
255
void __attribute__((interrupt, no_auto_psv)) _T1Interrupt (void)
256
{
257
  IFS0bits.T1IF = 0;
258
  Period = ActualCapture - PastCapture;  // This is an UNsigned substraction
259
                                           // to get the Period between one 
260
                                           // hall effect sensor transition
261
262
    // These operations limit the Period value to a range from 60 to 6000 rpm
263
  if (Period < (unsigned int)MINPERIOD)  // MINPERIOD or 6000 rpm
264
    Period = MINPERIOD;
265
  else if (Period > (unsigned int)MAXPERIOD) // MAXPERIOD or 60 rpm
266
    Period = MAXPERIOD;
267
268
    // PhaseInc is a value added to the Phase variable to generate the sine
269
    // voltages. 1 electrical degree corresponds to a PhaseInc value of 184,
270
    // since the pointer to the sine table is a 16bit value, where 360 Elec
271
    // Degrees represents 65535 in the pointer. 
272
    // __builtin_divud(Long Value, Int Value) is a function of the compiler
273
    // to do Long over Integer divisions.
274
  PhaseInc = __builtin_divud(512000UL, Period);  // Phase increment is used
275
                           // by the PWM isr (SVM)
276
277
    // This subroutine in assembly calculates the MeasuredSpeed using 
278
    // fractional division. These operations in assembly perform the following
279
    // formula:
280
    //                   MINPERIOD (in fractional) 
281
    //  MeasuredSpeed = ---------------------------
282
    //                    Period (in fractional)
283
    //
284
285
  __asm__ volatile("repeat #17\n\t"
286
                     "divf %1,%2\n\t"
287
                     "mov w0,%0" : /* output */ "=g"(MeasuredSpeed)  
288
                                 : /* input */ "r"(_MINPERIOD),
289
                                               "e"(Period)
290
                                 : /* clobber */ "w0");
291
292
    // MeasuredSpeed sign adjustment based on current motor direction of 
293
    // rotation
294
  if (Current_Direction == CCW)
295
    MeasuredSpeed = -MeasuredSpeed;
296
297
    // The following values represent the MeasuredSpeed values from the 
298
    // previous operations:
299
    //
300
  // CONDITION        RPM          SFRAC16      SINT      HEX
301
  // Max Speed CW  -> 6000 RPM  -> 0.996805  -> 32663  -> 0x7F97
302
  // Min Speed CW  -> 60 RPM    -> 0.009984  -> 327    -> 0x0147
303
  // Min Speed CCW -> -60 RPM   -> -0.009984 -> -327   -> 0xFEB9
304
  // Max Speed CCW -> -6000 RPM -> -0.996805 -> -32663 -> 0x8069
305
306
  SpeedControl(); // Speed PID controller is called here. It will use 
307
                    // MeasuredSpeed, RefSpeed, some buffers and will generate
308
                    // the new ControlOutput, which represents a new amplitude
309
                    // of the sinewave that will be generated by the SVM 
310
                    // subroutine.
311
312
#ifdef PHASE_ADVANCE
313
  // Calculate Phase Advance Based on Actual Speed and MAX_PH_ADV define
314
        // The following assembly instruction perform the following formula
315
        // using fractional multiplication:
316
        // 
317
        // PhaseAdvance = MAX_PH_ADV * MeasuredSpeed
318
        //
319
320
        register int a_reg asm("A");
321
        a_reg = __builtin_mpy(_MAX_PH_ADV, MeasuredSpeed, 0,0,0,0,0,0);
322
        PhaseAdvance = __builtin_sac(a_reg,0);
323
           
324
#endif
325
326
//  MotorStalledCounter++;  // We increment a timeout variable to see if the////////////////////////04.03.2024
327
                            // motor is too slow (not generating hall effect
328
                            // sensors interrupts frequently enough) or if
329
                            // the motor is stalled. This variable is cleared
330
                            // in halls ISRs
331
    if ((MotorStalledCounter % _10MILLISEC) == 0)
332
  {
333
    ForceCommutation();  // Force Commutation if no hall sensor changes 
334
                            // have occured in specified timeout.
335
  }
336
  else if (MotorStalledCounter >= _100MILLISEC)
337
  {
338
    StopMotor(); // Stop motor is no hall changes have occured in 
339
                     // specified timeout
340
  }
341
  return;
342
}
343
344
/*********************************************************************
345
  Function:        void __attribute__((__interrupt__)) _CNInterrupt (void)
346
347
  PreCondition:    The inputs of the hall effect sensors should have low pass
348
                   filters. A simple RC network works.
349
 
350
  Input:           None.
351
352
  Output:          None.
353
354
  Side Effects:    None.
355
356
  Overview:        This interrupt represent Hall A ISR. Hall A -> RB3 -> CN5.
357
                   This is generated by the input change notification CN5.
358
                   The purpose of this ISR is to Calculate the actual 
359
                   mechanical direction of rotation of the motor, and to adjust
360
                   the Phase variable depending on the sector the rotor is in.
361
362
  Note 1:          The sector is validated in order to avoid any spurious
363
                   interrupt due to a slow slew rate on the halls inputs due to
364
                   hardware filtering.
365
366
  Note 2:          For Phase adjustment in CCW, an offset is added to 
367
                   compensate non-symetries in the sine table used.
368
********************************************************************/
369
370
void __attribute__((interrupt, no_auto_psv)) _CNInterrupt (void)
371
{
372
  IFS0bits.CNIF = 0;  // Clear interrupt flag
373
  HallValue = (unsigned int)((PORTB >> 3) & 0x0007);  // Read halls
374
  Sector = SectorTable[HallValue];  // Get Sector from table
375
376
    // This MUST be done for getting around the HW slow rate
377
  if (Sector != LastSector)  
378
  {
379
    // Since a new sector is detected, clear variable that would stop 
380
        // the motor if stalled.
381
    MotorStalledCounter = 0;
382
383
    // Motor current direction is computed based on Sector
384
    if ((Sector == 5) || (Sector == 2))  
385
      Current_Direction = CCW;
386
    else
387
      Current_Direction = CW;
388
389
        // Motor commutation is actually based on the required direction, not
390
        // the current dir. This allows driving the motor in four quadrants
391
    if (Required_Direction == CW)  
392
    {
393
      Phase = PhaseValues[Sector];
394
    }
395
    else
396
    {
397
      // For CCW an offset must be added to compensate difference in 
398
            // symmetry of the sine table used for CW and CCW
399
      Phase = PhaseValues[(Sector + 3) % 6] + PhaseOffset;
400
    }
401
    LastSector = Sector; // Update last sector
402
  }
403
404
  return;
405
}
406
407
/*********************************************************************
408
  Function:        void __attribute__((__interrupt__)) _IC7Interrupt (void)
409
410
  PreCondition:    The inputs of the hall effect sensors should have low pass
411
                   filters. A simple RC network works.
412
 
413
  Input:           None.
414
415
  Output:          None.
416
417
  Side Effects:    None.
418
419
  Overview:        This interrupt represent Hall B ISR. Hall B -> RB4 -> IC7.
420
                   This is generated by the input Capture Channel IC7.
421
                   The purpose of this ISR is to Calculate the actual Period
422
                   between hall effect sensor transitions, calculate the actual
423
                   mechanical direction of rotation of the motor, and also to
424
                   adjust the Phase variable depending on the sector the rotor
425
                   is in.
426
427
  Note 1:          The sector is validated in order to avoid any spurious
428
                   interrupt due to a slow slew rate on the halls inputs due to
429
                   hardware filtering.
430
431
  Note 2:          For Phase adjustment in CCW, an offset is added to 
432
                   compensate non-symetries in the sine table used.
433
********************************************************************/
434
435
void __attribute__((interrupt, no_auto_psv)) _IC7Interrupt (void)
436
{
437
  IFS1bits.IC7IF = 0;  // Cleat interrupt flag
438
  HallValue = (unsigned int)((PORTB >> 3) & 0x0007);  // Read halls
439
  Sector = SectorTable[HallValue];  // Get Sector from table
440
441
    // This MUST be done for getting around the HW slow rate
442
  if (Sector != LastSector)
443
  {
444
    // Calculate Hall period corresponding to half an electrical cycle
445
    PastCapture = ActualCapture;
446
    ActualCapture = IC7BUF;
447
    IC7BUF;
448
    IC7BUF;
449
    IC7BUF;
450
451
    // Since a new sector is detected, clear variable that would stop 
452
        // the motor if stalled.
453
    MotorStalledCounter = 0;
454
455
    // Motor current direction is computed based on Sector
456
    if ((Sector == 3) || (Sector == 0))
457
      Current_Direction = CCW;
458
    else
459
      Current_Direction = CW;
460
461
        // Motor commutation is actually based on the required direction, not
462
        // the current dir. This allows driving the motor in four quadrants
463
    if (Required_Direction == CW)
464
    {
465
      Phase = PhaseValues[Sector];
466
    }
467
    else
468
    {
469
      // For CCW an offset must be added to compensate difference in 
470
            // symmetry of the sine table used for CW and CCW
471
      Phase = PhaseValues[(Sector + 3) % 6] + PhaseOffset;
472
    }
473
    LastSector = Sector; // Update last sector
474
  }
475
476
  return;
477
}
478
479
/*********************************************************************
480
  Function:        void __attribute__((__interrupt__)) _IC8Interrupt (void)
481
482
  PreCondition:    The inputs of the hall effect sensors should have low pass
483
                   filters. A simple RC network works.
484
 
485
  Input:           None.
486
487
  Output:          None.
488
489
  Side Effects:    None.
490
491
  Overview:        This interrupt represent Hall C ISR. Hall C -> RB5 -> IC8.
492
                   This is generated by the input Capture Channel IC8.
493
                   The purpose of this ISR is to Calculate the actual 
494
                   mechanical direction of rotation of the motor, and to adjust
495
                   the Phase variable depending on the sector the rotor is in.
496
497
  Note 1:          The sector is validated in order to avoid any spurious
498
                   interrupt due to a slow slew rate on the halls inputs due to
499
                   hardware filtering.
500
501
  Note 2:          For Phase adjustment in CCW, an offset is added to 
502
                   compensate non-symetries in the sine table used.
503
********************************************************************/
504
505
void __attribute__((interrupt, no_auto_psv)) _IC8Interrupt (void)
506
{  
507
  IFS1bits.IC8IF = 0;  // Cleat interrupt flag
508
  HallValue = (unsigned int)((PORTB >> 3) & 0x0007);  // Read halls
509
  Sector = SectorTable[HallValue];  // Get Sector from table
510
511
    // This MUST be done for getting around the HW slow rate
512
  if (Sector != LastSector)
513
  {
514
    // Since a new sector is detected, clear variable that would stop 
515
        // the motor if stalled.
516
    MotorStalledCounter = 0;
517
518
    // Motor current direction is computed based on Sector
519
    if ((Sector == 1) || (Sector == 4))
520
      Current_Direction = CCW;
521
    else
522
      Current_Direction = CW;
523
    
524
        // Motor commutation is actually based on the required direction, not
525
        // the current dir. This allows driving the motor in four quadrants
526
    if (Required_Direction == CW)
527
    {
528
      Phase = PhaseValues[Sector];
529
    }
530
    else
531
    {
532
      // For CCW an offset must be added to compensate difference in 
533
            // symmetry of the sine table used for CW and CCW
534
      Phase = PhaseValues[(Sector + 3) % 6] + PhaseOffset;
535
    }
536
    LastSector = Sector; // Update last sector
537
  }
538
539
  return;
540
}
541
542
/*********************************************************************
543
  Function:        void __attribute__((__interrupt__)) _PWMInterrupt (void)
544
545
  PreCondition:    None.
546
 
547
  Input:           None.
548
549
  Output:          None.
550
551
  Side Effects:    None.
552
553
  Overview:        in this ISR the sinewave is generated. If the current motor
554
                   direction of rotation is different from the required 
555
                   direction then the motor is operated  in braking mode and 
556
                   step commutation is performed. Once both directions are 
557
                   equal then the sinewave is fed into the motor windings.
558
                   If PHASE_ADVANCE is defined, a value corresponding to the
559
                   multiplication of the actual speed * maximum phase advance
560
                   is added to the sine wave phase to produce the phase shift
561
562
  Note:            None.
563
********************************************************************/
564
565
void __attribute__((interrupt, no_auto_psv)) _PWMInterrupt (void)
566
{
567
  IFS2bits.PWMIF = 0;  // Clear interrupt flag
568
569
  if (Required_Direction == CW)
570
  {
571
    if (Current_Direction == CW)
572
      Phase += PhaseInc;    // Increment Phase if CW to generate the 
573
                                  // sinewave only if both directions are equal
574
    // If Required_Direction is CW (forward) POSITIVE voltage is applied
575
    #ifdef PHASE_ADVANCE
576
    SVM(ControlOutput, Phase + PhaseAdvance);  // PhaseAdvance addition
577
                          // produces the sinewave
578
                          // phase shift
579
    #else
580
    SVM(ControlOutput, Phase);
581
    #endif
582
  }
583
  else
584
  {
585
    if (Current_Direction == CCW)  
586
      Phase -= PhaseInc;      // Decrement Phase if CCW to generate
587
                  // the sinewave only if both 
588
                  // directions are equal
589
    // If Required_Direction is CCW (reverse) NEGATIVE voltage is applied
590
    #ifdef PHASE_ADVANCE
591
    SVM(-(ControlOutput+1), Phase + PhaseAdvance);// PhaseAdvance addition
592
                            // produces the sinewave
593
                            // phase shift
594
    #else
595
    SVM(-(ControlOutput+1), Phase);
596
    #endif
597
  }
598
  return;
599
}
600
601
/*********************************************************************
602
  Function:        void __attribute__((__interrupt__)) _ADCInterrupt (void)
603
604
  PreCondition:    None.
605
 
606
  Input:           None.
607
608
  Output:          None.
609
610
  Side Effects:    None.
611
612
  Overview:        The ADC interrupt loads the reference speed (RefSpeed) with
613
                   the respective value of the POT. The value will be a signed
614
                   fractional value, so it doesn't need any scaling.
615
616
  Note:            None.
617
********************************************************************/
618
619
void __attribute__((interrupt, no_auto_psv)) _ADCInterrupt (void)
620
{
621
  IFS0bits.ADIF = 0;  // Clear interrupt flag
622
  RefSpeed = ADCBUF0/2;  //(ADCBUF0/2)+0x8000; // Read POT value to set Reference Speed                      //03.04.2024
623
    RefSpeed = RefSpeed + 0x8000;                                                           //rückwärts 06.05.2024
624
    /*
625
    __asm ("push W0");
626
    __asm ("push W1");
627
    __asm ("mov #0xffc0,W0");
628
    __asm ("mov _RefSpeed,W1");
629
    __asm ("com  W1,W0") ;
630
    __asm ("and  W1,W0,W1") ;
631
    __asm ("mov W1, _RefSpeed") ;
632
    __asm ("pop W0");
633
    __asm ("pop W1");
634
    RefSpeed = RefSpeed + 0x8000;
635
     */
636
  return;
637
}
638
639
/*********************************************************************
640
  Function:        int main(void)
641
642
  PreCondition:    None.
643
 
644
  Input:           None.
645
646
  Output:          None.
647
648
  Side Effects:    None.
649
650
  Overview:        main function of the application. Peripherals are 
651
                   initialized, and then, depending on the motor status 
652
                   (running or stopped) and  if the push button is pressed, 
653
                   the motor is started or stopped.  All other operations and
654
                   state machines are performed with interrupts.
655
656
  Note:            None.
657
********************************************************************/
658
659
int main(void)
660
{
661
  InitUserInt();  // Initialize User Interface I/Os
662
  InitADC10();  // Initialize ADC to be signed fractional
663
  InitTMR1();    // Initialize TMR1 for 1 ms periodic ISR
664
  InitTMR3();    // Initialize TMR3 for timebase of capture
665
  InitICandCN();  // Initialize Hall sensor inputs ISRs  
666
  InitMCPWM();  // Initialize PWM @ 20 kHz, center aligned, 500 ns of 
667
                    // deadtime
668
  for(;;)
669
  {
670
        
671
    if ((SWITCH_S2) && (!Flags.MotorRunning))
672
    {
673
      while(SWITCH_S2);
674
      RunMotor();  // Run motor if push button is pressed and motor is
675
                        // stopped
676
    }
677
    else if ((SWITCH_S2) && (Flags.MotorRunning))
678
    {
679
      while(SWITCH_S2);
680
      StopMotor();// Stop motor if push button is pressed and motor is 
681
                        // running
682
    }
683
 
684
  }
685
  return 0;
686
}
687
688
/*********************************************************************
689
  Function:        void ChargeBootstraps(void)
690
691
  PreCondition:    None.
692
 
693
  Input:           None.
694
695
  Output:          None.
696
697
  Side Effects:    None.
698
699
  Overview:        In the topology used, it is necessary to charge the 
700
                   bootstrap caps each time the motor is energized for the 
701
                   first time after an undetermined amount of time. 
702
                   ChargeBootstraps subroutine turns ON  the lower transistors
703
                   for 10 ms to ensure voltage on these caps, and then it 
704
                   transfers the control of the outputs to the PWM module.
705
706
  Note:            None.
707
********************************************************************/
708
709
void ChargeBootstraps(void)
710
{
711
  unsigned int i;
712
  OVDCON = 0x0015;  // Turn ON low side transistors to charge
713
  for (i = 0; i < 33330; i++) // 10 ms Delay at 20 MIPs
714
    ;
715
  PWMCON2bits.UDIS = 1;
716
  PDC1 = PTPER;  // Initialize as 0 voltage
717
  PDC2 = PTPER;  // Initialize as 0 voltage
718
  PDC3 = PTPER;  // Initialize as 0 voltage
719
  OVDCON = 0x3F00;  // Configure PWM0-5 to be governed by PWM module
720
  PWMCON2bits.UDIS = 0;
721
  return;
722
}
723
724
/*********************************************************************
725
726
  Function:        void RunMotor(void)
727
728
  PreCondition:    None.
729
 
730
  Input:           None.
731
732
  Output:          None.
733
734
  Side Effects:    None.
735
736
  Overview:        Call this subroutine when first trying to run the motor and
737
                   the motor is previously stopped. RunMotor will charge 
738
                   bootstrap caps, will initialize application variables, and
739
                   will enable all ISRs.
740
741
  Note:            None.
742
********************************************************************/
743
744
void RunMotor(void)
745
{
746
  ChargeBootstraps();
747
  // init variables
748
  ControlDifference[0] = 0;  // Error at K  (most recent)
749
  ControlDifference[1] = 0;  // Error at K-1
750
  ControlDifference[2] = 0;  // Error at K-2  (least recent)
751
  PIDCoefficients[0] = Kp + Ki + Kd;  // Modified coefficient for using MACs
752
  PIDCoefficients[1] = -(Kp + 2*Kd);  // Modified coefficient for using MACs
753
  PIDCoefficients[2] = Kd;      // Modified coefficient for using MACs
754
  
755
  TMR1 = 0;      // Reset timer 1 for speed control
756
  TMR3 = 0;      // Reset timer 3 for speed measurement
757
  ActualCapture = MAXPERIOD;   // Initialize captures for minimum speed 
758
                //(60 RPMs)
759
  PastCapture = 0;
760
761
  // Initialize direction with required direction
762
  // Remember that ADC is not stopped.
763
  HallValue = (unsigned int)((PORTB >> 3) & 0x0007);  // Read halls
764
  LastSector = Sector = SectorTable[HallValue];  // Initialize Sector 
765
    
766
767
  // RefSpeed's sign will determine if the motor should be run at CW 
768
    // (+RefSpeed) or CCW (-RefSpeed) ONLY at start up, since when the motor 
769
    // has started, the required direction will be set by the control output
770
    // variable to be able to operate in the four quadrants
771
  if (RefSpeed < 0)
772
  {
773
    ControlOutput = 0;  // Initial output voltage
774
    Current_Direction = Required_Direction = CCW;
775
    Phase = PhaseValues[(Sector + 3) % 6] + PhaseOffset;
776
  }
777
  else
778
  {
779
    ControlOutput = 0;  // Initial output voltage
780
    Current_Direction = Required_Direction = CW;
781
    Phase = PhaseValues[Sector];
782
  }
783
784
  MotorStalledCounter = 0;  // Reset motor stalled protection counter
785
  // Set initial Phase increment with minimum value. This will change if a 
786
    // costing operation is required by the application
787
  PhaseInc = __builtin_divud(512000UL, MAXPERIOD);  
788
789
  // Clear all interrupts flags
790
  IFS0bits.T1IF = 0;  // Clear timer 1 flag
791
  IFS0bits.CNIF = 0;  // Clear interrupt flag
792
  IFS1bits.IC7IF = 0;  // Clear interrupt flag
793
  IFS1bits.IC8IF = 0;  // Clear interrupt flag
794
  IFS2bits.PWMIF = 0;  // Clear interrupt flag
795
796
  // enable all interrupts
797
  __asm__ volatile ("DISI #0x3FFF");
798
  IEC0bits.T1IE = 1;  // Enable interrupts for timer 1
799
  IEC0bits.CNIE = 1;  // Enable interrupts on CN5
800
  IEC1bits.IC7IE = 1;  // Enable interrupts on IC7
801
  IEC1bits.IC8IE = 1;  // Enable interrupts on IC8
802
  IEC2bits.PWMIE = 1;  // Enable PWM interrupts
803
    DISICNT = 0;
804
805
  Flags.MotorRunning = 1;  // Indicate that the motor is running
806
  return;
807
}
808
809
/*********************************************************************
810
  Function:        void StopMotor(void)
811
812
  PreCondition:    None.
813
 
814
  Input:           None.
815
816
  Output:          None.
817
818
  Side Effects:    None.
819
820
  Overview:        Call this subroutine whenever the user want to stop the 
821
                   motor. This subroutine will clear interrupts properly, and
822
                   will also turn OFF all PWM channels.
823
824
  Note:            None.
825
********************************************************************/
826
void StopMotor(void)
827
{
828
  OVDCON = 0x0000;  // turn OFF every transistor
829
  
830
  // disable all interrupts
831
  __asm__ volatile ("DISI #0x3FFF");
832
  IEC0bits.T1IE = 0;  // Disable interrupts for timer 1
833
  IEC0bits.CNIE = 0;  // Disable interrupts on CN5
834
  IEC1bits.IC7IE = 0;  // Disable interrupts on IC7
835
  IEC1bits.IC8IE = 0;  // Disable interrupts on IC8
836
  IEC2bits.PWMIE = 0;  // Disable PWM interrupts
837
    DISICNT = 0;
838
839
  Flags.MotorRunning = 0;  // Indicate that the motor has been stopped
840
  return;
841
}
842
843
/*********************************************************************
844
  Function:        void SpeedControl(void)
845
846
  PreCondition:    None.
847
 
848
  Input:           None.
849
850
  Output:          None.
851
852
  Side Effects:    None.
853
854
  Overview:        This subroutine implements a PID in assembly using the MAC
855
                   instruction of the dsPIC.
856
857
  Note:            None.
858
********************************************************************/
859
860
/*
861
862
                                             ----   Proportional
863
                                            |    |  Output
864
                             ---------------| Kp |-----------------
865
                            |               |    |                 |
866
                            |                ----                  |
867
Reference                   |                                     --- 
868
Speed         ---           |           --------------  Integral | + | Control   -------
869
     --------| + |  Error   |          |      Ki      | Output   |   | Output   |       |
870
             |   |----------|----------| ------------ |----------|+  |----------| Plant |--
871
        -----| - |          |          |  1 - Z^(-1)  |          |   |          |       |  |
872
       |      ---           |           --------------           | + |           -------   |
873
       |                    |                                     ---                      |
874
       | Measured           |         -------------------  Deriv   |                       |
875
       | Speed              |        |                   | Output  |                       |
876
       |                     --------| Kd * (1 - Z^(-1)) |---------                        |
877
       |                             |                   |                                 |
878
       |                              -------------------                                  |
879
       |                                                                                   |
880
       |                                                                                   |
881
        -----------------------------------------------------------------------------------
882
883
   ControlOutput(K) = ControlOutput(K-1) 
884
                    + ControlDifference(K) * (Kp + Ki + Kd)
885
                    + ControlDifference(K-1) * (-Ki - 2*Kd)
886
                    + ControlDifference(K-2) * Kd
887
888
   Using PIDCoefficients:
889
   PIDCoefficients[0] = Kp + Ki + Kd
890
   PIDCoefficients[1] = -(Kp + 2*Kd)
891
   PIDCoefficients[2] = Kd
892
   and leting:
893
   ControlOutput -> ControlOutput(K) and ControlOutput(K-1)
894
   ControlDifference[0] -> ControlDifference(K)
895
   ControlDifference[1] -> ControlDifference(K-1)
896
   ControlDifference[2] -> ControlDifference(K-2)
897
898
   ControlOutput = ControlOutput
899
                 + ControlDifference[0] * PIDCoefficients[0]
900
                 + ControlDifference[1] * PIDCoefficients[1]
901
                 + ControlDifference[2] * PIDCoefficients[2]
902
903
   This was implemented using Assembly with signed fractional and saturation enabled
904
   with MAC instruction
905
*/
906
907
void SpeedControl(void) {
908
        SFRAC16 *ControlDifferencePtr = ControlDifference;
909
        SFRAC16 *PIDCoefficientsPtr = PIDCoefficients;
910
        SFRAC16 x_prefetch;
911
        SFRAC16 y_prefetch;
912
913
    register int reg_a asm("A");
914
    register int reg_b asm("B");
915
916
    CORCONbits.SATA = 1;    // Enable Saturation on Acc A
917
918
  #if __C30_VERSION__ == 320
919
  #error "This Demo is not supported with v3.20"
920
  #endif
921
922
  #if __C30_VERSION__ < 320
923
924
    reg_a = __builtin_lac(RefSpeed,0);
925
    reg_b = __builtin_lac(MeasuredSpeed,0);
926
    reg_a = __builtin_subab();
927
    *ControlDifferencePtr = __builtin_sac(reg_a,0);
928
    reg_a = __builtin_movsac(&ControlDifferencePtr, &x_prefetch, 2,
929
         &PIDCoefficientsPtr, &y_prefetch, 2, 0);
930
    reg_a = __builtin_lac(ControlOutput, 0);
931
    reg_a = __builtin_mac(x_prefetch,y_prefetch,
932
                              &ControlDifferencePtr, &x_prefetch, 2,
933
                              &PIDCoefficientsPtr, &y_prefetch, 2, 0);
934
    reg_a = __builtin_mac(x_prefetch,y_prefetch,
935
                              &ControlDifferencePtr, &x_prefetch, 2,
936
                              &PIDCoefficientsPtr, &y_prefetch, 2, 0);
937
    reg_a = __builtin_mac(x_prefetch,y_prefetch,
938
                              &ControlDifferencePtr, &x_prefetch, 2,
939
                              &PIDCoefficientsPtr, &y_prefetch, 2, 0);
940
        ControlOutput = __builtin_sac(reg_a, 0);
941
942
  #else
943
944
    reg_a = __builtin_lac(RefSpeed,0);
945
    reg_b = __builtin_lac(MeasuredSpeed,0);
946
    reg_a = __builtin_subab(reg_a,reg_b);
947
    *ControlDifferencePtr = __builtin_sac(reg_a,0);
948
    reg_a = __builtin_movsac(&ControlDifferencePtr, &x_prefetch, 2,
949
         &PIDCoefficientsPtr, &y_prefetch, 2, 0, reg_b);
950
    reg_a = __builtin_lac(ControlOutput, 0);
951
952
    reg_a = __builtin_mac(reg_a,x_prefetch,y_prefetch,
953
                              &ControlDifferencePtr, &x_prefetch, 2,
954
                              &PIDCoefficientsPtr, &y_prefetch, 2, 0, reg_b);
955
    reg_a = __builtin_mac(reg_a,x_prefetch,y_prefetch,
956
                              &ControlDifferencePtr, &x_prefetch, 2,
957
                              &PIDCoefficientsPtr, &y_prefetch, 2, 0, reg_b);
958
    reg_a = __builtin_mac(reg_a,x_prefetch,y_prefetch,
959
                              &ControlDifferencePtr, &x_prefetch, 2,
960
                              &PIDCoefficientsPtr, &y_prefetch, 2, 0, reg_b);
961
962
      ControlOutput = __builtin_sac(reg_a, 0);
963
964
  #endif
965
966
        CORCONbits.SATA = 0;    // Disable Saturation on Acc A
967
        // Store last 2 errors
968
        ControlDifference[2] = ControlDifference[1];
969
        ControlDifference[1] = ControlDifference[0];
970
971
        // If CLOSED_LOOP is undefined (running open loop) overide ControlOutput
972
        // with value read from the external potentiometer
973
        #ifndef CLOSED_LOOP
974
                ControlOutput = RefSpeed;
975
        #endif
976
977
        // ControlOutput will determine the motor required direction
978
        if (ControlOutput < 0)
979
                Required_Direction = CCW;
980
        else
981
                Required_Direction = CW;
982
        return;
983
}
984
985
/*********************************************************************
986
  Function:        void ForceCommutation(void)
987
988
  PreCondition:    None.
989
 
990
  Input:           None.
991
992
  Output:          None.
993
994
  Side Effects:    None.
995
996
  Overview:        This function is called each time the motor doesn't 
997
                   generate  hall change interrupt, which means that the motor
998
                   running too slow or is stalled. If it is stalled, the motor
999
                   is stopped, but if it is only slow, this function is called
1000
                   and forces a commutation based on the actual hall sensor 
1001
                   position and the required direction of rotation.
1002
1003
  Note:            None.
1004
********************************************************************/
1005
1006
void ForceCommutation(void)
1007
{
1008
  HallValue = (unsigned int)((PORTB >> 3) & 0x0007);  // Read halls
1009
  Sector = SectorTable[HallValue];  // Read sector based on halls
1010
  if (Sector != -1)  // If the sector is invalid don't do anything
1011
  {
1012
    // Depending on the required direction, a new phase is fetched
1013
    if (Required_Direction == CW)
1014
    {
1015
      // Motor is required to run forward, so read directly the table
1016
      Phase = PhaseValues[Sector];
1017
    }
1018
    else
1019
    {
1020
      // Motor is required to run reverse, so calculate new phase and 
1021
            // add offset to compensate asymmetries
1022
      Phase = PhaseValues[(Sector + 3) % 6] + PhaseOffset;
1023
    }
1024
  }
1025
  return;
1026
}
1027
1028
/*********************************************************************
1029
  Function:        void InitADC10(void)
1030
1031
  PreCondition:    None.
1032
 
1033
  Input:           None.
1034
1035
  Output:          None.
1036
1037
  Side Effects:    None.
1038
1039
  Overview:        Below is the code required to setup the ADC registers for:
1040
                 1. 1 channel conversion (in this case RB2/AN2)
1041
                   2. PWM trigger starts conversion
1042
                   3. Pot is connected to CH0 and RB2/AN2
1043
                   4. The data format will be signed fractional    
1044
1045
  Note:            None.
1046
********************************************************************/
1047
1048
void InitADC10(void)
1049
{
1050
  ADPCFG = 0x0038;        // RB3, RB4, and RB5 are digital            //04.05.2024 vorher 0x2038
1051
    
1052
    
1053
    ADCON3 = 0x0003;
1054
    ADCON2 = 0x0404;
1055
    ADCHS = 0;
1056
    ADCON1 = 0x8066;
1057
    ADCON1 = 0x0266;
1058
    ADCSSL = 0x2004;
1059
    IFS0bits.ADIF = 0;
1060
    IEC0bits.ADIE = 1;        // Enable interrupts
1061
    /*
1062
  ADCON1 = 0x026E;        // PWM starts conversion                                //03.04.2024
1063
                  // Signed fractional conversions
1064
  ADCON2 = 0x000;                           
1065
  ADCHS = 0x0002;          // Pot is connected to AN2
1066
                   
1067
  ADCON3 = 0x0003;         
1068
  IFS0bits.ADIF = 0;        // Clear ISR flag
1069
  IEC0bits.ADIE = 1;        // Enable interrupts
1070
  */
1071
  ADCON1bits.ADON = 1;      // turn ADC ON
1072
  return;
1073
}
1074
1075
/*********************************************************************
1076
  Function:        void InitMCPWM(void)
1077
1078
  PreCondition:    None.
1079
 
1080
  Input:           None.
1081
1082
  Output:          None.
1083
1084
  Side Effects:    None.
1085
1086
  Overview:        InitMCPWM, intializes the PWM as follows:
1087
                   1. FPWM = 20000 hz
1088
                   2. Complementary PWMs with center aligned
1089
                   3. Set Duty Cycle to 0 for complementary, which is half the
1090
                      period
1091
                   4. Set ADC to be triggered by PWM special trigger
1092
                   5. Configure deadtime to be 500 ns  
1093
1094
  Note:            None.
1095
********************************************************************/
1096
1097
void InitMCPWM(void)
1098
{
1099
  TRISE = 0x0100;  // PWM pins as outputs, and FLTA as input
1100
  PTPER = (FCY/FPWM - 1) >> 1;  // Compute Period based on CPU speed and 
1101
                                    // required PWM frequency (see defines)
1102
  OVDCON = 0x0000;  // Disable all PWM outputs.
1103
  DTCON1 = 0x0008;  // ~500 ns of dead time
1104
  PWMCON1 = 0x0077;  // Enable PWM output pins and configure them as 
1105
                        // complementary mode     
1106
  PDC1 = PTPER;      // Initialize as 0 voltage
1107
  PDC2 = PTPER;      // Initialize as 0 voltage
1108
  PDC3 = PTPER;      // Initialize as 0 voltage
1109
  SEVTCMP = 1;      // Enable triggering for ADC
1110
  PWMCON2 = 0x0F02;  // 16 postscale values, for achieving 20 kHz
1111
  PTCON = 0x8002;    // start PWM as center aligned mode
1112
  return;         
1113
}
1114
1115
/*********************************************************************
1116
  Function:        void InitICandCN(void)
1117
1118
  PreCondition:    None.
1119
 
1120
  Input:           None.
1121
1122
  Output:          None.
1123
1124
  Side Effects:    None.
1125
1126
  Overview:        Configure Hall sensor inputs, one change notification and 
1127
                   two input captures. on IC7 the actual capture value is used
1128
                   for further period calculation
1129
1130
  Note:            None.
1131
********************************************************************/
1132
1133
void InitICandCN(void)
1134
{
1135
  //Hall A -> CN5. Hall A is only used for commutation.
1136
  //Hall B -> IC7. Hall B is used for Speed measurement and commutation.
1137
  //Hall C -> IC8. Hall C is only used for commutation.
1138
  
1139
  // Init Input change notification 5
1140
  TRISB |= 0xffff;    // Ensure that hall connections are inputs    7.8.2023 vorher; 0x38 
1141
  CNPU1 = 0;        // Disable all CN pull ups
1142
CNPU1 = 0x00e0; //03.03.2024
1143
  CNEN1 = 0x0020;    // Enable CN5
1144
  IFS0bits.CNIF = 0;  // Clear interrupt flag
1145
1146
  // Init Input Capture 7
1147
  IC7CON = 0x0001;  // Input capture every edge with interrupts and TMR3
1148
  IFS1bits.IC7IF = 0;  // Clear interrupt flag
1149
1150
  // Init Input Capture 8
1151
  IC8CON = 0x0001;  // Input capture every edge with interrupts and TMR3
1152
  IFS1bits.IC8IF = 0;  // Clear interrupt flag
1153
1154
  return;
1155
}
1156
1157
/*********************************************************************
1158
  Function:        void InitTMR1(void)
1159
1160
  PreCondition:    None.
1161
 
1162
  Input:           None.
1163
1164
  Output:          None.
1165
1166
  Side Effects:    None.
1167
1168
  Overview:        Initialization of timer 1 as a periodic interrupt each 1 ms
1169
                   for speed control, motor stalled protection which includes:
1170
                   forced commutation if the motor is too slow, or motor 
1171
                   stopped if the motor is stalled.
1172
1173
  Note:            None.
1174
********************************************************************/
1175
1176
void InitTMR1(void)
1177
{
1178
  T1CON = 0x0020;      // internal Tcy/64 clock
1179
  TMR1 = 0;
1180
  PR1 = 313;        // 1 ms interrupts for 20 MIPS
1181
  T1CONbits.TON = 1;    // turn on timer 1 
1182
  return;
1183
}
1184
1185
/*********************************************************************
1186
  Function:        void InitTMR3(void)
1187
1188
  PreCondition:    None.
1189
 
1190
  Input:           None.
1191
1192
  Output:          None.
1193
1194
  Side Effects:    None.
1195
1196
  Overview:        Initialization of timer 3 as the timebase for the capture 
1197
                   channels for calculating the period of the halls.
1198
1199
  Note:            None.
1200
********************************************************************/
1201
1202
void InitTMR3(void)
1203
{
1204
  T3CON = 0x0020;      // internal Tcy/64 clock
1205
  TMR3 = 0;
1206
  PR3 = 0xFFFF;
1207
  T3CONbits.TON = 1;    // turn on timer 3 
1208
  return;
1209
}
1210
1211
/*********************************************************************
1212
  Function:        void InitUserInt(void)
1213
1214
  PreCondition:    None.
1215
 
1216
  Input:           None.
1217
1218
  Output:          None.
1219
1220
  Side Effects:    None.
1221
1222
  Overview:        Initialization of the IOs used by the application. The IOs 
1223
                   for the PWM and for the ADC are initialized in their 
1224
                   respective peripheral initialization subroutine.
1225
1226
  Note:            None.
1227
********************************************************************/
1228
1229
void InitUserInt(void)
1230
{
1231
  TRISC |= 0x4000;  // S2/RC14 as input
1232
  // Analog pin for POT already initialized in ADC init subroutine
1233
  PORTF = 0x0008;    // RS232 Initial values
1234
  TRISF = 0xFFF7;    // TX as output
1235
  return;
1236
}
1237
1238
// End of SinusoidalBLDC v1.2.c