NEW DATABASE - 350 MILLION DATASHEETS FROM 8500 MANUFACTURERS
AN908 230VAC E3-500-500-IHT AN15/OCFB/CN12 OC5/CN13 OC6/CN14 OC7/CN15 - Datasheet Archive
Using the dsPIC30F for Vector Control of an ACIM Author: Dave Ross, John Theys Diversified Engineering Inc. Co-Author: Steve
AN908 AN908 Using the dsPIC30F for Vector Control of an ACIM Author: Dave Ross, John Theys Diversified Engineering Inc. Co-Author: Steve Bowling Microchip Technology Inc. INTRODUCTION This application note describes a vector control application that is written for the dsPIC30F family of devices. Except for a brief discussion on control theory, the information presented assumes you have a basic understanding of AC induction motor characteristics. References are included in some instances to provide background information. SOFTWARE FEATURES The Vector Control software has the following features: · The software implements vector control of an AC induction motor using the indirect flux control method. · With a 50 µsec control loop period, the software requires approximately 9 MIPS of CPU overhead (less than 1/3 of the total available CPU). · The application requires 258 bytes of data memory storage and 256 bytes of constant storage. With the user interface, approximately 8 Kbytes of program memory are required. · The memory requirements of the application allow it to be run on the dsPIC30F2010, which is the smallest and least expensive dsPIC30F device at the time of this writing. · An optional diagnostics mode can be enabled to allow real-time observation of internal program variables on an oscilloscope. This feature facilitates control loop adjustment. VECTOR CONTROL THEORY Background The AC induction motor (ACIM) is the workhorse of industrial and residential motor applications due to its simple construction and durability. These motors have no brushes to wear out or magnets to add to the cost. The rotor assembly is a simple steel cage. 2004 Microchip Technology Inc. ACIM's are designed to operate at a constant input voltage and frequency, but you can effectively control an ACIM in an open loop variable speed application if the frequency of the motor input voltage is varied. If the motor is not mechanically overloaded, the motor will operate at a speed that is roughly proportional to the input frequency. As you decrease the frequency of the drive voltage, you also need to decrease the amplitude by a proportional amount. Otherwise, the motor will consume excessive current at low input frequencies. This control method is called Volts-Hertz control. In practice, a custom Volts-Hertz profile is developed that ensures the motor operates correctly at any speed setting. This profile can take the form of a look-up table or can be calculated during run time. Often, a slope variable is used in the application that defines a linear relationship between drive frequency and voltage at any operating point. The Volts-Hertz control method can be used in conjunction with speed and current sensors to operate the motor in a closed-loop fashion. The Volts-Hertz method works very well for slowly changing loads such as fans or pumps. But, it is less effective when fast dynamic response is required. In particular, high current transients can occur during rapid speed or torque changes. The high currents are a result of the high slip factor that occurs during the change. Fast dynamic response can be realized without these high currents if both the torque and flux of the motor are controlled in a closed loop manner. This is accomplished using Vector Control techniques. Vector control is also commonly referred to as Field Oriented Control (FOC). The benefits of vector control can be directly realized as lower energy consumption. This provides higher efficiency, lower operating costs and reduces the cost of drive components. Vector Control Traditional control methods, such as the Volts-Hertz control method described above, control the frequency and amplitude of the motor drive voltage. In contrast, vector control methods control the frequency, amplitude and phase of the motor drive voltage. The key to vector control is to generate a 3-phase voltage as a phasor to control the 3-phase stator current as a phasor that controls the rotor flux vector and finally the rotor current phasor. DS00908A-page 1 AN908 AN908 Ultimately, the components of the rotor current need to be controlled. The rotor current cannot be measured because the rotor is a steel cage and there are no direct electrical connections. Since the rotor currents cannot be measured directly, the application program calculates these parameters indirectly using parameters that can be directly measured. VECTOR CONTROL SUMMARY The technique described in this application note is called indirect vector control because there is no direct access to the rotor currents. Indirect vector control of the rotor currents is accomplished using the following data: 2. · Instantaneous stator phase currents, ia, ib and ic · Rotor mechanical velocity · Rotor electrical time constant To summarize the steps required for indirect vector control: 1. 3. The motor must be equipped with sensors to monitor the 3-phase stator currents and a rotor velocity feedback device. A MATTER OF PERSPECTIVE. The key to understanding how vector control works is to form a mental picture of the coordinate reference transformation process. If you picture how an AC motor works, you might imagine the operation from the perspective of the stator. From this perspective, a sinusoidal input current is applied to the stator. This time variant signal causes a rotating magnetic flux to be generated. The speed of the rotor is going to be a function of the rotating flux vector. From a stationary perspective, the stator currents and the rotating flux vector look like AC quantities. Now, instead of the previous perspective, imagine that you could climb inside the motor. Once you are inside the motor, picture yourself running alongside the spinning rotor at the same speed as the rotating flux vector that is generated by the stator currents. Looking at the motor from this perspective during steady state conditions, the stator currents look like constant values, and the rotating flux vector is stationary! Ultimately, you want to control the stator currents to get the desired rotor currents (which cannot be measured directly). With the coordinate transformation, the stator currents can be controlled like DC values using standard control loops. DS00908A-page 2 4. 5. 6. 7. The 3-phase stator currents are measured. This measurement provides ia, ib and ic. The rotor velocity is also measured. The 3-phase currents are converted to a 2-axis system. This conversion provides the variables i and i from the measured ia, ib and ic values. i and i are time varying quadrature current values as viewed from the perspective of the stator. The 2-axis coordinate system is rotated to align with the rotor flux using a transformation angle information calculated at the last iteration of the control loop. This conversion provides the Id and Iq variables from i and i. Id and Iq are the quadrature currents transformed to the rotating coordinate system. For steady state conditions, Id and Iq will be constant. Error signals are formed using Id, Iq and reference values for each. The Id reference controls rotor magnetizing flux. The Iq reference controls the torque output of the motor. The error signals are input to PI controllers. The output of the controllers provide Vd and Vq, which is a voltage vector that will be sent to the motor. A new coordinate transformation angle is calculated. The motor speed, rotor electrical time constant, Id and Iq are the inputs to this calculation. The new angle tells the algorithm where to place the next voltage vector to produce an amount of slip for the present operating conditions. The Vd and Vq output values from the PI controllers are rotated back to the stationary reference frame using the new angle. This calculation provides quadrature voltage values v and v. The v and v values are transformed back to 3-phase values va, vb and vc. The 3-phase voltage values are used to calculate new PWM duty cycle values that generate the desired voltage vector. The entire process of transforming, PI iteration, transforming back and generating PWM is illustrated in Figure 1. 2004 Microchip Technology Inc. AN908 AN908 FIGURE 1: VECTOR CONTROL BLOCK DIAGRAM (Torque Reference) Speed Reference dsPIC MC PWM qref PI (Flux Reference) - dref PI - v d,q Vd , 3-Phase Bridge SVM v PI - Field Weakening Vq Current Model , Speed ia , d,q dsPIC QEI a,b,c ib A Motor B Encoder Coordinate Transforms PARK TRANSFORM Through a series of coordinate transforms the time invariant values of torque and flux can be indirectly determined and controlled with classic PI control loops. The process starts out by measuring the three phase motor currents. In practice you can take advantage of the constraint that in a three-phase system the instantaneous sum of the three current values will be zero. Thus by measuring only two of the three currents you can know the third. The cost of the hardware is reduced because only two current sensors are required. At this point you have the stator current Phasor represented on a 2-axis orthogonal system with the axis called -. The next step is to transform into another 2-axis system that is rotating with the rotor flux. This transformation uses the Park Transform, as illustrated in Figure 3. This 2-axis rotating coordinate system is called the d-q axis. The first transform is to move from a 3-axis, 2-dimensional coordinate system referenced to the stator of the motor to a 2-axis system also referenced to the stator. The process is called the Clarke Transform, as illustrated in Figure 2. a b (c) Clarke PARK TRANSFORM q CLARK TRANSFORM FIGURE 2: FIGURE 3: i i Iq Park Id Id = i cos + i sin i = -i cos + i sin d i Iq Id is i CLARK TRANSFORM From this perspective the components of the current Phasor in the d-q coordinate system are time invariant. Under steady state conditions they are DC values. b i ia + ib + ic = 0 i = ia i = ia + 2ib 3 is i c 2004 Microchip Technology Inc. a, The stator current component along the d axis is proportional to the flux, and the component along the q axis is proportional to the rotor torque. Now that you have these components represented as DC values you can control them independently with classic PI control loops. DS00908A-page 3 AN908 AN908 INVERSE PARK After the PI iteration you have two voltage component vectors in the rotating d-q axis. You will need to go through complementary inverse transforms to get back to the 3-phase motor voltage. First you transform from the 2-axis rotating d-q frame to the 2-axis stationary frame -. This transformation uses the Inverse Park Transform, as illustrated in Figure 4. FIGURE 4: Vd v Vq Inverse v Park d EQUATION 2: Vd vs v = Vd cos - Vq sin v = Vd sin + Vq cos v INVERSE CLARKE va = v v + 3 v vb = 2 v + 3 v vc = 2 v = + b fs T where: fs = flux speed (as calculated from measured values) T = sample (loop) time (parameter in program) vs v va n In an asynchronous squirrel cage induction motor the mechanical speed of the rotor is slightly less than the rotating flux field. The difference in angular speed is called slip and is represented as a fraction of the rotating flux speed. For example if the rotor speed and the flux speed are the same the slip is 0 and if the rotor speed is 0 the slip is 1. You probably have noticed that the Park and Inverse Transforms require an input angle . The variable represents the angular position of the rotor flux vector. The correct angular position of the rotor flux vector must be estimated based on known values and motor parameters. This estimation uses a motor equivalent = rotor speed (measured with the shaft encoder) Tr = Lr/Rr = Rotor time constant (must be obtained from the motor manufacturer) vc Flux Estimator DS00908A-page 4 FLUX ANGLE Imr = magnetizing current (as calculated from measured values) INVERSE CLARKE vb FLUX SPEED I 1 - qf s = ( P pr n ) + - - T r b I mr EQUATION 3: The next step is to transform from the stationary 2-axis - frame to the stationary 3-axis, 3-phase reference frame of the stator. Mathematically, this transformation is accomplished with the Inverse Clark Transform, as illustrated in Figure 5. vr1 Inverse vr2 Clarke vr3 MAGNETIZING CURRENT T I mr = I mr + - ( I d I mr ) Tr v Vq v v The flux estimator calculates a new flux position based on stator currents, the rotor velocity and the rotor electrical time constant. This implementation of the flux estimation is based on the motor current model and in particular these three equations: EQUATION 1: INVERSE PARK q FIGURE 5: circuit model. The slip required to operate the motor is accounted for in the flux estimator equations and is included in the calculated angle. = rotor flux position (output variable from this module) b = electrical nominal flux speed (from motor name plate) Ppr = number of pole pairs (from motor name plate) During steady state conditions, the Id current component is responsible for generating the rotor flux. For transient changes, there is a low-pass filtered relationship between the measured Id current component and the rotor flux. The magnetizing current, Imr, is the component of Id that is responsible for producing the rotor flux. Under steady-state conditions, Id is equal to Imr. Equation 1 relates Id and Imr. This equation is dependent upon accurate knowledge of the rotor electrical time constant. Essentially, Equation 1 corrects the flux producing component of Id during transient changes. 2004 Microchip Technology Inc. AN908 AN908 The computed Imr value is then used to compute the slip frequency, as shown in Equation 2. The slip frequency is a function of the rotor electrical time constant, Iq, Imr and the current rotor velocity. Equation 3 is the final equation of the flux estimator. It calculates the new flux angle based on the slip frequency calculated in Equation 2 and the previously calculated flux angle. If the slip frequency and stator currents have been related by Equation 1 and Equation 2, then motor flux and torque have been specified. Furthermore, these two equations ensure that the stator currents are properly oriented to the rotor flux. If proper orientation of the stator currents and rotor flux is maintained, then flux and torque can be controlled independently. The Id current component controls rotor flux and the Iq current component controls motor torque. This is the key principle of indirect vector control. PI Control Three PI loops are used to control three interactive variables independently. The rotor speed, rotor flux and rotor torque are each controlled by a separate PI module. The implementation is conventional and includes a term (Kc*Excess) to limit integral windup, as illustrated in Figure 6. FIGURE 6: InRef PI CONTROL Kperr + Kierr dt Out FB Err = InRef - FB; U = Sum + Kp*Err; If (U > Outmax); Out = Outmax; else if (U < Outmin) Out = Outmin; else Out = U; Excess = U - Out; Sum = Sum + (Ki*Err)-(Kc*Excess); PID CONTROLLER BACKGROUND A complete discussion of Proportional Integral Derivative (PID) controllers is beyond the scope of this application note, but this section will provide you with the basics of PID operation. A PID controller responds to an error signal in a closed control loop and attempts to adjust the controlled quantity to achieve the desired system response. The controlled parameter can be any measurable system quantity such as speed, torque, or flux. The benefit of the PID controller is that it can be adjusted empirically by adjusting one or more gain values and observing the change in system response. A digital PID controller is executed at a periodic sampling interval. It is assumed that the controller is executed frequently enough so that the system can be properly controlled. The error signal is formed by subtracting the desired setting of the parameter to be controlled from the actual measured value of that parameter. The sign of the error indicates the direction of change required by the control input. The Proportional (P) term of the controller is formed by multiplying the error signal by a P gain, causing the PID controller to produce a control response that is a function of the error magnitude. As the error signal becomes larger, the P term of the controller becomes larger to provide more correction. The effect of the P term tends to reduce the overall error as time elapses. However, the effect of the P term reduces as the error approaches zero. In most systems, the error of the controlled parameter gets very close to zero but does not converge. The result is a small remaining steady state error. The Integral (I) term of the controller is used to eliminate small steady state errors. The I term calculates a continuous running total of the error signal. Therefore, a small steady state error accumulates into a large error value over time. This accumulated error signal is multiplied by an I gain factor and becomes the I output term of the PID controller. The Differential (D) term of the PID controller is used to enhance the speed of the controller and responds to the rate of change of the error signal. The D term input is calculated by subtracting the present error value from a prior value. This delta error value is multiplied by a D gain factor that becomes the D output term of the PID controller. The D term of the controller produces more control output the faster the system error is changing. Not all PID controllers will implement the D or, less commonly, the I terms. For example, this application does not use D terms due to the relatively slow response time of motor speed changes. In this case, the D term could cause excessive changes in PWM duty cycle that could affect the operation of the algorithms and produce over current trips. 2004 Microchip Technology Inc. DS00908A-page 5 AN908 AN908 Space Vector Modulation The process of Space Vector Modulation allows the representation of any resultant vector by the sum of the components of the two adjacent vectors. In Figure 8, UOUT is the desired resultant. It lies in the sector between U60 and U0. If during a given PWM period T U0 is output for T1/T and U60 is output for T2/T, the average for the period will be UOUT. The final step in the vector control process is to generate pulse-width-modulation signals for the 3-phase motor voltage signals. By using Space Vector Modulation (SVM) techniques the process of generating the pulse width for each of the 3 phases reduces to a few simple equations. In this implementation the Inverse Clarke Transform has been folded into the SVM routine, which further simplifies the calculations. FIGURE 8: Each of the three inverter outputs can be in one of two states. The inverter output can be either connected to the + bus rail or the bus rail, which allows for 23=8 possible states that the output can be in (see Table 1). U60(011) T = T1 + T2 + T0 = PWM Period The two states where all three outputs are connected to either the + bus or the bus are considered null states because there is no line-to-line voltage across any of the phases. These are plotted at the origin of the SVM Star. The remaining six states are represented as vectors with 60 degree rotation between each state, as shown in Figure 7. FIGURE 7: U(111) U180(110) U240(100) TABLE 1: T2/T * U60 T1/T * U0 U0(001) The values for T1 and T2 can be extracted with no extra calculations by using a modified Inverse Clark transformation. By reversing v and v, a reference axis is generated that is shifted by 30 degrees from the SVM star. As a result, for each of the six segments one axis is exactly opposite that segment and the other two axis symmetrically bound the segment. The values of the vector components along those two bounding axis are equal to T1 and T2. See the CalcRef.s and SVGen.s files in "Appendix B. Source Code" for details of the calculations. U60(011) U(000) UOUT UOUT = T1 * U0 + T2 * U60 T SPACE VECTOR MODULATION U120(010) AVERAGE SPACE VECTOR MODULATION U0(001) You can see from Figure 9 that for the PWM period T, the vector T1 is output for T1/T and the vector T2 is output for T2/T. During the remaining time the null vectors are output. The dsPIC® device is configured for center aligned PWM, which forces symmetry about the center of the period. This configuration produces two pulses line-to-line during each period. The effective switching frequency is doubled, reducing the ripple current while not increasing the switching losses in the power devices. U300(101) SPACE VECTOR MODULATION INVERTER STATES C B A Vab Vbc Vca Vds Vqs Vector 0 0 0 0 0 0 0 0 U(000) 0 0 1 VDC 0 -VDC 2/3VDC 0 U0 0 1 1 0 VDC -VDC VDC/3 VDC/3 U60 0 1 0 -VDC VDC 0 -VDC/3 VDC/3 U120 1 1 0 -VDC 0 VDC -2VDC/3 0 U180 1 0 0 0 -VDC VDC -VDC/3 - VDC/3 U240 1 0 1 VDC -VDC 0 VDC/3 - VDC/3 U300 1 1 1 0 0 0 0 0 U(111) DS00908A-page 6 2004 Microchip Technology Inc. AN908 AN908 FIGURE 9: PWM FOR PERIOD T 000 100 110 111 111 110 100 T0/4 T1/2 T2/2 T0/4 T0/4 T2/2 T1/2 000 PWM1 PWM2 PWM3 T0/4 T CODE DESCRIPTION Variable Definition and Scaling The vector control source code was developed in MPLAB® using the Microchip MPLAB C30 tool suite. The main application is written in C and all the primary vector control functions are written in assembly and optimized for speed of execution. Most variables are stored in 1.15 fractional format, which is one of the inherent math modes in the dsPIC devices. A signed fixed-point integer is represented as follows: Conventions A description of the functions is contained in the header of each source file. The equivalent C code for the function is also included in the header for reference. The C lines of code are used as comments in the optimized assembly code so that code flow can easily be followed. At the beginning of each function the pertinent variables are moved to specific working (W) registers that are used by the DSP and math instructions. The variables are moved back to their respective register locations at the end of the code function. Most of these variables are grouped into structures of related parameters to provide efficient access from the C or assembly code. · · · · · MSB is the sign bit range -1 to +.9999 0x8000 = -1 0000 = 0 0x7FFF = .9999 All values are normalized using the Per Unit system (PU). VPU = VACT/VB Then scaled so that the base quantity = .125 This allows for values of 8 times the base value. VB = 230V, VACT =120V, VPU = 120/230 =.5PU, Scaling VB = .125 = 0x0FFF (1.15) 120V = .5 * .125 = 0x07FF (1.15) Each W register used in an assembly module has been assigned a descriptive name that tells what value the register holds during the calculation. The re-naming of the W registers makes the code easier to follow and avoids register usage conflicts. 2004 Microchip Technology Inc. DS00908A-page 7 AN908 AN908 Individual Source File Descriptions CalcRef.s This section describes the functions contained in each source file. This file contains the CalcRefVec() function, which calculates the scaled 3-phase voltage output vector, (Vr1, Vr2, Vr3), from v and v. The function implements the inverse Clarke function, which translates the voltage vector components from a 2-coordinate system back to a 3-coordinate system that can be used by the 3-phase PWM. The method is a modified inverse Clarke transform where v and v are swapped compared to the normal Inverse Clarke. The modified method must be used to produce the proper phase alignment of the voltage vector. Note: If you are viewing an electronic version of this application note, you can click on the following file names to navigate to the code in "Appendix B. Source Code". UserParms.h All user definable parameters are located in the UserParms.h file. These parameters include motor data and control loop tuning values. More information on the parameters is provided in the Software Tuning section of this document. ACIM.c The ACIM.c file is the primary source code file for the application. This file contains the main software loop and all ISR handlers. This file calls all hardware and variable initialization routines. To accomplish high performance closed loop control the entire vector control loop must be executed every PWM cycle. This is done in the ISR for the ADC converter. The PWM timebase is used to trigger ADC conversions. When the ADC conversion is complete, an interrupt is generated. When not in the ISR, a main software loop is run that handles the user interface. A software count variable is maintained in the ISR so that the user interface is run at periodic intervals. As written, the user interface code is scheduled to run every 50 milliseconds. This parameter can be changed by modifying the UserParms.h file. A software diagnostics mode can be enabled by uncommenting the #define DIAGNOSTICS statement in the UserParms.h file. The diagnostics mode enables output compare channels OC7 and OC8 as PWM outputs. These outputs can be filtered using simple RC filters and used like a D/A converter to observe the time history of software variables. The diagnostics output simplifies tuning of the PI control loops. More information on the diagnostics output is provided in the Software Tuning section of this document. CalcVel.s This file has three functions, InitCalcVel(), CalcVelIrp() and CalcVel(), which are used to determine the motor velocity. The InitCalcVel() function initializes key variables associated with the velocity calculations. The CalcVelIrp() function is called at each vector control interrupt period. The interrupt interval, VelPeriod, MUST be less than the minimum time required for 1/2 revolution at maximum speed. This routine accumulates the change for a specified number of interrupt periods, then copies the accumulation value to the iDeltaCnt variable for use by the CalcVel() routine to calculate velocity. The accumulation is set back to zero and a new accumulation starts. The CalcVel() routine is only called when new velocity information is available. For the default software values, the CalcVel() routine is called every 30 interrupt periods. This interval gives new velocity information every 1.5msec for a 50usec interrupt period. The velocity control loop is run each time new velocity information is obtained. ClarkePark.s This file contains the function ClarkePark() and calculates Clarke and Park transforms. The function uses the sine and cosine values of the flux position angle to calculate the quadrature current values of Id and Iq. This routine works the same for both integer scaling and 1.15 scaling. InitCurModel.c CurModel.s This file contains the InitCurModScaling() function, which is called from the setup routines in the ACIM.c file. This function is used to calculated fixedpoint scaling factors that are used in the current model equations from floating point values. The current model scaling factors are a function of the rotor time constant, vector calculation loop period, number of motor poles and the maximum motor velocity in revolutions per second. This file contains the CurModel() and InitCurModel() functions. The CurModel() function executes the rotor current model equation to determine a new rotor flux angle as a function of the rotor velocity and the transformed stator current components. The InitCurModel() function is used to clear variables associated with the CurModel() routine. DS00908A-page 8 2004 Microchip Technology Inc. AN908 AN908 FIGURE 10: VECTOR CONTROL INTERRUPT SERVICE ROUTINE void _attribute_(_interrupt_) _ADCInterrupt(void) { IFS0bits.ADIF = 0; // Increment count variable that controls execution // of display and button functions. iDispLoopCnt+; // acumulate encoder counts since last interrupt CalcVelIrp(); if( uGF.bit.RunMotor ) { // Set LED1 for diagnostics pinLED1 = 1; // Calculate velocity from accumulated encoder counts CalcVel(); // Calculate qIa,qIb MeasCompCurr(); // Calculate qId,qIq from qSin,qCos,qIa,qIb ClarkePark(); // Calculate PI control loop values DoControl(); // Calculate qSin,qCos from qAngle SinCos(); // Calculate qValpha, qVbeta from qSin,qCos,qVd,qVq InvPark(); // Calculate Vr1,Vr2,Vr3 from qValpha, qVbeta CalcRefVec(); // Calculate and set PWM duty cycles from Vr1,Vr2,Vr3 CalcSVGen(); // Clear LED1 for diagnostics pinLED1 = 0; } } 2004 Microchip Technology Inc. DS00908A-page 9 AN908 AN908 FdWeak.s InvPark.s The FdWeak.s file contains the function for field weakening. The application code, as provided, does not implement field weakening. Field weakening allows a motor to be run at higher than the rated speed. At these higher speeds, the voltage delivered to the motor is kept constant while the frequency is increased. This file contains the InvPark() function, which processes the voltage vector values, Vd and Vq, which are generated by the inner PI current control loops. The InvPark() function `un-rotates' the voltage vector values to align them with the stationary reference frame. The function produces the v and v values. The rotation is accomplished using sine and cosine values of the new rotor flux angle that was previously calculated in the rotor current model equations. A field weakening constant is defined in the UserParms.h file. This value is derived from the V/Hz constant of the motor. The motor that was used to develop this application has a working voltage of 230VAC 230VAC and is designed for an input frequency of 60Hz. Based on these values, the V/Hz constant is 230/60 = 3.83. The value of 3750 defined for the field weakening constant in UserParms.h was empirically derived based on the V/Hz constant of the motor and the absolute scaling of A/D feedback values for the application. When the motor operates within its rated speed and voltage range, the reference for the Id control loop is held constant. The field weakening constant in UserParms.h is used as the reference value for the control loop. In the normal operating range of the motor, the rotor flux is kept constant. If field weakening is implemented, the Id control loop reference should be reduced linearly when the motor is said to `run out of voltage'. The motor `runs out of voltage' when the V/Hz ratio for the motor can not be maintained. For example, assume that you are driving a 230 VAC motor with a 115 VAC power source. Since the motor is designed to run at 230 VAC and 60 Hz, the motor would `run out of voltage' at 30 Hz when operating from a 115 VAC supply. Above 30 Hz, the Id control loop reference should be linearly reduced as a function of frequency. You can determine the drive frequency where your ACIM application will run out of voltage by monitoring the inverter DC bus voltage. When operating in a region where field weakening would be required, the Id and Iq control loops will saturate, which effectively limits the motor flux. The use of field weakening allows the vector control algorithm to limit its output without saturating the control loops. This is one of the key benefits of field weakening. The operating range of the motor can be extended while closed loop control is maintained. You can experiment with field weakening in this application by changing the defined reference value in UserParms.h. By lowering this value, you can limit the available voltage that can be delivered to the motor. This routine works the same for both integer scaling and 1.15 scaling. MeasCur.s This file has two functions, MeasCompCurr() and InitMeasCompCurr(). The MeasCompCurr() function reads S/H channels CH1 and CH2 of the ADC, scales them as signed fractional values using qKa, qKb and put the results qIa and qIb of ParkParm. A running average of the A/D offset is maintained and is subtracted from the ADC value before scaling. The InitMeasCompCurr() function is used to initialize the A/D offset values at startup. Scaling and offset variables associated with these functions are kept in the MeasCurrParm data structure, which is declared in the MeasCurr.h file. OpenLoop.s This file contains the OpenLoop() function that calculates a new rotor flux angle when the application is running open loop. The function calculates the change in rotor flux angle for the desired operating speed. The change in rotor flux angle is then added to the old angle to set the new angle of the voltage vector. PI.s This file contains the CalcPI() function, which executes a PI controller. The CalcPI() function accepts a pointer to a structure that contains the PI coefficients, input and reference signals, output limits and the PI controller output value. ReadADC0.s This file contains the ReadADC0() and ReadSignedADC0() functions. These functions read the data obtained from sample/hold Channel 0 of the ADC, scale the value and store the results. The ReadSignedADC0() function is currently used to read a reference speed value from the potentiometer on the demo board. If speed is obtained from another source, these functions are not required for the application. SVGen.s This file has the CalcSVGen() function, which calculates the final PWM values as a function of the 3-phase voltage vector. DS00908A-page 10 2004 Microchip Technology Inc. AN908 AN908 Trig.s FIGURE 11: HARDWARE SETUP USING dsPICDEM MOTOR CONTROL DEVELOPMENT SYSTEM FIGURE 12: LEESON MOTOR WITH MOUNTED INCREMENTAL ENCODER This file contains the SinCos() function, which calculates sine and cosine for a specified angle using linear interpolation on a table of 128 words. To save data memory space, the 128-word sine wave table is placed in program memory and accessed using the program space visibility (PSV) feature of the dsPIC architecture. PSV allows a portion of program memory to be mapped into data memory space so that constant data can be accessed as if it were in RAM. This routine works the same for both integer scaling and 1.15 scaling. For integer scaling the angle is scaled such that 0 angle < 2 corresponds to 0 angle < 0xFFFF. The resulting Sine and Cosine values are returned, scaled to -32769 to +32767 (i.e., 0x8000 to 0x7FFF). For 1.15 scaling, the angle is scaled such that - angle < corresponds to -1 to +0.9999 (i.e., 0x8000 angle < 0x7FFF). The resulting sine and cosine values are returned scaled to -1 to +0.9999 (i.e., 0x8000 to 0x7FFF). DEMO HARDWARE The vector control application can be run on the dsPICDEMTM MC1 Motor Control Development System. You will need the following hardware: · Microchip dsPICDEM MC1 Motor Control Development Board · 9 VDC power supply · Microchip dsPICDEM MC1H 3-Phase High Voltage Power Module · Power supply cable for the power module · 3-Phase AC induction motor with shaft encoder Note: An encoder of at least 250 lines per revolution should be used. The upper limit would be 32,768 lines per revolution. Recommended Motor and Encoder The following motor and encoder combination was used to develop this application and select the software tuning parameters: · Leeson Cat# 102684 motor, 1/3 HP, 3450 RPM · U.S. Digital encoder, model E3-500-500-IHT E3-500-500-IHT The Leeson motor can be obtained from Microchip or an electric motor distributor. The encoder can be ordered from the U.S. Digital web site, www.usdigital.com. This model of encoder is shipped with a mounting alignment kit and a self-sticking encoder body. The encoder can be mounted directly on the front face of the motor, as shown in Figure 12. Any other similar encoder with 500 lines of resolution may be used instead of the U.S. Digital device, if desired. 2004 Microchip Technology Inc. If You Select Another Motor. If another motor is selected, you will likely have to experiment with the control loop tuning parameters to get good response from the control algorithm. At a minimum, you will need to determine the rotor electrical time constant in seconds. This information can be obtained from the motor manufacturer. The application will run without the proper rotor time constant, but the response of the system to transient changes will not be ideal. If the above referenced Leeson motor and a 500-line encoder are used, no adjustment of software tuning parameters should be necessary to get the demo running properly. DS00908A-page 11 AN908 AN908 Phase Current Feedback The vector control application requires knowledge of the 3-phase motor currents. This application is designed to use the isolated hall-effect current transducers found on the dsPICDEM MC1H power module. These transducers are active devices that provide a 200-KHz bandwidth, 0-5 volt feedback signal. The halleffect devices have been used in this application for convenience and safety reasons. The signal from these devices can be connected directly to the dsPIC A/D converter. For your end application, you can choose to measure currents using shunt resistors installed in each leg of the 3-phase inverter. The shunt resistors offer a less expensive solution for current measurement. Motor Wiring Configuration Most 3-phase ACIM's, including the Leeson motor, can be wired for 208V or 460V operation. If you are using the dsPICDEM MC1 system to drive your motor, you should wire the motor for 208V operation. The vector control application does not regulate the DC bus voltage. However, a 208V motor will operate correctly from a 120V source with limited speed and torque output. Jumper Placement All jumpers on the 3-Phase High Voltage Power Module can be left at the default settings. If you have removed the cover of the power module to make modifications, please refer to the power module user's guide for the default jumper configuration. The following jumper configuration should be used for the motor control development board. · Switch S2 (located next to the ICD connector) should be set to the `Analog' position when running the demo code to connect the phase current feedback to the dsPIC analog input pins. (S2 should be placed in the `ICD' position for device programming). · All other jumpers should be left in their default placements. External Connections · Plug the Motor Control Development Board directly into the 37pin connector on the Power Module. · Make sure a dsPIC30F6010 device is installed on the development board · Connect the motor leads to the output of the Power Module in the terminals labeled R,Y,B. Connect phase 1 to `R', phase 2 to `Y' and phase 3 to `B'. · Connect the encoder leads to the QEI terminal block on the MCDB. Match up the pin names screened on the MCDB with the signal names on the encoder. Finally connect the 9V power supply to J2 on the MCDB. Port Usage Table 2 indicates how the dsPIC device ports are used in this application. This information is provided to help you develop your hardware definition. The I/O pins that are required for the vector control application are shown in bold text. The application uses other pins, such as LCD interface lines, that are not required for the motor control function. These I/O connections may or may not be used in your final design. · The isolated hall-effect current sensors are used to measure the motor phase currents. Ensure LK1 and LK2 (next to the 5V regulator) are placed on pins 1 and 2. . DS00908A-page 12 2004 Microchip Technology Inc. AN908 AN908 TABLE 2: dsPIC DEVICE PORT USAGE SUMMARY Pin Functions Type Application Usage PORTA RA9 VREF- O LED1, D6 (Active high) RA10 VREF+ O LED2, D7 (Active high) RA14 INT3 O LED3, D8 (Active high) RA15 INT4 O LED4, D9 (Active high) PGD/EMUD/AN0/CN2 AI Phase1 Current/Device Programming Pin RB1 PGC/EMUC/AN1/CN3 AI Phase2 Current/Device Programming Pin RB2 AN2/SS1/LVDIN/CN4 AI not used in application PORTB RB0 RB3 AN3/INDX/CN5 I QEI Index RB4 AN4/QEA/CN6 I QEI A I QEI B RB5 AN5/QEB/CN7 RB6 AN6/OCFA AI not used in application RB7 AN7 AI Pot (VR1) RB8 AN8 AI not used in application RB9 AN9 AI not used in application RB10 AN10 AI not used in application RB11 AN11 AI not used in application RB12 AN12 AI not used in application RB13 AN13 AI not used in application RB14 AN14 AI not used in application RB15 AN15/OCFB/CN12 AN15/OCFB/CN12 O not used in application PORTC RC1 T2CK O LCD R/W RC3 T4CK O LCD RS RC13 EMUD1/SOSC2/CN1 Alternate ICD2 Communication Pin RC14 EMUC1/SOSC1/T1CK/CN0 Alternate ICD2 Communication Pin RC15 OSC2/CLKO Port D RD0 EMUC2/OC1 I/O LCD D0 RD1 EMUD2/OC2 I/O LCD D1 RD2 OC3 I/O LCD D2 RD3 OC4 I/O LCD D3 RD4 OC5/CN13 OC5/CN13 O not used in application RD5 OC6/CN14 OC6/CN14 O not used in application RD6 OC7/CN15 OC7/CN15 O PWM for diagnostics output RD7 OC8/CN16/UPDN OC8/CN16/UPDN O PWM for diagnostics output RD8 IC1 I not used in application RD9 IC2 I not used in application RD10 IC3 I not used in application RD11 IC4 O Demo board PWM output buffer enable (Active low) O LCD E RD12 IC5 RD13 IC6/CN19 IC6/CN19 RD14 IC7/CN20 IC7/CN20 2004 Microchip Technology Inc. not used in application not used in application DS00908A-page 13 AN908 AN908 TABLE 2: dsPIC DEVICE PORT USAGE SUMMARY (CONTINUED) Pin RD15 Functions Type IC8/CN21 IC8/CN21 Application Usage not used in application PORTE RE0 PWM1L O Phase1 L RE1 PWM1H O Phase1 H RE2 PWM2L O Phase2 L RE3 PWM2H O Phase2 H RE4 PWM3L O Phase3 L RE5 PWM3H O Phase3 H RE6 PWM4L O not used in application RE7 PWM4H O not used in application RE8 FLTA/INT1 I Power Module Fault Signal (active low) RE9 FLTB/INT2 O Power Module Fault Reset (Active high) Port F RF0 C1RX I not used in application RF1 C1TX O not used in application RF2 U1RX I not used in application RF3 U1TX O not used in application RF4 U2RX/CN17 U2RX/CN17 I not used in application RF5 U2TX/CN18 U2TX/CN18 O not used in application RF6 EMUC3/SCK1/INT0 I not used in application RF7 SDI1 I not used in application RF8 EMUD3/SDO1 O not used in application Port G RG0 C2RX O not used in application RG1 C2TX O not used in application RG2 SCL I/O not used in application RG3 SDA I/O not used in application RG6 SCK2/CN8 I Button 1 (S4) (Active low) RG7 SDI2/CN9 I Button 2 (S5) (Active low) RG8 SDO2/CN10 SDO2/CN10 I Button 3 (S6) (Active low) RG9 SS2/CN11 SS2/CN11 I Button 4 (S7) (Active low) DS00908A-page 14 2004 Microchip Technology Inc. AN908 AN908 PROJECT SETUP AND DEVICE PROGRAMMING SOFTWARE OPERATION It is recommended that you use MPLAB IDE v6.50, or later, to create a project and program the device. To program the source code onto the dsPIC device, you have two options: 1. 2. You can import the pre-compiled hex file supplied with the application source code into MPLAB IDE and program the device, or You can create a new project in MPLAB IDE, compile the source code and program the device. As provided, the demo program has basic features that allow you to evaluate the performance of the system in response to a 2:1 step change in requested speed. Two modes of control are provided that allow full closed loop operation or operation in a conventional open loop constant Volts/Hertz mode. The operational modes are controlled by four push buttons. The speed command reference is obtained from potentiometer VR2, which is a bidirectional control where zero speed is in the center of the potentiometer. Importing the HEX File Buttons If you don't have the MPLAB C30 compiler installed, you won't be able to compile the application. In this case, just use the supplied hex file. You will need to use the same hardware setup described in the `Demo Hardware" section of this document. BUTTON 1 (S4) Setting Up a New Project BUTTON 2 (S5) The MPLAB C30 v. 1.20 compiler was used to build the application source code. To compile the source code, add all of the assembly files (.s extension) and C files to a new project. Include a device linker script in your project files. Assuming the C30 compiler was installed to the default location, use linker script file p30f6010.gld (this file is located in the c:\pic30_tools\support\gld directory). Also, set the assembler and C compiler include path for the build options. These paths are c:\pic30_tools\support\inc c:\pic30_tools\support\h. Pressing Button 1 toggles the active state of the system. If it is off it will run, and if it is running it will stop. This button can also be used to clear any hardware faults by restarting the motor. and Device Frequency The supplied source code is set up to use a 7.37-MHz crystal and the 8X PLL option on the device oscillator, providing a device operating speed of 14.76 MIPS. If you have a different crystal value installed, you may need to change some of the values in the UserParms.h file. Refer to the `Software Tuning" section of this document for more information on the adjustment of values in UserParms.h. Also, you will need to modify the config.s file if a different oscillator option is to be used. Button 2 toggles the system between open-loop and closed-loop mode. By default, the system starts in open-loop mode BUTTON 3 (S6) Button 3 toggles the commanded speed by a factor of 2. It powers up in the half speed mode. BUTTON 4 (S7) Button 4 does not have any function in the demo code, but the button processing code is provided so you can add your own functions. LEDs LED 1 (D6) LED 1 is on when the system is running. This signal is modulated by the interrupt routine. The length of the interrupt service routine can be measured by looking at the time this signal is high. LED 2 (D7) On when system is in closed loop mode. LED 3 (D8) On when speed is at full value, off when speed is at half value. LED 4 (D9) Not used in the application. 2004 Microchip Technology Inc. DS00908A-page 15 AN908 AN908 FDW/REV (D5) The RD7 port pin that is connected to D5 is used as an output compare channel (OC8) for the diagnostics function. Therefore, D5 activity does not have any meaning in the application. If the diagnostics output is not used, D5 can be driven directly from the quadrature encoder interface (QEI) on the dsPIC device. There is a control bit in the QEICON register that enables RD7 as a direction status output pin. With this feature enabled, D5 will be lit for the forward direction of travel. LCD The LCD is the primary means of user feedback. When the program is in the standby mode, the display prompts the user to push S4 to start the motor. When the program is running, the RPM is displayed. The LCD is updated in the main loop, and other display parameters can easily be added. Troubleshooting The motor will not run in open-loop mode: · Check power module fault lights. Reset the dsPIC device if necessary to clear faults. · Check to make sure power module has power. Check bus voltage LED inside module. The motor runs in open-loop mode, but will not run closed loop. · · · · Ensure S2 is in `Analog' position. Make sure LK1 and LK2 are configured properly. Check encoder wiring connections. There may be a reversal of encoder signals with respect to motor wiring and direction of rotation. If this is suspected, reverse the A and B signals on the encoder wiring connections. The encoder wiring will also depend on whether the encoder is mounted on the front or rear of the motor. DS00908A-page 16 SOFTWARE TUNING Diagnostics Mode A diagnostics mode is available that allows you to use spare output compare (OC) channels OC7 and OC8 to observe internal program variables. These channels are used as PWM outputs for diagnostics. These PWM outputs can then be filtered using simple RC filter networks and used like simple DAC outputs to show the time history of internal variables on an oscilloscope. The OC7 and OC8 channels are available on pins RD6 and RD7 of the dsPIC30F6010 device. These two pins are accessible on header J7 of the dsPICDEM MC1 Motor Control Development Board. ENABLING DIAGNOSTICS MODE To enable the diagnostics output, simply uncomment the #define DIAGNOSTICS statement in the UserParms.h file and re-compile the application. HARDWARE SETUP FOR DIAGNOSTICS You will need to add two RC low-pass filter networks to your development board to use the diagnostics. The RC filters should be connected to device pins RD6 and RD7. A 10 kohm resistor and a 1uF capacitor will work well for most situations. If you don't have the exact values, anything close to these values should work fine. FIGURE 13: OC7 or OC8 DIAGNOSTICS CIRCUIT 10K Test Point 1 µF 2004 Microchip Technology Inc. AN908 AN908 Adjusting the PID Gains The P gain of a PID controller sets the overall system response. When first tuning a controller, the I and D gains should be set to zero. The P gain can then be increased until the system responds well to set-point changes without excessive overshoot or oscillations. Using lower values of P gain will `loosely' control the system, while higher values will give `tighter' control. At this point, the system will probably not converge to the set-point. After a reasonable P gain is selected, the I gain can be slowly increased to force the system error to zero. Only a small amount of I gain is required in most systems. Note that the effect of the I gain, if large enough, can overcome the action of the P term, slow the overall control response and cause the system to oscillate around the set-point. If oscillation occurs, reducing the I gain and increasing the P gain will usually solve the problem. This application includes a term to limit integral windup, which will occur if the integrated error saturates the output parameter. Any further increase in the integrated error will not effect the output. If allowed to accumulate, when the error does decrease the accumulated error will have to reduce (or unwind) to below the value that caused the output to saturate. The Kc coefficient limits this unwanted accumulation. For most situations, it can be set equal to Ki. All three controllers have a maximum value for the output parameter. These values can be found in the UserParms.h file and are currently set to avoid saturation in the SVGen() routine. RECOMMENDED CONTROL LOOP TUNING PROCEDURE If the control loops require adjustment, it is helpful to bypass the velocity control loop as described above. In most situations, the PI coefficients for the Id and Iq control loops should be set to equal values. Once the motor has good torque response in the torque mode, the velocity control loop can be enabled and adjusted. Example Scope Plots The following scope plots demonstrate the use of the diagnostic outputs and proper tuning of the application parameters. A plot of the transformed quadrature phase current (Iq) vs. the motor mechanical velocity is shown in Figure 14. Assuming the application is properly tuned, the Iq value is proportional to the motor torque. This value can be found in the ParkParm data structure. The motor mechanical velocity is in the EncoderParm data structure. The plot shows an example of properly tuned control loops. As you can see, there is little overshoot or ringing in the bottom trace (motor velocity). Also, there is a rapid response in the quadrature current (top trace), followed by a decay with little overshoot or ringing as the motor reaches the new speed. FIGURE 14: IQ VS. VELOCITY, 500 TO 1000 RPM STEP CONTROL LOOP DEPENDENCIES There are three PI control loops in this application that are interdependent. The outer loop controls the motor velocity. The two inner loops control the transformed motor currents, Id and Iq. As mentioned previously, the Id loop is responsible for controlling flux and the Iq value is responsible for controlling the motor torque. TORQUE MODE When adjusting the coefficients for the three control loops, it can be beneficial to separate the outer control loop from the inner loops. The motor can be operated in a torque mode by un-commenting the #define TORQUE_MODE statement in the UserParms.h file. This will bypass the outer velocity control loop and feed the potentiometer demand value directly to the Iq control loop setpoint. 2004 Microchip Technology Inc. DS00908A-page 17 AN908 AN908 Figure 15 compares the actual AC phase current and the motor velocity during a 1000 RPM to 2000 RPM step change with properly tuned PI loop parameters and the correct motor time constant. The phase current is measured directly from one of the two phase current sensors on the motor control development system. The velocity data is obtained from the EncoderParm data structure and sent to one of the PWM diagnostic outputs for display on the scope. In this scope plot you can observe that the velocity moves quickly to the new setpoint with little or no overshoot and ringing. Furthermore, the amplitude of the phase current does not change dramatically during the speed change. FIGURE 15: Figure 17 demonstrates a step change with an incorrect rotor time constant value. The step change requires more current and time to execute. FIGURE 17: PHASE CURRENT VS. VELOCITY, 1000 TO 2000 RPM STEP, TR = 0.039 SEC PHASE CURRENT VS. VELOCITY, 1000 TO 2000 RPM STEP, TR = 0.078 SEC APPENDIX A. REFERENCES 1. 2. Vector Control and Dynamics of AC Drives, D. W. Novotny, T. A. Lipo, Oxford University Press, 2003, ISBN: 0 19 856439 2. Modern Power Electronics and AC Drives, Bimal K. Bose, Pearson Education, 2001, ISBN: 0 13 016743 6. Figure 16 shows the same phase current and velocity data shown in Figure 15. In this case, a step change is made from 1000 RPM to 2000 RPM in open loop mode. The speed change in open loop mode requires a higher current amplitude and more time to complete. A comparison of Figure 15 and Figure 16 clearly shows the benefits of vector control. The speed change takes less current to execute in closed loop mode. FIGURE 16: DS00908A-page 18 PHASE CURRENT VS. VELOCITY, 1000 TO 2000 RPM STEP, OPEN LOOP 2004 Microchip Technology Inc. AN908 AN908 APPENDIX B. SOURCE CODE Assembly Files This appendix contains source listings for the files listed below. These are the primary files associated with the vector control algorithm. Other files related to the user interface have not been included in this listing. CalcRef.s If you are viewing an electronic version of this application, you can navigate to a particular file by clicking the file name below. CurModel.s Header Files MeasCur.s CalcVel.s ClarkePark.s FdWeak.s InvPark.s OpenLoop.s UserParms.h C Files ACIM.c Encoder.c PI.s ReadADC0.s SVGen.s Trig.s InitCurModel.c Software License Agreement The software supplied herewith by Microchip Technology Incorporated (the "Company") is intended and supplied to you, the Company's customer, for use solely and exclusively with products manufactured by the Company. The software is owned by the Company and/or its supplier, and is protected under applicable copyright laws. All rights are reserved. Any use in violation of the foregoing restrictions may subject the user to criminal sanctions under applicable laws, as well as to civil liability for the breach of the terms and conditions of this license. THIS SOFTWARE IS PROVIDED IN AN "AS IS" CONDITION. NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. 2004 Microchip Technology Inc. DS00908A-page 19 AN908 AN908 UserParms.h //#define TORQUE_MODE #define DIAGNOSTICS //* Oscillator * #define dFoscExt 7372800 // External Crystal or Clock Frequency (Hz) #define dPLL 8 // PLL ratio #define dLoopTimeInSec 0.00005 // PWM Period - 100 uSec, 10Khz PWM #define dDeadTimeSec 0.000002 // Deadtime in seconds // Derived #define dFosc (dFoscExt*dPLL) // Clock frequency (Hz) #define dFcy (dFosc/4) // Instruction cycle frequency (Hz) #define dTcy (1.0/dFcy) // Instruction cycle period (sec) #define dDeadTime (int)(dDeadTimeSec*dFcy) // Dead time in dTcys #define dLoopInTcy (dLoopTimeInSec/dTcy) // Basic loop period in units of Tcy #define dDispLoopTime 0.100 // Display and button polling loop //* Motor #define diPoles #define diCntsPerRev #define diNomRPM #define dfRotorTmConst Parameters * 1 // Number of pole pairs 2000 // Encoder Lines per revolution 3600 // Name Plate Motor RPM 0.078 // Rotor time constant in sec, from mfgr //* Measurement * #define diIrpPerCalc 30 // PWM loops per velocity calculation //* PI Coefficients * #define dDqKp 0x2000 // 4.0 (NKo = 4) #define dDqKi 0x0100; // 0.125 #define dDqKc 0x0100; // 0.125 #define dDqOutMax 0x5A82; // 0.707 set to prevent saturation #define #define #define #define dQqKp dQqKi dQqKc dQqOutMax 0x2000; 0x0100; 0x0100; 0x5A82; // // // // 4.0 0.125 0.125 0.707 (NKo = 4) #define #define #define #define dQrefqKp dQrefqKi dQrefqKc dQrefqOutMax 0x4000 0x0800 0x0800 0x3FFF // // // // 8.0 1.0 1.0 0.4999 (NKo = 4) set to prevent saturation set to prevent saturation //* ADC Scaling * // Scaling constants: Determined by calibration or hardware design. #define dqK 0x3FFF; // equivalent to 0.4999 #define dqKa 0x3FFF; // equivalent to 0.4999 #define dqKb 0x3FFF; // equivalent to 0.4999 //* Field Weakening * // Flux reference value in constant torque range. // Determined empirically to give rated volts/hertz #define dqK1 3750; // DS00908A-page 20 2004 Microchip Technology Inc. AN908 AN908 ACIM.c /* * * * Author: John Theys/Dave Ross * * * * Filename: ACIM.c * * Date: 10/31/03 * * File Version: 3.00 * * * * Tools used: MPLAB -> 6.43 * * Compiler -> 1.20.00 * * * * Linker File: p30f6010.gld * * * * * * *10/31/03 2.00 Released Motor runs fine, still some loose ends * *12/19/03 2.01 Cleaned up structure, created UserParms.h for all user defines. * *02/12/043.00-Removed unnecessary files from project. * -Changed iRPM to int to correct floating point calc problems. * -CalcVel() and velocity control loop only execute after number of loop periods * specified by iIrpPerCalc. * -Added iDispLoopCount variable to schedule execution of display and button routines * -trig.s file changed to use program space for storage of sine data. * -Added DiagnosticsOutput() function that uses output compare channels to * output control variable information. * -Added TORQUE_MODE definition to bypass velocity control loop. * -Turned off SATDW bit in curmodel.s file. The automatic saturation feature prevents * slip angle calculation from wrapping properly. * * Code Description * * This file demonstrates Vector Control of a 3 phase ACIM using the dsPIC30F. * SVM is used as the modulation strategy. */ /* GLOBAL DEFINITIONS */ #define INITIALIZE #include "Motor.h" #include "Parms.h" #include "Encoder.h" #include "SVGen.h" #include "ReadADC.h" #include "MeasCurr.h" #include "CurModel.h" #include "FdWeak.h" #include "Control.h" #include "PI.h" #include "Park.h" #include "OpenLoop.h" #include "LCD.h" #include "bin2dec.h" #include "UserParms.h" /* END OF GLOBAL DEFINITIONS */ unsigned short uWork; short iCntsPerRev; short iDeltaPos; 2004 Microchip Technology Inc. DS00908A-page 21 AN908 AN908 union tPIParm tPIParm tPIParm { struct { unsigned unsigned unsigned unsigned unsigned unsigned unsigned unsigned unsigned unsigned }bit; WORD Word; } uGF; DoLoop:1; OpenLoop:1; RunMotor:1; Btn1Pressed:1; Btn2Pressed:1; Btn3Pressed:1; Btn4Pressed:1; ChangeMode:1; ChangeSpeed:1; :7; // general flags PIParmQ; PIParmQref; PIParmD; tReadADCParm ReadADCParm; int iRPM; WORD iMaxLoopCnt; WORD iLoopCnt; WORD iDispLoopCnt; /*/ void _attribute_(_interrupt_) _ADCInterrupt(void); void SetupBoard( void ); bool SetupParm(void); void DoControl( void ); void Dis_RPM( BYTE bChrPosC, BYTE bChrPosR ); void DiagnosticsOutput(void); /* START OF MAIN FUNCTION */ int main ( void ) { SetupPorts(); InitLCD(); while(1) { uGF.Word = 0; // init Mode uGF.bit.OpenLoop = 1; // init pinLED1 pinLED2 pinLED3 pinLED4 // clear flags // start in openloop LEDs = 0; = !uGF.bit.OpenLoop; = 0; = 0; // init board SetupBoard(); // init user specified parms and stop on error if( SetupParm() ) { // Error uGF.bit.RunMotor=0; return; DS00908A-page 22 2004 Microchip Technology Inc. AN908 AN908 } // zero out i sums PIParmD.qdSum = 0; PIParmQ.qdSum = 0; PIParmQref.qdSum = 0; iMaxLoopCnt = 0; Wrt_S_LCD("Vector Control Wrt_S_LCD("S4-Run/Stop ", 0 , 0); ", 0, 1); // Enable ADC interrupt and begin main loop timing IFS0bits.ADIF = 0; IEC0bits.ADIE = 1; if(!uGF.bit.RunMotor) { // Initialize current offset compensation while(!pinButton1) //wait here until button 1 is pressed { ClrWdt(); // Start offset accumulation MeasCompCurr(); } while(pinButton1); uGF.bit.RunMotor = 1; } //and accumulate current offset while waiting //when button 1 is released //then start motor // Run the motor uGF.bit.ChangeMode = 1; // Enable the driver IC on the motor control PCB pinPWMOutputEnable_ = 0; Wrt_S_LCD("RPM= ", 0, 0); Wrt_S_LCD("S5-Cls. Lp S6-2x", 0, 1); //Run Motor loop while(1) { ClrWdt(); // If using OC7 and OC8 to display vector control variables, // call the update code. #ifdefDIAGNOSTICS DiagnosticsOutput(); #endif // The code that updates the LCD display and polls the buttons // executes every 50 msec. if(iDispLoopCnt >= dDispLoopCnt) { //Display RPM Dis_RPM(5,0); // Button 1 starts or stops the motor if(pinButton1) { if( !uGF.bit.Btn1Pressed ) uGF.bit.Btn1Pressed = 1; } else 2004 Microchip Technology Inc. DS00908A-page 23 AN908 AN908 { if( uGF.bit.Btn1Pressed ) { // Button just released uGF.bit.Btn1Pressed = 0; // begin stop sequence uGF.bit.RunMotor = 0; pinPWMOutputEnable_ = 1; break; } } //while running button 2 will toggle open and closed loop if(pinButton2) { if( !uGF.bit.Btn2Pressed ) uGF.bit.Btn2Pressed = 1; } else { if( uGF.bit.Btn2Pressed ) { // Button just released uGF.bit.Btn2Pressed = 0; uGF.bit.ChangeMode = 1; uGF.bit.OpenLoop = ! uGF.bit.OpenLoop; pinLED2 = !uGF.bit.OpenLoop; } } //while running button 3 will double/half the speed or torque demand if(pinButton3) { if( !uGF.bit.Btn3Pressed ) uGF.bit.Btn3Pressed = 1; LATGbits.LATG0 = 0; } else { if( uGF.bit.Btn3Pressed ) { // Button just released uGF.bit.Btn3Pressed = 0; uGF.bit.ChangeSpeed = !uGF.bit.ChangeSpeed; pinLED3 = uGF.bit.ChangeSpeed; LATGbits.LATG0 = 1; } } // Button 4 does not do anything if(pinButton4) { if( !uGF.bit.Btn4Pressed ) uGF.bit.Btn4Pressed = 1; } else { if( uGF.bit.Btn4Pressed ) { // Button just released uGF.bit.Btn4Pressed = 0; //* ADD CODE HERE FOR BUTTON 4 FUNCTION } } DS00908A-page 24 2004 Microchip Technology Inc. AN908 AN908 } // end of display and button polling code } // End of Run Motor loop } // End of Main loop // should never get here while(1){} } //-// Executes one PI itteration for each of the three loops Id,Iq,Speed void DoControl( void ) { short i; // Assume ADC channel 0 has raw A/D value in signed fractional form from // speed pot (AN7). ReadSignedADC0( &ReadADCParm ); // Set reference speed if(uGF.bit.ChangeSpeed) CtrlParm.qVelRef = ReadADCParm.qADValue/8; else CtrlParm.qVelRef = ReadADCParm.qADValue/16; if( uGF.bit.OpenLoop ) { ` // OPENLOOP: force rotating angle,Vd,Vq if( uGF.bit.ChangeMode ) { // just changed to openloop uGF.bit.ChangeMode = 0; // synchronize angles OpenLoopParm.qAngFlux = CurModelParm.qAngFlux; // VqRef & VdRef not used CtrlParm.qVqRef = 0; CtrlParm.qVdRef = 0; } OpenLoopParm.qVelMech = CtrlParm.qVelRef; // calc rotational angle of rotor flux in 1.15 format // just for reference & sign needed by CorrectPhase CurModelParm.qVelMech = EncoderParm.qVelMech; CurModel(); ParkParm.qVq = 0; if( OpenLoopParm.qVelMech >= 0 ) i = OpenLoopParm.qVelMech; else i = -OpenLoopParm.qVelMech; uWork = i iMaxLoopCnt ) iMaxLoopCnt = iLoopCnt; // Clear LED1 for diagnostics pinLED1 = 0; } } 2004 Microchip Technology Inc. DS00908A-page 27 AN908 AN908 //-// SetupBoard // // Initialze board //-void SetupBoard( void ) { BYTE b; // Disable ADC interrupt IEC0bits.ADIE = 0; // Reset any active faults on the motor control power module. pinFaultReset = 1; for(b=0;b 1.08504 uS tick // = Motor PWM = PDC1 PDC2 PDC3 PDC4 // // // // = = = = 0; 0; 0; 0; Center aligned PWM. Note: The PWM period is set to dLoopInTcy/2 but since it counts up and and then down => the interrupt flag is set to 1 at zero => actual interrupt period is dLoopInTcy PTPER = dLoopInTcy/2; // Setup PWM period to Loop Time defined in parms.h PWMCON1 = 0x0077; DTCON1 = dDeadTime; DTCON2 = 0; FLTACON = 0; FLTBCON = 0; PTCON = 0x8002; // Enable PWM 1,2,3 pairs for complementary mode // Dead time // PWM fault pins not used // Enable PWM for center aligned operation // SEVTCMP: Special Event Compare Count Register // Phase of ADC capture set relative to PWM cycle: 0 offset and counting up SEVTCMP = 2; // Cannot be 0 -> turns off trigger (Missing from doc) DS00908A-page 30 2004 Microchip Technology Inc. AN908 AN908 SEVTCMPbits.SEVTDIR = 0; // = Encoder = MAXCNT = MotorParm.iCntsPerRev; POSCNT = 0; QEICON = 0; QEICONbits.QEIM = 7; // x4 reset by MAXCNT pulse QEICONbits.POSRES = 0; // Don't allow Index pulse to reset counter QEICONbits.SWPAB = 0; // direction DFLTCON = 0; // Digital filter set to off // = ADC - Measure Current & Pot = // ADC setup for simultanous sampling on // CH0=AN7, CH1=AN0, CH2=AN1, CH3=AN2. // Sampling triggered by PWM and stored in signed fractional form. ADCON1 = 0; // Signed fractional (DOUT = sddd dddd dd00 0000) ADCON1bits.FORM = 3; // Motor Control PWM interval ends sampling and starts conversion ADCON1bits.SSRC = 3; // Simultaneous Sample Select bit (only applicable when CHPS = 01 or 1x) // Samples CH0, CH1, CH2, CH3 simultaneously (when CHPS = 1x) // Samples CH0 and CH1 simultaneously (when CHPS = 01) ADCON1bits.SIMSAM = 1; // Sampling begins immediately after last conversion completes. // SAMP bit is auto set. ADCON1bits.ASAM = 1; ADCON2 = 0; // Samples CH0, CH1, CH2, CH3 simultaneously (when CHPS = 1x) ADCON2bits.CHPS = 2; ADCON3 = 0; // A/D Conversion Clock Select bits = 8 * Tcy ADCON3bits.ADCS = 15; /* ADCHS: ADC Input Channel Select Register */ ADCHS = 0; // CH0 is AN7 ADCHSbits.CH0SA = 7; // CH1 positive input is AN0, CH2 positive input is AN1, CH3 positive input is AN2 ADCHSbits.CH123SA CH123SA = 0; /* ADPCFG: ADC Port Configuration Register */ // Set all ports digital ADPCFG = 0xFFFF; ADPCFGbits.PCFG0 = 0; // AN0 analog ADPCFGbits.PCFG1 = 0; // AN1 analog ADPCFGbits.PCFG2 = 0; // AN2 analog ADPCFGbits.PCFG7 = 0; // AN7 analog /* ADCSSL: ADC Input Scan Select Register */ ADCSSL = 0; // Turn on A/D module ADCON1bits.ADON = 1; #ifdefDIAGNOSTICS // Initialize Output Compare 7 and 8 for use in diagnostics. 2004 Microchip Technology Inc. DS00908A-page 31 AN908 AN908 // Compares are used in PWM mode // Timer2 is used as the timebase PR2 = 0x1FFF; OC7CON = 0x0006; OC8CON = 0x0006; T2CONbits.TON = 1; #endif return False; } #ifdefDIAGNOSTICS void DiagnosticsOutput(void) { int Data; if(IFS0bits.T2IF) { IFS0bits.T2IF = 0; Data = (ParkParm.qIq >> 4) + 0xfff; if(Data > 0x1ff0) Data = 0x1ff0; if(Data < 0x000f) Data = 0x000f; OC7RS = Data; Data = (EncoderParm.qVelMech) + 0x0fff; if(Data > 0x1ff0) Data = 0x1ff0; if(Data < 0x000f) Data = 0x000f; OC8RS = Data; } } #endif DS00908A-page 32 2004 Microchip Technology Inc. AN908 AN908 Encoder.c // Scaling for encoder routines #include "general.h" #include "Parms.h" #include "Encoder.h" /* InitEncoderScaling Initialize scaling constants for encoder rotuines. Arguments: CntsPerRev: Encoder counts per revolution from quadrature ScalingSpeedInRPS: Rev per sec used for basic velocity scaling IrpPerCalc: Number of CalcVelIrp interrupts per velocity calculation VelIrpPeriod: Period between VelCalcIrp interrupts (in Sec) For CalcAng: Runtime equation: qMechAng = qKang * (POSCNT*4) / 2^Nang Scaling equations: qKang = (2^15)*(2^Nang)/CntsPerRev. For CalcVelIrp, CalcVel: Runtime equation: qMechVel = qKvel * (2^15 * Delta / 2^Nvel) Scaling equations: fVelCalcPeriod = fVelIrpPeriod * iIrpPerCalc MaxCntRate = CntsPerRev * ScaleMechRPS MaxDeltaCnt = fVelCalcPeriod * MaxCntRate qKvel = (2^15)*(2^Nvel)/MaxDeltaCnt */ bool InitEncoderScaling( void ) { float fVelCalcPeriod, fMaxCntRate; long MaxDeltaCnt; long K; EncoderParm.iCntsPerRev = MotorParm.iCntsPerRev; K = 32768; K *= 1 w7 ; Timing: ; 20 cycles ;* ; include "general.inc" ; External references include "park.inc" ; Register usage .equ ParmW, w3 ; Ptr to ParkParm structure .equ Sq3W, w4 ; OneBySq3 .equ SinW, w4 ; replaces Work0W .equ CosW, w5 .equ IaW, w6 ; copy of qIa .equ IalphaW, w6 ; replaces Ia .equ IbW, w7 ; copy of qIb .equ IbetaW, w7 ; Ibeta replaces Ib ; Constants equ OneBySq3, 0x49E7 ; 1/sqrt(3) in 1.15 format ;= CODE = section .text global _ClarkePark global ClarkePark _ClarkePark: ClarkePark: ; Ibeta = Ia*OneBySq3 + 2*Ib*OneBySq3; mov.w mov.w mpy mov.w mac mac mov.w mov.w sac mov.w #OneBySq3,Sq3W ; 1/sqrt(3) in 1.15 format _ParkParm+Park_qIa,IaW Sq3W*IaW,A _ParkParm+Park_qIb,IbW Sq3W*IbW,A Sq3W*IbW,A _ParkParm+Park_qIa,IalphaW IalphaW,_ParkParm+Park_qIalpha A,IbetaW IbetaW,_ParkParm+Park_qIbeta ; Ialpha and Ibeta have been calculated. Now do rotation. ; Get qSin, qCos from ParkParm structure mov.w _ParkParm+Park_qSin,SinW mov.w _ParkParm+Park_qCos,CosW ; Id = mpy mac mov.w sac Ialpha*cos(Angle) + Ibeta*sin(Angle) SinW*IbetaW,A CosW*IalphaW,A #_ParkParm+Park_qId,ParmW A,[ParmW+] ; Ibeta*qSin -> A ; add Ialpha*qCos to A ; store to qId, inc ptr to qIq ; Iq = -Ialpha*sin(Angle) + Ibeta*cos(Angle) mpy CosW*IbetaW,A ; Ibeta*qCos -> A msc SinW*IalphaW,A ; sub Ialpha*qSin from A sac A,[ParmW] ; store to qIq return .end 2004 Microchip Technology Inc. DS00908A-page 37 AN908 AN908 CurModel.s ;* ;Routines: CurModel ;* ;Common to all routines in file .include "general.inc" .include "curmodel.inc" .include "park.inc" ;* ; CurModel ; ; Description: ; ; Physical constants: ; fRotorTmConst Rotor time constant in sec ; ;Physical form of equations: ; Magnetizing current (amps): ; Imag = Imag + (fLoopPeriod/fRotorTmConst)*(Id - Imag) ; ; Slip speed in RPS: ; VelSlipRPS = (1/fRotorTmConst) * Iq/Imag / (2*pi) ; ; Rotor flux speed in RPS: ; VelFluxRPS = iPoles * VelMechRPS + VelSlipRPS ; ; Rotor flux angle (radians): ; AngFlux = AngFlux + fLoopPeriod * 2 * pi * VelFluxRPS ; ; Scaled Variables: ; qdImag Magnetizing current scaled by maximum current (1.31) ; qVelSlip Mechnical Slip velocity in RPS scaled by fScaleMechRPS ; qAngFlux Flux angle scaled by pi ; ; Scaled Equations: ; qdImag = qdImag + qKcur * (qId - qdImag) ; qVelSlip = qKslip * qIq/qdImag ; qAngFlux = qAngFlux + qKdelta * (qVelMech + qVelSlip) ; ; Scaling factors: ; qKcur = (2^15) * (fLoopPeriod/fRotorTmConst) ; qKdelta = (2^15) * 2 * iPoles * fLoopPeriod * fScaleMechRPS ; qKslip = (2^15)/(2 * pi * fRotorTmConst * iPoles * fScaleMechRPS) ; ; Functional prototype: ; ; void CurModel( void ) ; ; On Entry: CurModelParm structure must contain qKcur, qKslip, iKpoles, ; qKdelta, qVelMech, qMaxSlipVel ; On Exit: CurModelParm will contain qAngFlux, qdImag and qVelSlip ; ; Parameters: ; Input arguments: ; None ; Return: ; Void ; SFR Settings required: ; CORCON.SATA = 0 ; CORCON.IF = 0 ; ; Support routines required: ; None ; Local Stack usage: ; 0 DS00908A-page 38 2004 Microchip Technology Inc. AN908 AN908 ; Registers modified: : w0-w7,AccA ; Timing: ; 72 instruction cycles ;* ; ;= CODE = .section .text ; Register usage for CurModel .equ SignW, w2 .equ ShiftW, w3 .equ IqW, w4 .equ KslipW, w5 .equ ImagW, w7 .global .global ; ; ; ; ; track sign changes # shifts before divide Q current (1.15) Kslip constant (1.15) magnetizing current (1.15) _CurModel CurModel _CurModel: CurModel: ; qdImag = qdImag + qKcur * (qId - qdImag) mov.w _CurModelParm+CurMod_qdImag,w6 mov.w _CurModelParm+CurMod_qdImag+2,w7 lac w7,A mov.w w6,ACCALL mov.w sub.w mov.w _ParkParm+Park_qId,w4 w4,w7,w4 _CurModelParm+CurMod_qKcur,w5 mac sac mov.w mov.w mov.w w4*w5,A A,w7 ACCALL,w6 w6,_CurModelParm+CurMod_qdImag w7,_CurModelParm+CurMod_qdImag+2 ; magnetizing current ; qId-qdImagH ; add Kcur*(Id-Imag) to Imag ; qVelSlip = qKslip * qIq/qdImag ; First make qIqW and qdImagW positive and save sign in SignW clr SignW ; set flag sign to positive ; if( IqW < 0 ) => toggle SignW and set IqW = -IqW mov.w _ParkParm+Park_qIq,IqW cp0 IqW bra Z,jCurModSkip bra NN,jCurMod1 neg IqW,IqW com SignW,SignW ; toggle sign jCurMod1: ; if( ImagW < 0 ) => toggle SignW and set ImagW = -ImagW cp0 ImagW bra NN,jCurMod2 neg ImagW,ImagW com SignW,SignW ; toggle sign jCurMod2: ; Calculate Kslip*|IqW| in Acc A to maintain 1.31 mov.w _CurModelParm+CurMod_qKslip,KslipW mpy IqW*KslipW,A ; Make sure denominator is > numerator else skip term sac A,w0 ; temporary cp ImagW,w0 ; |qdImag| - |Kslip*qIq| bra LEU,jCurModSkip ; skip term: |qdImag| A CosW*VqW,A ; add Vq*qCos to A A,[ParmW] ; store to Vbeta return 2004 Microchip Technology Inc. DS00908A-page 41 AN908 AN908 CalcRef.s ;* ; CalcRefVec ; ; Description: ; Calculate the scaled reference vector, (Vr1,Vr2,Vr3), from qValpha,qVbeta. ; The method is an modified inverse Clarke transform where Valpha & Vbeta ; are swaped compared to the normal Inverse Clarke. ; ; Vr1 = Vbeta ; Vr2 = (-Vbeta/2 + sqrt(3)/2 * Valpha) ; Vr3 = (-Vbeta/2 - sqrt(3/2) * Valpha) ; ; Functional prototype: ; ; void CalcRefVec( void ) ; ; On Entry:The ParkParm structure must contain qCos, qSin, qValpha and qVbeta. ; On Exit: SVGenParm will contain qVr1, qVr2, qVr3 ; ; Parameters: ; Input arguments: ; None ; Return: ; Void ; SFR Settings required: ; CORCON.SATA = 0 ; Support routines required: ; None ; Local Stack usage: ; None ; Registers modified: ; w0, w4, w5, w6 ; Timing: ; About 20 instruction cycles ;* ; .include "general.inc" ; External references .include "park.inc" .include "SVGen.inc" ; Register usage .equ WorkW, w0 .equ ValphaW, w4 .equ VbetaW, w5 .equ ScaleW, w6 ; Constants .equ Sq3OV2,0x6ED9 ;= CODE = .section .global .global _CalcRefVec: CalcRefVec: ; Get qValpha, qVbeta mov.w mov.w ; Put Vr1 = Vbeta mov.w ; Load Sq(3)/2 mov.w DS00908A-page 42 ; ; ; ; working qValpha (scaled) qVbeta (scaled) scaling ; sqrt(3)/2 in 1.15 format .text _CalcRefVec CalcRefVec from ParkParm structure ParkParm+Park_qValpha,ValphaW _ParkParm+Park_qVbeta,VbetaW VbetaW,_SVGenParm+SVGen_qVr1 #Sq3OV2,ScaleW 2004 Microchip Technology Inc. AN908 AN908 ; AccA = -Vbeta/2 neg.w VbetaW,VbetaW lac VbetaW,#1,A ; Vr2 = -Vbeta/2 + sqrt(3)2 * Valpha) mac ValphaW*ScaleW,A ; add Valpha*sqrt(3)/2 to A sac A,WorkW mov.w WorkW,_SVGenParm+SVGen_qVr2 ; AccA = -Vbeta/2 lac VbetaW,#1,A ; Vr3 = (-Vbeta/2 - sqrt(3)2 * Valpha) msc ValphaW*ScaleW,A ; sub Valpha*sqrt(3)2 to A sac A,WorkW mov.w WorkW,_SVGenParm+SVGen_qVr3 return .end 2004 Microchip Technology Inc. DS00908A-page 43 AN908 AN908 CalcVel.s ;* ; Routines: InitCalcVel, CalcVel ; ;* ; Common to all routines in file .include "general.inc" .include "encoder.inc" ;* ; void InitCalcVel(void) ; Initialize private velocity variables. ; iIrpPerCalc must be set on entry. ;* ; Register usage for InitCalcVel .equ Work0W, .equ PosW, w4 w5 ; Working register ; current position: POSCNT ;* .global .global _InitCalcVel: InitCalcVel: _InitCalcVel InitCalcVel ; Disable interrupts for the next 5 instructions DISI #5 ; Load iPrevCnt & zero Delta ; encoder value. Note: To get accurate velocity qVelMech must be ; calculated twice. mov.w POSCNT,PosW ; current encoder value mov.w PosW,_EncoderParm+Encod_iPrevCnt clr.w _EncoderParm+Encod_iAccumCnt ; Load iVelCntDwn mov.w _EncoderParm+Encod_iIrpPerCalc,WREG mov.w WREG,_EncoderParm+Encod_iVelCntDwn return ;* ; CalcVelIrp ; ; Called from timer interrupt at specified intervals. ; ; The interrupt interval, VelPeriod, MUST be less than the minimum time ; required for 1/2 revolution at maximum speed. ; ; This routine will accumulate encoder change for iIrpPerCalc interrupts, ; a period of time = iIrpPerCalc * VelPeriod, and then copy the accumulation ; to iDeltaCnt for use by the CalcVel routine to calculate velocity. ; The accumulation is set back to zero and a new accumulation starts. ; ;Functional prototype: void CalcVelIrp( void ); ; ;On Entry: EncoderParm must contain iPrevCnt, iAccumCnt, iVelCntDwn ; ;On Exit: EncoderParm will contain iPrevCnt, iAccumCnt and iDeltaCnt ; (if countdown reached zero). ; DS00908A-page 44 2004 Microchip Technology Inc. AN908 AN908 ;Parameters: ; Input arguments None ; ; Return: ; Void ; ; SFR Settings required None ; ; Support routines required: None ; ; Local Stack usage: 3 ; ; Registers modified: None ; ; Timing: About 29 instruction cycles (if new iDeltaCnt produced) ; ;= ; Equivalent C code ; { ; register short Pos, Delta; ; ; Pos = POSCNT; ; ; Delta = Pos - EncoderParm.iPrevCnt; ; EncoderParm.iPrevCnt = Pos; ; ; if( iDelta >= 0 ) ; { ; // Delta > 0 either because ; // 1) vel is > 0 or ; // 2) Vel < 0 and encoder wrapped around ; ; if( Delta >= EncoderParm.iCntsPerRev/2 ) ; { ; // Delta >= EncoderParm.iCntsPerRev/2 => Neg speed, wrapped around ; ; Delta -= EncoderParm.iCntsPerRev; ; } ; } ; else ; { ; // Delta < 0 either because ; // 1) vel is < 0 or ; // 2) Vel > 0 and wrapped around ; ; if( Delta < -EncoderParm.iCntsPerRev/2 ) ; { ; // Delta < -EncoderParm.iCntsPerRev/2 => Pos vel, wrapped around ; ; Delta +