Text preview for : an1215 routines PID.pdf part of MAAS KNT-5000 Stabilized DC Power Supply
MAAS KNT-5000
Back to : Maas KNT-5000.pdf | Home
MOTOROLA
Order this document by: A N 1 2 1 5 / D
SEMICONDUCTOR
APPLICATION NOTE
PID Routines for MC68HC11K4 and MC68HC11N4 Microcontrollers
By James W. Gray
INTRODUCTION
PID (proportional, integral, derivative) compensation is one of the most common forms of closed-loop control. Control of closed-loop systems that require compensation is a growing area of application for embedded microprocessors. In these systems, analog signals must be converted into discrete digital samples before compensation or filtering can take place. Loop performance dictates the sampling rate, and calculations must be complete before the next sample time begins. These loop-related constraints and the Nyquist frequency requirement place an upper bound on digital control of closed systems with feedback error. If the controlled system has a resonance or other behavior with a time constant shorter than the sample and calculation time, chaos is the most likely outcome. Despite these limitations, increases in microprocessor clock rates and the addition of on-chip control-oriented hardware are expanding the number of medium performance control applications handled by 8-bit machines. While an expensive DSP-class processor is the correct choice for the most demanding applications, several members of the M68HC11 family have the speed and resources to control multiple PWM channels. This note provides two working examples of PID control-loop software. The first example, written primarily in C, shows a PID algorithm in a straightforward way using floating-point math. Key features of the C environment are covered for readers who are more used to assembly language. The second example implements a PID algorithm in assembly language. It uses the MC68HC11N4 on-chip math coprocessor to speed up arithmetic operations. Both examples are complete and ready to run on a Motorola M68HC11EVS evaluation board. External interfacing is identical for both examples -- an 8-bit analog to digital converter is used for input, and an 8-bit PWM waveform is output. Because the code in both examples carries more than 16 bits of precision, and because both processors support 16-bit PWM, only minor changes are needed to increase precision. Power amplifiers, sensors, and other interface circuitry must be supplied in order to experiment with real-world systems -- a simple RC circuit is used for software checkout. C and assembly language source code and loadable object code can be obtained from Motorola Freeware Data Systems. Modem access: (512) 891-3733. Internet access: freeware.aus sps.mot.com. Web access: http:///www.freeware.aus.sps.mot.com.
THE MICROCONTROLLERS
The MC68HC11K4 and MC68HC11N4 are 16-MHz devices with nonmultiplexed external address and data buses. Each has 24 Kbytes of on-chip ROM or EPROM. Both devices have multiple PWM channels with programmable period, duty cycle, polarity, and clock source. In both, two 8-bit channels can be concatenated to generate a 16-bit PWM output. The MC68HC11N4 also has two additional 12-bit PWM channels and two digital to analog converter channels with 8-bit resolution.
© MOTOROLA INC, 1996
The MC68HC11N4 is particularly well-suited to PID computation because it has an on-chip math coprocessor that performs 16- and 32-bit multiplication and division, fractional division, and multiply-and-accumulate operations. All operations are done by means of memory-mapped registers, thus preserving the standard M68HC11 family instruction set. Multiplication and fractional division are complete in a maximum of 5 microseconds while integer division requires a maximum of 8.75 microseconds.
PID ALGORITHM
The general flow of a controlled system with PID compensation is shown in Figure 1. An informal review of the derivation of the discrete form of each term and how they function follows. REFERENCES 2 and 3 provide a complete analysis of digital PID control.
Kp
e(kT) E(z)
K IT(z + 1) 2(z 1)
u(kT) U(z)
K d (z 1) Tz
AN1215 DIGITAL PID BLOCK
Figure 1 PID Flow Diagram There is a desired setpoint in our process (Gd) and a measurement of the actual value G(t) in time. Error is: e(t) = Gd - G(t) Output correction x(t) for the PID controller is: de(t) x(t) = KP e(t) + KI e(t) + KD ----------- | t = T dt where KP, KI, and KD are constants. Now, rewriting the integral:
t
x(t) = KP e(t) + KI
t=0
de(t) [Gd - G(t)]dt + KD ----------- | t = T dt
To introduce discrete time, let t = kT where k = 1,2,...,n and T = the sampling and control update period. Now, t0 = (k 1)T. The integral evaluated from (k 1)T to kT can be approximated using the trapezoidal integration rule. The derivative of the error term is simply the rate of change of error, but this can be noisy over one period. Using a four-point central-weighted average for the difference term is a practical way to deal with this on a microprocessor.
MOTOROLA 2
AN1215/D
The form which can be executed directly on the microprocessor is: T KD x (t ) = KP e (t ) + KI (G dt - ( G (Kt ) + G [ (k - 1)T])) + ((e (kT ) - e (k - 3) + 3 ( e (k - 1) - e (k - 2))) 2 6T This term is added to the current output and put into the PWM control register at the beginning of the next calculation cycle. Substituting the microcode labels for constants and variables into EQ. 4 and using C language operator notation gives: NEWDTY = KP (ERRX) + KI PERDT (CMNDX - (ADRCX + ADRCXM1) / 2) + (KD / (6 PERDT)) ((ERRX - ERRM3X) + 3 (ERRM1X - ERRM2X)) + OLDDTY The function of the proportional term is clear, but the derivative and integral terms may need a brief explanation. When a system with only proportional control is off the specified setpoint, the controller will increase the control voltage until the error signal is zero, and the system thus returns to the setpoint with more applied voltage than is required for maintaining equilibrium. This causes overshoot and, as the process continues, under-damped ringing. The derivative term contributes proportionally to the error rate of change, but with the opposite sign of the proportional term. If the proper constants are chosen, critical damping can be achieved. The role of the integral term is to eliminate steady state error. A system that has a steady state error when tracking a ramping input function can use an integral term to integrate the error over time and compensate for it.
C LANGUAGE IMPLEMENTATION
This version of the PID control routine illustrates use of high-level language for control applications. Highlevel language offers many conveniences not available in assembly language. Here are a few instances: Memory-mapped registers can be defined in a single file, which can be included in any function. Since C is a strongly-typed language, the compiler can identify data-type mismatches, such as writing a 16-bit integer to an 8-bit port. Most C compilers for the M68HC11 family allow direct vectoring to interrupt service routines. Interrupt functions are usually defined for a special memory segment with a base address and a function name: interrupt [INTVEC_START + 26] void RTI_interrupt(void); When an interrupt service routine is written it can be declared as an interrupt function instead of a normal subroutine: interrupt void RTI_interrupt(void) The function is compiled with a terminating RTI instruction, eliminating the need for a patch between hardware interrupts and C subroutines. The void statements indicate that no arguments are being passed to or from the interrupt routine. One of the most attractive features of contemporary C compilers is the ability to add floating point math with an "include math.h" statement. Even when the final application can't afford the time or code space for floating point calculations, use of floating point math during debugging provides an excellent means of testing new algorithms. Now to examine the control routine itself (refer to Appendix A for a complete C listing). After necessary files are included and floating point variables are declared, a prototype is given to define an assembly language function that is used later.
AN1215/D
MOTOROLA 3
The main program initializes constants and variables, sets up the required on-chip peripherals, and waits for interrupts to occur. The M68HC11 real-time interrupt (RTI) is used to establish a precise time base for performing PID compensation. The period (T or PERDT) is determined by the RTI rate. In these examples, the period is 16.383 milliseconds, but this value is arbitrary -- in real applications, the performance of the controlling microprocessor and the requirements of the controlled system determine the period. The RTI_interrupt function is a workhorse. It does PID loop PWM duty cycle calculations, performs I/O using the DOIO assembly language function, and checks the results against the usable PWM output range of $00 to $FF. If a floating-point result is out of range, the closest limit is substituted. This "saturation arithmetic" prevents out-of-range results from causing sign-reversals in the PWM output. Details of error-checking and the DOIO subroutine are best understood by looking at the format of the floating-point variables. The four byte format is: SEEEEEEE EMMMMMMM MMMMMMMM MMMMMMMM S represents a sign bit, E represents an 8-bit exponent biased by 127, and M represents a 23-bit fractional mantissa (significand) with an implicit leading 1. The I/O range of $00 to $FF is scaled into the eight most significant bits of a floating-point variable, giving a floating-point range of 1.0 ($3F800000) to 1.998046875 ($3FFF8000). The following expression is used to evaluate a floating-point number: F = [(-1)S] [2(E-127)] [1.M] When the RTI_interrupt function returns control to the C routine, the last task the routine must perform is preparation for the next period. A two-element pipeline of the A/D reading and a four-element error pipeline are updated. Finally the "old" duty cycle value is copied into OLDDTY.
MC68HC11N4 MATH COPROCESSOR
The assembly PID routine uses the MC68HC11N4 math coprocessor, which is commonly referred to as an arithmetic logic unit, or ALU. The ALU performs 32/16-bit division, 16/16 multiplication, multiply-and-accumulate operations, and 16/16-bit fractional division without CPU intervention. As Figure 2 shows, the coprocessor has one control register, one status register, and three data registers. Arrows indicate the most convenient order of writing the registers.
ALU REGISTERS $_040 $_041 $_042 $_043 $_044 $_045 $_046 $_047 $_048 $_049 (CREG HIGH) CREG (CREG LOW) ALUC AREG 8 BITS 16 BITS START DIVISION BREG ALUF 16 BITS 8 BITS START MULTIPLY
AN1215 COPROCESSOR MAP
MAC
MUL
DIV
FDIV
32 BITS
START FDIV
Figure 2 Coprocessor Registers and Operations MOTOROLA 4 AN1215/D
The 8-bit ALU control register (ALUC) controls ALU operation. Table 1 summarizes ALUC bit functions. ALUC -- Arithmetic Logic Unit Control
Bit 7 SIG RESET: 0 6 DIV 0 5 MAC 0 4 DCC 0 3 TRG 0 2 -- 0 1 -- 0 Bit 0 -- 0
$0044
SIG -- Signed Number Enable 0 = AREG, BREG, and CREG contents are unsigned numbers 1 = AREG, BREG, and CREG contents are signed numbers DIV -- Division Enable MAC -- Multiply with Accumulated Product Enable DCC -- Division Compensation for Concatenated Quotient Enable TRG -- Function Start Trigger Bit Always reads zero 0 = No effect 1 = Start ALU Bits [2:0] -- Not implemented Always read zero Table 1 ALUC Bit Function
SIG 0 1 0 1 0 1 1 0 1 1 DIV 0 0 0 0 1 1 1 1 1 1 MAC 0 0 1 1 0 0 0 1 1 1 DCC X X X X X 0 1 X 0 1 FUNCTION Unsigned MUL Signed MUL Unsigned MAC Signed MAC Unsigned IDIV Signed IDIV Signed IDIV DCC Unsigned FDIV Signed FDIV Signed FDIV DCC START TRIGGERS Write BREG or set TRG Write BREG or set TRG Write BREG or set TRG Write BREG or set TRG Write AREG or set TRG Write AREG or set TRG Write AREG or set TRG Set TRG Set TRG Set TRG
The 8-bit ALU status register (ALUF) signals when an operation is complete and indicates the status of the completed operation. ALUF -- Arithmetic Logic Unit Status Flag Register
Bit 7 NEG RESET: 0 6 RZF 0 5 -- 0 4 -- 0 3 -- 0 2 OVF 0 1 DZF 0 Bit 0 ACF 0
$0049
NEG -- Negative Result NEG is set if the result is a negative value. This is a read-only-bit. Writes to this bit do not affect the value. RZF -- Remainder Equals Zero Flag RZF is set if the remainder is zero. Bits [5:3] -- Not implemented Always read zero AN1215/D MOTOROLA 5
OVF -- Overflow Flag OVF is set if overflow from MSB on CREG is detected. This bit is cleared automatically by a write to this register with bit 2 set. DZF -- Divide by Zero Flag DZF is set if a divide by zero condition is detected. DZF is cleared automatically by a write to this register with bit 1 set. ACF -- Arithmetic Completion Flag ACF is set by completion of the arithmetic operation. ACF is cleared automatically by a write to this register with bit 0 set. Data register A (AREG) can hold either a 16-bit multiplicand or a 16-bit divisor. Data register B (BREG) can hold either a 16-bit multiplier or a 16-bit remainder after division. Data register C (CREG), which is treated as two 16-bit registers (CREG High and CREG Low), can hold a 32-bit product or accumulated product after multiplication, or it can hold a 32-bit numerator before division and a 32-bit quotient after division. There is an implied fixed radix point to the right of bits AREG0, BREG0, and CREG0. Table 2 shows numeric ranges of ALU registers. Table 3 shows signed expression of numbers. Table 4 shows fractional numeric representation. Figure 3 shows typical data register formats.
Table 2 Numeric Ranges of ALU Registers
Register AREG BREG CREG Size 16 bits 16 bits 32 bits Unsigned 0 to 65535 0 to 65535 0 to 4,294,967,295 Signed 32,768 to +32,767 32,768 to +32,767 2,147,483,648 to +2,147,483,647
Table 3 Representation of Signed Numbers
Decimal +2,147,483,647 · · +32,767 · · +1 0 1 2 · · 32,768 · · 2,147,483,647 16-Bit Hexadecimal -- -- -- $7FFF · · $0001 $0000 $FFFF $FFFE · · $8000 -- -- -- 32-Bit Hexadecimal $7FFF FFFF · · $0000 7FFF · · $0000 0001 $0000 0000 $FFFF FFFF $FFFF FFFE · · $FFFF 8000 · · $8000 0000
MOTOROLA 6
AN1215/D
Table 4 Representation of Fractions
Decimal +0.99998 · · +0.5 +0.25 +0.125 +0.0625 +0.03125 +0.015625 · · +0.0000153 0.99998 · · 0.5 0.25 0.125 0.0625 0.03125 0.015625 · · 0.0000153 16-Bit Hexadecimal $FFFF · · $8000 $4000 $2000 $1000 $0800 $0400 · · $0001 $0001 · · $8000 $C000 $E000 $F000 $F800 $FC00 · · $FFFF
AN1215/D
MOTOROLA 7
32-BIT SIGNED INTEGER NUMBER 31 S CREG HIGH
16 15 INTEGER CREG 15 S
CREG LOW
0
-2147483648 TO +2147483647 RADIX POINT
SIGN BIT 16-BIT SIGNED INTEGER NUMBER
INTEGER
0
-32768 TO 32767 RADIX POINT
SIGN BIT 16-BIT FRACTION NUMBER AFTER FDIV
AREG or BREG -16
-1
FRACTION
32-BIT SIGNED INTEGER AND FRACTION FOLLOWING AN FDIV 15 S INTEGER CREG HIGH 0 -1
CREG LOW RADIX POINT SIGN BIT IS IN INTEGER PART OR NEG FLAG -16 -32768.99998 TO +32767.99998
0.00000 TO 0.99998
FRACTION
CREG LOW RADIX POINT CREG LONG WORD SIGNED RESULT AFTER FDIV FOLLOWING AN IDIV SIGN BIT 31 S CREG HIGH AFTER IDIV 16 15
CREG LOW AFTER IDIV
0
SIGN BIT 15 S
INTEGER CREG 0 -1
RADIX POINT -16
CREG HIGH AFTER FDIV INTEGER
CREG LOW AFTER FDIV
SIGN BIT
FRACTION RADIX POINT CREG
AN1215 COPROCESSOR REG FORMAT
Figure 3 ALU Data Register Format
ASSEMBLY LANGUAGE IMPLEMENTATION
The assembly language version of the PID control routine consists of a C master program and an assembly subroutine (DOPID) that carries out all time-critical tasks (see Appendix B for a complete listing). The C master program is used for convenience -- DOPID can be made to stand alone with minor changes in variable definition. The constant and variable number representation for the assembly version of the PID loop is a four-byte number consisting of a 16-bit integer, an implied decimal point, and a 16-bit fraction. This representation was chosen to provide relatively high performance while giving enough precision to support MC68HC11N4 8-, 12-, and 16-bit PWM resolutions. Many other formats could be used, each with a particular trade-off between precision and time. MOTOROLA 8 AN1215/D
Although the sampling period constant and the constants of each term of the PID algorithm could be calculated during the assembly phase and set in the final code, these values are instead initialized as ratios of hexadecimal integers, then calculated in real time in the loop. This arrangement allows easy experimentation with these values without reassembling each time a value is changed. The initial format of these values (numerator and denominator) is a consequence of the four-byte numeric representation. Here are some examples of ALU operations performed during PID computation. To perform a signed integer divide followed by a signed fractional divide, the numerator is written to CREG, $C0 is written to ALUC, and the divisor is written to AREG. After the completion flag in ALUF is set ($49), $E8 is written to ALUC. Following integer division, the quotient is in CREG and the remainder is in BREG. Fractional division moves the content of CREG Low to CREG High, then places a 16-bit fraction in CREG Low. The final result is a 16-bit quotient in CREG High and a 16-bit fraction in CREG Low. There is an implicit decimal point between CREG High and CREG Low. More precision can be obtained by concatenating fractional divisions. To perform a signed multiply, $80 is written to ALUC and multiplicands are written to AREG and BREG. When the operation is complete, a 32-bit result is in CREG. The actual range used for control is hexadecimal $0000.0000 to $00FF.FFFF (decimal 0 to 255.99998). While the error term can be positive or negative, PWM output and feedback voltage are always positive. A result greater than $FF is treated as an overflow, and a result less than $00 is treated as an underflow. This effects a saturated value of the correct sign as in the C version. Except for the expression of initial constants as ratios, formula 5 is not changed. In the derivative term the factor (KDNUM / KDDEN) / ((6 (PERDTNUM / PERDTDEN)) is rearranged to ((KDNUM / KDDEN) PERDTDEN) / (6 PERDTNUM). The DOPID routine is written as straight-line code. Only two subroutines and a limit-checking section are shared by the proportional, integral, and derivative terms. The subroutines MULLNG and ADLNG are used to multiply and add terms and factors expressed in the special four-byte format explained previously. Each of the P, I, and D terms use ADLNG to contribute to the new PWM duty cycle (NEWDTY), but, as in the C version of the PID routine, NEWDTY is not output until the beginning of the next period. Only the 8-bit integer portion is used, and the 1-bit round-off error this causes is not corrected -- the effect is negligible in this 8-bit example. After all three terms are calculated, control is returned to the master C routine. The master routine updates the error and A to D pipelines, then enters the main wait loop. During program execution, all results and most intermediate values are kept in RAM, rather than on the stack. Controller state can easily be inspected by means of a single breakpoint and a dump of the appropriate variable address. Variable addresses are provided in the C startup code for the assembly routine -- the addresses are only valid for this compilation and can change with code revision.
HARDWARE PLATFORM
The Motorola M68HC11KMNPEVS Evaluation System can be used to run both versions of the PID routine. With an MC68HC11K4 inserted in the emulator module, only the floating point version will execute. With an MC68HC11N4 inserted, both versions can be executed -- the floating point version simply does not use the math coprocessor. Both versions of the PID routine utilize special test mode in the EVS system. This means that the M68HC11 processor vectors are mapped from $BFD6 to $BFFF instead of from $FFD6 to $FFFF, and can be placed in user RAM or in emulation RAM, making experimentation with varied processor configuration options easier. Refer to the M68HC11KMNPEVS Evaluation System User's Manual for more information. AN1215/D MOTOROLA 9
S-record formatted object code can be loaded and run on the EVS using appropriate serial communications software. The default EVS Baud rate is 19200 Baud. A simple RC circuit is used to provide the feedback necessary for the software PID loop to operate. The connections to the EVS are shown in Figure 4. PH0 is the processor PWM output and PE0 is the channel 1 A/D input. Note that the A/D reference inputs must be connected to appropriate supplies and the SUP6(F(,IRQ)) line must also be tied high. A two-channel oscilloscope can be used to observe PWM output and controlled voltage. Both versions of the code write $FF to PORTA just before performing PID loop calculations and then write $00 to the port just after calculations are complete, allowing execution times to be observed with a scope.
VDD P4 VRH 14 VSS 1 M 0.1 µF VSS VDD 3.8 M VDD 4.7 k P5 7 IRQ
VRL 16 PE0 PH0 18 23
3.8 M VSS
AN1215 K4 EVS TEST SCHEM
Figure 4 Evaluation System Schematic
PERFORMANCE
Since two very different approaches were taken to implement the PID loop algorithm, it is not surprising that the performance and code sizes of the two routines differ significantly. The C language version contains over 1500 bytes, much of which consists of floating point runtime support. Because it carries full floatingpoint precision and does not use math support hardware, the C version takes approximately 6 milliseconds to complete the loop. The assembly version contains approximately 1000 bytes, and could be reduced to about 800 bytes if features added for clarity and experimentation were removed. Because it uses a tailored arithmetic format and gets a hardware assist from the math coprocessor, the assembly version completes the loop in approximately 700 microseconds. In both cases, performance could be improved by precomputing all the results with constant factors.
EXPERIMENTS AND EXTENSIONS
To develop a more intuitive understanding of PID loop function, try varying the term constants in the object code and observing the effect on controller performance. For the C version, it is best to change the values in the C source and recompile. For the assembly version, it is easy to recalculate and change denominators of the constants: only decimal-to-hex conversion is required. The PERDT constant must be changed when the RTI interrupt rate is changed, or the time base of the algorithm will be destroyed. Try adjusting the proportional and derivative constants to give good observable control and then start substituting smaller value resistors for R1. Eventually, the substitution will cause an unstable underdamped system. MOTOROLA 10 AN1215/D
Many extensions to the routines are simple yet interesting. The command voltage level can be read from one of the seven unused A/D channels to give real-time control points. The MC68HC11N4 version could have analog output instead of PWM with the use of an 8-bit D/A channel. The N4 version could also use an infinite impulse response (IIR) filter implemented by means of the math coprocessor multiply-and-accumulate capability, rather than utilizing the noise-canceling effect of the derivative term's four point central difference.
CONCLUSION
With the 16.383 millisecond sampling rate chosen, the floating point C routine cannot service all four MC68HC11K4 PWM channels. It could, however, service one higher-rate channel and several less timecritical processes. The assembly math coprocessor routine can service all the MC68HC11N4 PWM channels (four 8-bit and two 12-bit) in 4.2 milliseconds, leaving 75% of execution time for other tasks. If the MC68HC11N4 D/A channels were also used, six independent PID controllers could be run in 5.6 milliseconds -- this routine would use less than a third of the allowable processing time and require only half of the twelve MC68HC11N4 A/D input channels. The two approaches to PID control outlined in this note encompass a wide range of useful and cost-effective applications. The simplicity of the coded C algorithm is very appealing. Since the C routine carries virtually no code-space overhead, it is very well-suited to an application where floating-point math is already required, and a sampling rate in the 20-millisecond range is acceptable. Because it uses a number format adapted to the application and to use of on-chip resources, the assembly routine generally yields higher, more cost-effective performance than the C routine. A final word of caution. There is no substitute for thorough mathematical analysis of the system to be controlled in the discrete time domain. References 2 and 3 contain detailed discussions of control systems and analytic techniques.
REFERENCES
1. Andrews, Michael. Programming Microprocessor Interfaces for Control and Instrumentation. Prentice Hall; 1982 2. Kuo, Benjamin. Digital Control Systems. Holt, Rinehart and Winston Inc.; 1980 3. 3.Kuo, Benjamin. Automatic Control Systems. Prentice Hall; 1987 4. 4.Motorola. MC68HC11K4 Technical Summary, BR751/D 5. 5.Motorola. MC68HC11N4 Technical Summary, MC68HC11N4TS/D 6. 6.Motorola. M68HC11 Reference Manual, M68HC11RM/AD Rev. 3 7. 7.Motorola. M68HC11K4EVS Evaluation System User's Manual, M68HC11K4EVS/D1
AN1215/D
MOTOROLA 11
APPENDIX A C LANGUAGE PID ROUTINE
A.1 Main C Routine
#include #include #include #include zpage zpage zpage zpage zpage zpage zpage zpage zpage zpage zpage zpage zpage zpage zpage zpage unsigned int float float float float float float float float float float float float float float float TOFCOUNT; CMNDVX; ADRCX; ADRCXM1; ADRCXM2; ADRCXM3; ERRX; ERRM1X; ERRM2X; ERRM3X; PERDT; NEWDTY; OLDDTY; KP; KD; KI; /* declare variables */
extern int
DOIO (void);
/* prototype for assembly routine */
void main() { CMNDVX = 1.5; PERDT = 0.016383; KP = 0.18; KI = 6.0; KD = 0.009; OLDDTY = 1.9; PORTA = 0x00; DDRA = 0xFF; PACTL = 0x03; TMSK2 = 0x40; OPTION = 0x90; PWPER1 = 0xFF; PWDTY1 = 0xFF; PWPOL = 0x01; DDRH = 0x00; PWEN = 0x01; TFLG2 = 0x40; enable_interrupt(); wait_for_interrupt(); for (;;) { ; } }
/* main program */ /* RTI and therefore PID loop period = 16.383 ms */ /* kp = .12, ki = 6.0, kd = .006, for 1 M ohm drive */ /* /* /* /* /* /* /* /* start out with pwm set fairly high */ this will be used for a scope trigger */ set PORTA as output */ set RTI to 16.383 ms (E = 4 MHz) */ enable RTI interrupts */ enable A/D charge pump */ set up PWM channel 1 at 15.625 kHz */ with positive polarity */
/* wait here for RTI to cause loop execution */
interrupt void IRQ_interrupt(void) { PORTA = 0xFF; PORTA = 0x00; } interrupt void TO_interrupt(void) { TOFCOUNT++ ; }
/* should initialize all interrupts... */
MOTOROLA 12
AN1215/D
interrupt void RTI_interrupt(void) { PORTA = 0xFF; DOIO(); ADCTL = 0x10; ERRX = (CMNDVX - ADRCX);
/*PID LOOP/PWM routine */ /* scope strobe */ /* read A to D and output the duty cycle calculated last period */ /* begin new conversion cycle */ /* calculate current error */
/* The statement below is the entire floating point PID loop */ NEWDTY = KP*(ERRX) + KI*PERDT*(CMNDVX - (ADRCX + ADRCXM1)/2) + (KD/(6*PERDT))*((ERRX - ERRM3X) + 3*(ERRM1X - ERRM2X)) + OLDDTY; if (NEWDTY > 1.99609) NEWDTY = 1.99609; else if (NEWDTY < 1.0) NEWDTY = 1.0; TFLG2 = 0x40; ADRCXM1 = ADRCX; ERRM3X = ERRM2X; ERRM2X = ERRM1X; ERRM1X = ERRX; OLDDTY = NEWDTY; PORTA = 0x00; } /* test for result being in usable */ /* limits and set PWM duty cycle if */ /* beyond saturation */ /* clear RTI flag */ /* update A/D result for next cycle */ /* update error pipeline */ /* update old duty cycle for next calculation period */ /* scope strobe */
A.2 DOIO Subroutine Assembler Listing
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 ********************************************************* * DOIO assembly function * * This routine handles the conversion between * * 8 bit register values and the C float variables * * * ********************************************************* 0000 0000 0000 0000 006C 0031 0000 0000 0000 0000 0002 0003 0005 0007 0008 000A 000C 000D 000F 0011 0012 0014 0015 MODULE DOIO PUBLIC DOIO P68H11 RSEG CODE PWDTY1 set ADDR1 set EXTERN EXTERN DOIO: LDAA CLRB STD LDAA LSRD ORAA STD CLRB STAB LDD LSLD STAA RTS END $006c $0031 ADRCX:ZPAGE NEWDTY:ZPAGE #$3F ADRCX ADR1 #$80 ADRCX+1 ADRCX+3 NEWDTY+1 PWDTY1 INITIALIZE FLOAT LOCATION. GET CHANNEL 1 A/D RESULT. SHIFT TO FLOAT MANTISSA POSITION. OR IN LEAST SIGNIFICANT EXP BIT AND STORE IT IN FLOAT VARIABLE. CLEAR LEAST SIGNIFICANT FLOAT BYTE. GET TWO BYTES OF FLOAT MANTISSA. SHIFT TO CORRECT REGISTER POSITION. OUTPUT TO PWM DUTY REGISTER. REGISTER LOCATIONS EXTERNAL VARIABLE LOCATIONS
863F 5F DD00 9631 04 8A80 DD01 5F D703 DC01 05 976C 39
AN1215/D
MOTOROLA 13
APPENDIX B ASSEMBLY LANGUAGE PID ROUTINE
B.1 Master C Routine
/* This code just sets up variables and does some updates after the assembly PID loop is called. */ #include #include #include zpage zpage zpage zpage zpage zpage zpage zpage zpage zpage zpage zpage zpage zpage zpage zpage zpage zpage zpage zpage zpage zpage zpage zpage zpage zpage zpage zpage zpage zpage zpage zpage zpage zpage zpage zpage zpage zpage zpage unsigned int signed int signed int signed int signed int signed int signed int signed int signed int signed int signed int signed int signed int signed int signed int signed int signed int signed int signed int signed int signed int signed int long long long long long long long long long long long long long long long long long DOPID (void); TOFCOUNT; CMNDVX; ADRCX; ADRCXM1; ERRX; ERRM1X; ERRM2X; ERRM3X; KPNUM; KPDEN; KINUM; KIDEN; KDNUM; KDDEN; PERDTNUM; PERDTDEN; INT56; FC56; TEMP1; TEMP2; TEMP3; TEMP4; NEWDTY; OLDDTY; KPTRM; KDTRM; KITRM; LTEMP1; LTEMP2; LTEMP3; LTEMP4; LTEMP5; LTEMP6; LTEMP7; LTEMP8; LTEMP9; LTEMPA; FCINT56; INTFC56; /* declare variables */
extern int
/* prototype for assembly routine */
MOTOROLA 14
AN1215/D
void main() { CMNDVX = 0x0080; PERDTNUM = 0x00A4; PERDTDEN = 0x2710; KPNUM = 0x000C; KPDEN = 0x0064; KINUM = 0x0006; KIDEN = 0x0001; KDNUM = 0x0006; KDDEN = 0x03E8; OLDDTY =0x00FF0000; PORTA = 0x00; DDRA = 0xFF; PACTL = 0x03; TMSK2 = 0x40; OPTION = 0x90; PWPER1 = 0xFF; PWDTY1 = 0xFF; PWPOL = 0x01; DDRH = 0x00; PWEN = 0x01; TFLG2 = 0x40; enable_interrupt(); wait_for_interrupt(); for (;;) { ; } }
/* main program */
/* PERIOD = 164/10000 decimal */ /* kp = .12, ki = 6.0, kd = .006, for 1M ohm drive */
/* /* /* /* /* /*
set PORTA as output */ set RTI to 16.383 ms (E = 4MHz) */ enable RTI interrupts */ enable A/D charge pump */ set up PWM channel 1 at 15.625 kHz */ with positive polarity */
/* wait for RTI to execute assembly PID routine */
interrupt void IRQ_interrupt(void) { PORTA = 0xFF; PORTA = 0x00; } interrupt void TO_interrupt(void) { TOFCOUNT++ ; } interrupt void RTI_interrupt(void) { PORTA = 0xFF; DOPID(); /*
/* Just some traps for unexpected */ /* interrupts */
/* PWM routine */ /* scope strobe */ /*DO THE PID LOOP USING THE MATH COPROCESSOR */
NEWDTY = KP*(ERRX) + KI*PERDT*(CMNDVX - (ADRCX + ADRCXM1)/2) + (KD/(6*PERDT))*((ERRX - ERRM3X) + 3*(ERRM1X - ERRM2X)) + OLDDTY; */ TFLG2 = 0x40; ADRCXM1 = ADRCX; ERRM3X = ERRM2X; ERRM2X = ERRM1X; ERRM1X = ERRX; PORTA = 0x00; /* clear RTI flag */ /* update A/D result for next cycle */ /* update error pipeline */ /* scope strobe */
}
AN1215/D
MOTOROLA 15
B.2 DOPID Assembly Listing
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 **************************************************************** * DOPID assembly function* * These routines calculate the new PWM duty cycle* * using the MC68HC11N4 math coprocessor. The* * code can be run on an M68HC11EVS with an* * M68HC11K4 emulator and MC68HC11N4 processor.* * The EVS monitor should be 1.1 or later. The EVS* * and vectors were set to SPECIAL TEST MODE to aid debug.* * This code is called by a C routine but could be converted* * to an all assembly environment by defining the variables* * in assembly instead of as externals.* **************************************************************** 0000 0000 0000 0000 006C 0030 0031 0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 PWDTY1 ADCTL ADR1 CREGH CREGMH CREGML CREGL ALUC AREGH AREGL BREGH BREGL ALUF MODULE PUBLIC P68H11 RSEG set set set set set set set set set set set set set DOPID DOPID
CODE $006c $0030 $0031 $0040 $0041 $0042 $0043 $0044 $0045 $0046 $0047 $0048 $0049
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
EXTERN EXTERN EXTERN EXTERN EXTERN EXTERN EXTERN EXTERN EXTERN EXTERN EXTERN EXTERN EXTERN EXTERN EXTERN EXTERN EXTERN EXTERN EXTERN EXTERN EXTERN EXTERN EXTERN EXTERN EXTERN EXTERN EXTERN EXTERN EXTERN EXTERN
ADRCX:ZPAGE ADRCXM1:ZPAGE CMNDVX:ZPAGE ERRX:ZPAGE ERRM1X:ZPAGE ERRM2X:ZPAGE ERRM3X:ZPAGE KPNUM:ZPAGE KPDEN:ZPAGE KINUM:ZPAGE KIDEN:ZPAGE KDNUM:ZPAGE KDDEN:ZPAGE PERDTNUM:ZPAGE PERDTDEN:ZPAGE INT56:ZPAGE FC56:ZPAGE TEMP1:ZPAGE TEMP2:ZPAGE TEMP3:ZPAGE TEMP4:ZPAGE KPTRM:ZPAGE KITRM:ZPAGE KDTRM:ZPAGE LTEMP1:ZPAGE LTEMP2:ZPAGE LTEMP3:ZPAGE LTEMP4:ZPAGE LTEMP5:ZPAGE LTEMP6:ZPAGE
$0084 EXTERNAL VARIABLES $0086 SIGNED INTS $0082 $0088 $008A $008C $008E $0090 $0092 $0094 $0096 $0098 $009A $009C $009E $00A0 $00A2 $00A4 $00A6 $00A8 $00AA $00B4 LONGS $00BC $00B8 $00C0 $00C4 $00C8 $00CC $00D0 $00D4
MOTOROLA 16
AN1215/D
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
0000 0000 0000 0000 0000 0000 0000 0000 0000
EXTERN EXTERN EXTERN EXTERN EXTERN EXTERN EXTERN EXTERN
LTEMP7:ZPAGE LTEMP8:ZPAGE LTEMP9:ZPAGE LTEMPA:ZPAGE FCINT56:ZPAGE INTFC56:ZPAGE OLDDTY:ZPAGE NEWDTY:ZPAGE
$00D8 $00DC $00E0 $00E4 $00E8 $00EC $00B0 $00AC
DOPID: ******** OUTPUT LAST PERIOD RESULT AND DO KP TERM ******** 9601 976C 4F D631 DD00 C610 D730 DC00 9300 DD00 2B06 8600 9700 2004 86FF 9700 8680 9744 DC00 DD45 8601 9749 DC00 DD47 134901FC 86C0 DD44 8601 9749 DC00 DD45 134901FC 8601 9749 86E8 DD44 134901FC DC40 DD00 DD00 DC42 DD02 DD02 BD0361 BD007F BD014F DC00 2B0F 1A8300FF 2B10 CC00FF DD00 DD00 2007 CC0000 DD00 DD00 LDAA STAA CLRA LDAB STD LDAB STAB LDD SUBD STD BMI LDAA STAA BRA LDAA STAA LDAA STAA LDD STD LDAA STAA LDD STD BRCLR LDAA STD LDAA STAA LDD STD BRCLR LDAA STAA LDAA STD BRCLR LDD STD STD LDD STD STD JSR JSR JSR LDD BMI CPD BMI LDD STD STD BRA LDD STD STD NEWDTY+1 PWDTY1 ADR1 ADRCX #$10 ADCTL CMNDVX ADRCX ERRX NFLAG1 #$00 TEMP3 NFLGG2 #$FF TEMP3 #$80 ALUC ERRX AREGH #$01 ALUF KPNUM BREGH ALUF,#$01,WPMUL1 #$D0 ALUC #$01 ALUF KPDEN AREGH ALUF,#$01,WPDIV1 #$01 ALUF #$E8 ALUC ALUF,#$01,WPFDV1 CREGH KPTRM LTEMP1 CREGML KPTRM+2 LTEMP1+2 ADLNG DOKIT DOKDT NEWDTY JAMZP #$00FF KXDONE #$00FF NEWDTY OLDDTY KXDONE #$0000 NEWDTY OLDDTY OUTPUT PREVIOUS CALC.
0000 0002 0004 0005 0007 0009 000B 000D 000F 0011 0013 0015 0017 0019 001B 001D 001F 0021 0023 0025 0027 0029 002B 002D 002F 0033 0035 0037 0039 003B 003D 003F 0043 0045 0047 0049 004B 004F 0051 0053 0055 0057 0059 005B 005E 0061 0064 0066 0068 006C 006E 0071 0073 0075 0077 007A 007C
GET CHANNEL 1 A/D RESULT. DO KP TERM FIRST START NEW A/D CONVERSION FORM ERROR TERM SET UP SIGN FLAG IN TEMP3 POS
NFLAG1 NFLGG2
NEG SET ALU FOR SMUL
CLEAR ACF
WPMUL1
TRIGGER SMUL WAIT FOR ACF SET ALU FOR SIDIV CLEAR ACF
WPDIV1
TRIGGER SIDIV WAIT FOR ACF CLEAR ACF TRIGGER SFDIV WAIT FOR ACF GET INT PART OF RESULT
WPFDV1
GET FRACTION
NOW ADD TO OLDDTY DO I TERM, ADD TO OLDDTY DO D TERM, ADD TO OLDDTY CHECK LIMITS
JAM FF SATURATED HIGH
JAMZP
JAM 00 SATURATED LOW
AN1215/D
MOTOROLA 17
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
007E 39
KXDONE
RTS
* ROUTINE TO DO INTEGRAL TERM * 007F DC00 DOKIT LDD ADRCX GET CURRENT CONVERSION 0081 D300 ADDD ADRCXM1 FORM (ADRCX + ADRCXM1)/2 0083 04 LSRD 0084 DD00 STD LTEMP2 0086 2507 BCS JMHAFI 0088 CC0000 LDD #$0000 008B DD02 STD LTEMP2+2 FRACTIONAL PART OF FINAL ERROR 008D 2005 BRA INTKIE TERM WILL ALWAYS BE 0 or 0.5 008F CC8000 JMHAFI LDD #$8000 0092 DD02 STD LTEMP2+2 0094 DC00 INTKIE LDD CMNDVX 0096 9300 SUBD LTEMP2 0098 1302800B BRCLR LTEMP2+2,#$80,NOFCN 009C DD00 STD LTEMP2 009E 1A830000 CPD #$0000 00A2 2F0B BLE NGFLG3 00A4 830001 SUBD #$0001 00A7 DD00 NOFCN STD LTEMP2 CMNDVX - ((ADRCX + ADRCXM1)/2) 00A9 2B04 BMI NGFLG3 SET UP SIGN FLAG IN TEMP3 00AB 8600 LDAA #$00 00AD 2002 BRA NGFLG2 00AF 86FF NGFLG3 LDAA #$FF 00B1 9700 NGFLG2 STAA TEMP3 00B3 86C0 LDAA #$D0 SET ALU FOR SIDIV TO FORM 00B5 DD44 STD ALUC KINUM/KIDEN 00B7 8601 LDAA #$01 CLEAR ACF 00B9 9749 STAA ALUF 00BB CC0000 LDD #$0000 SET UP KI NUMERATOR 00BE DD40 STD CREGH 00C0 DC00 LDD KINUM 00C2 DD42 STD CREGML 00C4 DC00 LDD KIDEN 00C6 DD45 STD AREGH TRIGGER SIDIV 00C8 134901FC WIDIV1 BRCLR ALUF,#$01,WIDIV1 WAIT FOR ACF 00CC 8601 LDAA #$01 CLEAR ACF 00CE 9749 STAA ALUF 00D0 86E8 LDAA #$E8 TRIGGER SFDIV 00D2 DD44 STD ALUC 00D4 134901FC WIFDV1 BRCLR ALUF,#$01,WIFDV1 WAIT FOR ACF 00D8 DC40 LDD CREGH 00DA DD00 STD LTEMP3 00DC DC42 LDD CREGML 00DE DD02 STD LTEMP3+2 00E0 86C0 LDAA #$D0 SET ALU FOR SIDIV TO FORM 00E2 DD44 STD ALUC PERDTNUM/PERDTDEN 00E4 8601 LDAA #$01 CLEAR ACF 00E6 9749 STAA ALUF 00E8 CC0000 LDD #$0000 SET UP PERDTNUM 00EB DD40 STD CREGH 00ED DC00 LDD PERDTNUM 00EF DD42 STD CREGML 00F1 DC00 LDD PERDTDEN 00F3 DD45 STD AREGH TRIGGER SIDIV 00F5 134901FC WIDIV2 BRCLR ALUF,#$01,WIDIV2 WAIT FOR ACF 00F9 8601 LDAA #$01 CLEAR ACF 00FB 9749 STAA ALUF 00FD 86E8 LDAA #$E8 TRIGGER SFDIV 00FF DD44 STD ALUC 0101 134901FC WIFDV2 BRCLR ALUF,#$01,WIFDV2 WAIT FOR ACF 0105 DC40 LDD CREGH 0107 DD00 STD LTEMP4 0109 DC42 LDD CREGML 010B DD02 STD LTEMP4+2 010D DC00 LDD LTEMP3 NOW FORM LTEMP2*LTEMP3*LTEMP4
MOTOROLA 18
AN1215/D
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
010F 0111 0113 0115 0117 0119 011B 011D 011F 0121 0123 0125 0128 012A 012C 012E 0130 0132 0134 0136 0138 013A 013C 013F 0141 0143 0145 0147 0149 014B 014E
DD00 DC02 DD02 DC00 DD00 DC02 DD02 9600 9700 8600 9700 BD023A DC00 DD00 DC02 DD02 9600 9700 DC00 DD00 DC02 DD02 BD023A DC00 DD00 DD00 DC02 DD02 DD02 BD0361 39
STD LDD STD LDD STD LDD STD LDAA STAA LDAA STAA JSR LDD STD LDD STD LDAA STAA LDD STD LDD STD JSR LDD STD STD LDD STD STD JSR RTS *********
LTEMP5 LTEMP3+2 LTEMP5+2 LTEMP4 LTEMP6 LTEMP4+2 LTEMP6+2 TEMP3 TEMP4 #$00 TEMP3 MULLNG LTEMP7 LTEMP5 LTEMP7+2 LTEMP5+2 TEMP4 TEMP3 LTEMP2 LTEMP6 LTEMP2+2 LTEMP6+2 MULLNG LTEMP7 LTEMP1 KITRM LTEMP7+2 LTEMP1+2 KITRM+2 ADLNG
SAVE SIGN FLAG AND USE TEMP3 AS A FLAG FOR LTEMP6 BEING POSITIVE DO LTEMP3*LTEMP4(PERDT*KI) NOW PUT RESULT IN LTEMP5
RETRIEVE SIGN FLAG
ERROR FOR KI TERM
DO RESULT*LTEMP2
ADD KI TERM INTO NEWDTY KITERM DONE RETURN ********** FORM (ERRX - ERRM3X) + 3*(ERRM1X - ERRM2X)
ROUTINE TO DO KD TERM ERRX ERRM3X TEMP1 ERRM1X ERRM2X AREGH #$80 ALUC #$01 ALUF #$0003 BREGH ALUF,#$01,WDMUL0 CREGML TEMP1 LTEMPA NGFLGS0 POSGN #$FF TEMP3 KDFLGD #$00 TEMP3 #$0000 LTEMPA+2 #$00 ALUC #$01 ALUF #$0006 AREGH PERDTNUM BREGH ALUF,#$01,WDMUL1
014F 0151 0153 0155 0157 0159 015B 015D 015F 0161 0163 0166 0168 016C 016E 0170 0172 0174 0176 0178 017A 017C 017E 0180 0183 0185 0187 0189 018B 018D 0190 0192 0194 0196
DC00 9300 DD00 DC00 9300 DD45 8680 9744 8601 9749 CC0003 DD47 134901FC DC42 D300 DD00 2B02 2006 86FF 9700 2004 8600 9700 CC0000 DD02 8600 9744 8601 9749 CC0006 DD45 DC00 DD47 134901FC
DOKDT
LDD SUBD STD LDD SUBD STD LDAA STAA LDAA STAA LDD STD WDMUL0 BRCLR LDD ADDD STD BMI BRA NGFLGS0 LDAA STAA BRA POSGN LDAA STAA KDFLGD LDD STD LDAA STAA LDAA STAA LDD STD LDD STD WDMUL1 BRCLR
FORM 3*(ERRM1X - ERRM2X)
WAIT FOR ACF
SET UP SIGN FLAG IN TEMP3
DONE FORM 6*PERDTNUM
WAIT FOR ACF
AN1215/D
MOTOROLA 19
271 019A DC42 272 019C DD00 273 019E 86C0 274 01A0 DD44 275 01A2 8601 276 01A4 9749 277 01A6 CC0000 278 01A9 DD40 279 01AB DC00 280 01AD DD42 281 01AF DC00 282 01B1 DD45 283 01B3 134901FC 284 01B7 8601 285 01B9 9749 286 01BB 86E8 287 01BD DD44 288 01BF 134901FC 289 01C3 DC40 290 01C5 DD00 291 01C7 DC42 292 01C9 DD02 293 01CB 86C0 294 01CD DD44 295 01CF 8601 296 01D1 9749 297 01D3 CC0000 298 01D6 DD40 299 01D8 DC00 300 01DA DD42 301 01DC DC00 302 01DE DD45 303 01E0 134901FC 304 01E4 8601 305 01E6 9749 306 01E8 86E8 307 01EA DD44 308 01EC 134901FC 309 01F0 DC40 310 01F2 DD00 311 01F4 DC42 312 01F6 DD02 313 01F8 DC00 314 01FA DD00 315 01FC DC02 316 01FE DD02 317 0200 DC00 318 0202 DD00 319 0204 DC02 320 0206 DD02 321 0208 9600 322 020A 9700 323 020C 8600 324 020E 9700 325 0210 BD023A 326 0213 DC00 327 0215 DD00 328 0217 DC02 329 0219 DD02 330 021B 9600 331 021D 9700 332 021F DC00 333 0221 DD00 334 0223 DC02 335 0225 DD02 336 0227 BD023A 337 022A DC00 338 022C DD00
LDD CREGML STD TEMP2 NOFCND LDAA #$D0 STD ALUC LDAA #$01 STAA ALUF LDD #$0000 STD CREGH LDD KDNUM STD CREGML LDD KDDEN STD AREGH WDDIV1 BRCLR ALUF,#$01,WDDIV1 LDAA #$01 STAA ALUF LDAA #$E8 STD ALUC WDFDV1 BRCLR ALUF,#$01,WDFDV1 LDD CREGH STD LTEMP8 LDD CREGML STD LTEMP8+2 LDAA #$D0 STD ALUC LDAA #$01 STAA ALUF LDD #$0000 STD CREGH LDD PERDTDEN STD CREGML LDD TEMP2 STD AREGH WDDIV2 BRCLR ALUF,#$01,WDDIV2 LDAA #$01 STAA ALUF LDAA #$E8 STD ALUC WDFDV2 BRCLR ALUF,#$01,WDFDV2 LDD CREGH STD LTEMP9 LDD CREGML STD LTEMP9+2 LDD LTEMP8 STD LTEMP5 LDD LTEMP8+2 STD LTEMP5+2 LDD LTEMP9 STD LTEMP6 LDD LTEMP9+2 STD LTEMP6+2 LDAA TEMP3 STAA TEMP4 LDAA #$00 STAA TEMP3 JSR MULLNG LDD LTEMP7 STD LTEMP5 LDD LTEMP7+2 STD LTEMP5+2 LDAA TEMP4 STAA TEMP3 LDD LTEMPA STD LTEMP6 LDD LTEMPA+2 STD LTEMP6+2 JSR MULLNG LDD LTEMP7 STD LTEMP1
SET ALU FOR SIDIV TO FORM KDNUM/KDDEN CLEAR ACF SET UP KD NUMERATOR
TRIGGER SIDIV WAIT FOR ACF CLEAR ACF TRIGGER SFDIV WAIT FOR ACF
SET ALU FOR SIDIV TO FORM PERDTDEN/(PERDTNUM*6) CLEAR ACF SET UP PERDTNUM
TRIGGER SIDIV WAIT FOR ACF CLEAR ACF TRIGGER SFDIV WAIT FOR ACF
NOW FORM LTEMPA*LTEMP8*LTEMP9
SAVE SIGN FLAG AND USE TEMP3 AS A FLAG FOR LTEMP6 BEING POSITIVE DO LTEMP8*LTEMP9 NOW PUT RESULT IN LTEMP5
RETRIEVE SIGNED ERROR
ERROR FOR KD TERM
DO RESULT*LTEMPA
MOTOROLA 20
AN1215/D
339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406
022E 0230 0232 0234 0236 0239
DD00 DC02 DD02 DD02 BD0361 39 * * *
STD LDD STD STD JSR RTS
KDTRM LTEMP7+2 LTEMP1+2 KDTRM+2 ADLNG
ADD KD TERM INTO NEWDTY KDTERM DONE * * *
SUBROUTINE TO MULTIPLY LONGS(INTEGER & FRACTION) LTEMP5*LTEMP6=LTEMP7 ONLY LTEMP6 CAN HAVE A NEGATIVE TERM TO HANDLE. #$80 ALUC LTEMP5 AREGH #$01 ALUF LTEMP6 BREGH ALUF,#$01,WMULL1 CREGML INT56 #$01 ALUF #$80 TEMP3 NEGFRAC LTEMP6+2 BREGH ALUF,#$01,WMULL2 CREGH INTFC56 CREGML INTFC56+2 NXFRAC #$0000 LTEMP6+2 BREGH ALUF,#$01,WMULL3 #$0000 CREGH INTFIX1 INTFIX2 #$0001 INTFC56 #$0000 CREGML INTFC56+2 #$00 LTEMP5+2 AREGH #$01 ALUF #$00 LTEMP6 BREGH ALUF,#$01,WMULL4 #$80 TEMP3 DFXINT #$80 AREGH FXINT DFXINT #$0000 CREGH CREGH CREGH
023A 023C 023E 0240 0242 0244 0246 0248 024A 024E 0250 0252 0254 0256 0258 025A 025C 025E 0260 0264 0266 0268 026A 026C 026E 0271 0273 0275 0279 027C 027E 0280 0282 0285 0287 028A 028C 028E 0290 0292 0294 0296 0298 029A 029C 029E 02A2 02A4 02A6 02A8 02AA 02AC 02AE 02B0 02B3 02B5 02B7
8680 9744 DC00 DD45 8601 9749 DC00 DD47 134901FC DC42 DD00 8601 9749 8680 9500 2B12 DC02 DD47 134901FC DC40 DD00 DC42 DD02 2022 CC0000 9302 DD47 134901FC CC0000 9340 2B02 2003 C30001 DD00 CC0000 9342 DD02 8600 DC02 DD45 8601 9749 8600 DC00 DD47 134901FC 8680 9500 2A0F 8680 9545 2B02 2007 CC0000 9340 DD40 DC40
LDAA STAA LDD STD LDAA STAA LDD STD WMULL1 BRCLR LDD STD LDAA STAA LDAA BITA BMI LDD STD WMULL2 BRCLR LDD STD LDD STD BRA NEGFRAC LDD SUBD STD WMULL3 BRCLR LDD SUBD BMI BRA INTFIX1 ADDD INTFIX2 STD LDD SUBD STD LDAA NXFRAC LDD STD LDAA STAA LDAA LDD STD WMULL4 BRCLR LDAA BITA BPL LDAA BITA BMI BRA FXINT LDD SUBD STD DFXINT LDD
MULLNG
SET ALU FOR SMUL AND MULTIPLY INTS
CLEAR ACF
TRIGGER SMUL WAIT FOR ACF
CLEAR ACF AND DO NEXT MULT TEST TEMP3 SIGN SEE IF ERR IS NEG TERM IS NEGATIVE GET FRAC NOT NEG TRIGGER SMUL WAIT FOR ACF SCALE AND STORE
NEGATE FRAC TRIGGER SMUL WAIT FOR ACF NEGATE RESULT SCALE AND STORE
GET FRAC AND MULTIPLY WITH POSSIBLE NEG INT CLEAR ACF
TRIGGER SMUL WAIT FOR ACF
SEE IF SIGN OVERFLOW ON FRACTION
THIS SCALES FRAC
AN1215/D
MOTOROLA 21
407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474
02B9 02BB 02BD 02C0 02C2 02C4 02C6 02C8 02CA 02CC 02CE 02D0 02D2 02D4 02D6 02D8 02DC 02DE 02E0 02E2 02E5 02E7 02E9 02ED 02F0 02F2 02F4 02F6 02F8 02FA 02FC 02FE 0300 0302 0304 0306 0308 030A 030B 030E 0310 0312 0313 0315 0317 0319 031B 031E 0320 0322 0324 0327 0329 032B 032E 0330 0332 0335 0337 0339 033B 033D 033F 0341 0342 0345 0347 0349
2B02 2003 C30001 DD00 DC42 DD02 8601 9749 8600 9744 8680 9500 2B0E DC02 DD47 134901FC DC40 DD00 2012 CC0000 9302 DD47 134901FC CC0000 9340 DD00 DC00 D300 D300 DD00 8680 9500 2B22 DC02 D302 2502 2009 8F CC0001 D300 DD00 8F D300 DD02 2502 2045 CC0001 D300 DD00 203C CC0000 9302 DD02 CC0000 9302 DD02 CC0000 9300 DD00 DC02 D302 2502 2009 8F CCFFFF D300 DD00 8F
BMI BRA NFFIX ADDD PFFIX STD LDD STD LDAA STAA LDAA STAA LDAA BITA BMI LDD STD WMULL5 BRCLR LDD STD BRA NFCFRAC LDD SUBD STD WMULL6 BRCLR LDD SUBD STD SUMMUL LDD ADDD ADDD STD LDAA BITA BMI LDD ADDD BCS BRA FCCAR1 XGDX LDD ADDD STD XGDX SUMFC1 ADDD STD BCS BRA FCCAR2 LDD ADDD STD BRA SUMNFC LDD SUBD STD LDD SUBD STD LDD SUBD STD LDD ADDD BCS BRA FCCAR3 XGDX LDD ADDD STD XGDX
NFFIX PFFIX #$0001 FCINT56 CREGML FCINT56+2 #$01 ALUF #$00 ALUC #$80 TEMP3 NFCFRAC LTEMP6+2 BREGH ALUF,#$01,WMULL5 CREGH FC56 SUMMUL #$0000 LTEMP6+2 BREGH ALUF,#$01,WMULL6 #$0000 CREGH FC56 INT56 FCINT56 INTFC56 LTEMP7 #$80 TEMP3 SUMNFC FCINT56+2 INTFC56+2 FCCAR1 SUMFC1 #$0001 LTEMP7 LTEMP7 FC56 LTEMP7+2 FCCAR2 SMFCDP #$0001 LTEMP7 LTEMP7 SMFCDP #$0000 FCINT56+2 FCINT56+2 #$0000 INTFC56+2 INTFC56+2 #$0000 FC56 FC56 FCINT56+2 INTFC56+2 FCCAR3 SUMFC2 #$FFFF LTEMP7 LTEMP7
NOW DO FRAC*FRAC CLEAR ACF SET UNSIGNED MULT FOR FRACS TEST ERR SIGN SEE IF ERR IS NEG TERM IS NEGATIVE GET FRAC NOT NEG TRIGGER SMUL WAIT FOR ACF SCALE AND STORE
NEGATE FRAC TRIGGER SMUL WAIT FOR ACF NEGATE RESULT SCALE AND STORE NOW SUMM ALL PRODUCTS INTS ARE ALL SIGNED CAN JUST ADD UP TEST ERRX SIGN SEE IF FRACS ARE NEG FRACS ARE NEGATIVE POSITIVE
SAVE SUM ADD CARRY INTO INT
RETRIEVE SUM
ADD CARRY INTO INT
COMPLEMENT NEG FRACS
NEGATIVE REMEMBER SIGN BIT!! SAVE SUM ADD BORROW INTO INT
RETRIEVE SUM
MOTOROLA 22
AN1215/D
475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520
034A 034C 034E 0350 0352 0355 0357 0359 035C 035E 0360
D300 DD02 2502 2007 CCFFFF D300 DD00 CC0000 9302 DD02 39
SUMFC2
FCCAR4
SMFCDN
SMFCDP
ADDD STD BCS BRA LDD ADDD STD LDD SUBD STD RTS
FC56 LTEMP7+2 FCCAR4 SMFCDN #$FFFF LTEMP7 LTEMP7 #$0000 LTEMP7+2 LTEMP7+2
ADD BORROW INTO INT
CONVERT BACK TO NEG
* SUBROUTINE TO ADD INTEGER AND FRACTION IN LTEMP1 TO OLDDTY * 0361 0363 0365 0367 0369 036B 036D 036F 0371 0373 0375 0377 037A 037C 037E 0380 0382 0384 0386 0388 038A 038C 038E 0391 0393 0395 0397 0399 039B 039D 039E 8680 9500 2B19 DC00 D300 DD00 DC02 D302 DD02 2502 201E CC0001 D300 DD00 2015 DC00 D300 DD00 DC02 D302 DD02 2507 CCFFFF D300 DD00 DC00 DD00 DC02 DD02 39 LDAA BITA BMI LDD ADDD STD LDD ADDD STD BCS BRA INCINT LDD ADDD STD BRA KXNEG LDD ADDD STD LDD ADDD STD BCS DECINT LDD ADDD STD ADDONE LDD STD LDD STD RTS END ######### # DOPID # ######### ADLNG #$80 TEMP3 KXNEG LTEMP1 OLDDTY NEWDTY LTEMP1+2 OLDDTY+2 NEWDTY+2 INCINT ADDONE #$0001 NEWDTY NEWDTY ADDONE LTEMP1 OLDDTY NEWDTY LTEMP1+2 OLDDTY+2 NEWDTY+2 ADDONE #$FFFF NEWDTY NEWDTY NEWDTY OLDDTY NEWDTY+2 OLDDTY+2 TEST ERRX SIGN TERM IS NEGATIVE GET INT PART ADD AND STORE INT GET FRAC PART ADD AND STORE FRAC
ADD CARRY FROM FRAC
GET INT PART ADD AND STORE INT GET FRAC PART ADD AND STORE FRAC ACTUALLY A SUBTRACTION SUBTRACT BORROW FROM FRAC
UPDATE OLDDTY FOR NEXT TERM OR FINISH
RETURN TO CALLING ROUTINE
Errors: Bytes: CRC:
None 926 EC21
AN1215/D
MOTOROLA 23
Motorola reserves the right to make changes without further notice to any products herein. Motorola makes no warranty, representation or guarantee regarding the suitability of its products for any particular purpose, nor does Motorola assume any liability arising out of the application or use of any product or circuit, and specifically disclaims any and all liability, including without limitation consequential or incidental damages. "Typical" parameters can and do vary in different applications. All operating parameters, including "Typicals" must be validated for each customer application by customer's technical experts. Motorola does not convey any license under its patent rights nor the rights of others. Motorola products are not designed, intended, or authorized for use as components in systems intended for surgical implant into the body, or other applications intended to support or sustain life, or for any other application in which the failure of the Motorola product could create a situation where personal injury or death may occur. Should Buyer purchase or use Motorola products for any such unintended or unauthorized application, Buyer shall indemnify and hold Motorola and its officers, employees, subsidiaries, affiliates, and distributors harmless against all claims, costs, damages, and expenses, and reasonable attorney fees arising out of, directly or indirectly, any claim of personal injury or death associated with such unintended or unauthorized use, even if such claim alleges that Motorola was negligent regarding the design or manufacture of the part. M is a registered trademark of Motorola, Inc. Motorola, Inc. is an Equal Opportunity/Affirmative Action Employer.
TO OBTAIN ADDITIONAL PRODUCT INFORMATION:
USA/EUROPE: JAPAN: HONG KONG: MFAX: INTERNET: Motorola Literature Distribution; P.O. Box 20912; Phoenix, Arizona 85036. 1-800-441-2447 Nippon Motorola Ltd.; Tatsumi-SPD-JLDC, Toshikatsu Otsuki, 6F Seibu-Butsuryu-Center, 3-14-2 Tatsumi Koto-Ku, Tokyo 135, Japan. 03-3521-8315 Motorola Semiconductors H.K. Ltd.; 8B Tai Ping Industrial Park, 51 Ting Kok Road, Tai Po, N.T., Hong Kong. 852-26629298 [email protected] - TOUCHTONE (602) 244-6609 http://www.mot.com