Você está na página 1de 64

An Application of the Low Cost Hitachi SH-1 RISC Controller for

PID Control of a Three-Phase Brushless DC Motor System


Ken Schultz
Hitachi America, Ltd.
9/1/97, Preliminary V0.1
1.0 Summary
Hitachis SH RISC family combines the computational ability of a high speed RISC core with
embedded Multiply-Accumulate hardware and extensive on-board peripheral function to enable a
virtual single chip PID controller. The function provided rivals the capability of low-end DSPs
while providing conventional microcontroller addressability, built-in memory and timer functions.
This paper describes basic DC motor theory of operation, the concept of Sine Wave PWM, and
derives a basic PID algorithm suited for use in a computer system. In addition, it provides
application software adapted to Hitachis 7034 RISC controller. The application code provided
cycles the PID algorithm on 500 usec intervals implementing speed control PID and current
control PID using a two-directional vector current model.
This paper was written using Hitachis Servo Control Demonstration Platform as a reference
along with material gathered from Brushless Servomotors Fundementals and Applicatons by
Yasuhiko Dote and Permanent Magnet Motor Technology by Jacek F. Gieras.

1.1 Table of Contents


2.0 Basic Motor Concepts

3.0 Three-Phase Rotating Fields and Sine Wave PWM ...

4.0 Adaptive Control Algorithms

5.0 Motor Control Using the Hitachi SH-1


5.1 The Hitachi Integrated Timer Unit
5.2 The Two-Directional Current Model for Three-Phase Current

11
13
16

6.0 SH/7034 Code Example ..


6.1 PID.h
6.2 7032.h .
6.3 Vect.asm .. ..
6.4 Init.c .
6.5 Initsct.c
6.6 Sect.asm .
6.7 Main.c ..
6.8 PID.map ..

18
19
22
34
38
36
39
40
54

2.0 Basic Motor Concepts


Before diving into the computational aspects of motor control, lets review a few basic concepts of
motor operation. As a prelude to introducing rotating fields, the following paragraphs will discuss,
1. The basic DC motor
2. The basic AC motor
3. The brushless servo motor
If youre familiar with basic motor theory, you may want to skip these elementary sections.
Figure 1 diagrams a basic single pole DC motor. In this example, two magnets are aligned such
that their north and south poles are opposing. Magnetic flux flows from north to south,
consequently the north pole of one magnet is attracted to the south pole of the other. In the gap
between these magnets, which has magnet flux flowing north to south, we have placed a loop of
wire.
Remember that whenever a current flows through a wire, a magnetic field is produced which
rotates around the wire. The direction of the magnetic field depends upon the direction of the
current and can be determined using Flemings Left Hand Rule. This is to say that if you were to
point your left thumb in the direction current is flowing, the remaining fingers on your left hand will
naturally tend to circle around your thumb in the same direction the magnetic field encircles the
wire.
In figure 1, we use a DC power source to produce a current. Notice that the loop of the wire
causes the current to flow in one direction as it passes along the North pole of one magnet and in
the opposite direction as it passes by the south pole of the other magnet. The magnetic field,
produced by the current flow, generates torque against the magnetic field of the permanent
magnet as defined by the Lorentz force in equation 2.1.

Figure 1

dT = RI dl X B

(2.1)

dT = the differential torque


R = the radial distance from the current source
I = the current
dl = the differential length of wire
B = the magnetic field produced by the permanent magnet
Please note that the torque is function of the cross product of the magnetic field from the wire and
magnet. Maximum torque is produced when these are orthogonal and reduces to zero as the
angle changes.
In our example, figure 1, the magnetic field of the wire is initially orthogonal to the field of the
magnet and the Lorentz force pushes the wire in a counter clockwise direction. The torque
continually reduces until the wire has rotated 90o and the cross product has become zero.
Fortunately, momentum continues the rotation past this point, allowing commutation to occur.
Notice that the connection of our wire to the DC power source is done through a set of brushes
and commutators. As our shaft passes through the 90o point, the commutators reverse the
direction of current. To appreciate this effect, consider again the cross product defined in
equation 2.1. At our starting point, the two magnetic fields were orthogonal. As the shaft rotated,
we reached the point equivalent to sin 180o where the force reduced to zero. As we travel past
this point, the Sine function would become negative and, in fact, the force would drive the shaft
back in the clockwise direction. Since the commutators reverse the direction of the current, they
also reverse the direction of the magnetic field, setting us back 180o and allowing the Lorentz
force to continue driving the shaft counter clockwise. This process occurs every 90o to keep the
applied force continually driving the shaft.
The motor shown in figure 1 is a single phase, single pole motor. Its single phase because we
only use a single wire and single pole since there is a single set of magnets. In practice, DC
motors employ multiple magnets, phases, and respective commutators to keep the torque high at
all angles of shaft rotation.

Figure 2
3

Now that weve discussed the basic DC motor, lets consider a variation as shown in figure 2. In
this case, weve replaced the DC power source with an AC power source and eliminated the
commutators all together. Brushes are still used to connect the stationary power source to the
rotating shaft. Remembering the Lorentz force from equation 2.1, the force produced remains a
function of the cross product of magnetic fields. In this case, however, the changing current
produced by the AC power source does the job of the commutators in the DC motor.
This brings us to an important difference between DC and AC motors. The Lorentz force
generated in each motor depends upon the two magnetic fields. By increasing the current in the
wire of figure 1, we can increase its magnetic field to produce more force. More force means
faster rotation. Thus, the speed of a DC motor is a function of the DC voltage applied. Although
it is true that the voltage supplied by the AC power source of figure 2 will affect the force
produced and how quickly the shaft rotates, the frequency of the AC source also plays a role. In
general, the speed of an AC motor is a function of the frequency of the AC power source unless
the applied power or load on the motor is not sufficient to drive the motor at the given AC
frequency. In this case, the AC frequency will become a multiple of the rotating frequency. Thus,
it is possible to input 100 Hz to obtain 25, 50, 75, or 100 RPS.
You may have noticed that all motors we have discussed so far use brushes to produce rotation.
Brushless motors result from a simple variation of the AC motor shown in figure 2. In this case,
the permanent magnet is attached to the rotor and the wire becomes part of the stator as shown
in figure 3. Again, an AC power source is used to produce a constantly varying magnetic field in
the stationary wire and the Lorentz force drives the magnet around the shaft. Note that this
brushless motor could not have been produced using the DC approach due to the dependency
on rotating commutators.
The brushless servomotor has a number of distinct advantages over conventional motors:
1. They have higher maximum speed and greater capacity.
2. They can be used in less favorable environments.
3. They require less maintenance.
4. They produced less noise.

Figure 3
4

3.0 Three-Phase Rotating Fields and Sine Wave PWM


Now that weve discussed basic motor concepts, lets consider the implementation of motors in
the real world. The most common types of brushless servomotors found are stepping motors,
induction synchronous motors, induction reluctance motors, DC brushless synchronous motors,
and vector-control induction motors. These are typically built with a widely varying number of
magnetic poles and phases. For the remainder of this paper, we will focus on the three phase
brushless DC synchronous motor. Three phase motors are the most common since they provide
a relatively even amount of torque at all shaft angles and require few switching elements.
Consider the motor diagrammed in figure 4. In this case, we are looking into the top of the motor
and can see a single magnet attached to a rotating shaft, which goes into the page. Around the
magnet are three separate sets of windings that also travel in and out of the page. These are
windings U, V, and W denoted by symbols U+, U-, V+, V-, W+, W- respectively. Again, the
magnet field of the permanent magnet travels from north to south. When the shaft is positioned
as in figure 4a, the alternating current driven into each of the three phases is as shown at point A
in figure 4c. Note that the phase U is wound in the opposite direction of phases V and W.
Consequently, positive voltage on phase U results in current into the page at the twelve oclock
position of figure 4a while negative voltage results in the same for phases V and W.

Figure 4
5

When voltages are applied as in point A of figure 4c, magnetic flux generated as is shown in
figure 4a is orthogonal to the flux of the magnet. The motor is driven clockwise. By the time the
motor has rotated 60o, as shown in figure 4b, the applied sinusoidal voltages have also changed
as shown at point B in figure 4c. Once again, remember that the direction of winding for phases
U and W are reversed, so the composite flux continues to drive the shaft clockwise. Thus, by
generating three sinusoidal voltages, each 60o out of phase, the motor turns continuously.
At this point, you may be wondering why we call them DC Brushless motors when we continually
refer to AC power sources. Although it is true that an AC current must be produced to make
these motors operate, it is quite possible to produce the AC current using DC voltages. In fact, it
is possible to produce both positive and negative current using only positive DC voltage. We
accomplish this using elementary physics and clever wiring.
First, let us consider that the windings we have discussed in these motors are, in reality, large
inductors. Basic physics tells us that the current in an inductor can not be instantaneously
changed. Thus, if we apply a voltage as a step function, the current flowing through the inductor
will rise steadily as energy is stored in the inductor. If the voltage is applied long enough, current
will stabilize following Ohms Law, V=IR.
Likewise, if we shut off the voltage instantly, the current flow through the inductor will not drop to
zero instantly. Rather, energy stored in the inductor will continue to produce a current that
decays to zero. Now, consider what would happen if the voltage were turned on and off at a rate
which greatly exceeded the time constant of the inductor. By controlling the rate of this switching,
we can control the current flow through the inductor. For a DC brushless motor, this is done
using pulse width modulation (PWM).

Figure 5
Figure 5 shows a current sine wave, which we would like to create using only a DC voltage. For
the moment, lets consider this sine wave to have a peak current of Icc and minimum of zero.
Well worry about producing negative current later. Superimposed over the sine wave in figure 5
is a much higher frequency triangular chopping wave. Following Shannons sampling theorem,
this chopping wave has a minimum frequency of twice the sine wave frequency, but in practice
the chopping wave or carrier frequency is ten to thirty times the sine wave frequency.
Each time the rising chopping wave intersects the sine wave, voltage is applied to the inductor
(PWM on) and each time the falling chopping wave intersects the sine wave, voltage is turned off.

As shown in figure 5, DC voltage is applied for continuously increasing amounts of time as we


build up current in the inductor and decreasing amounts of time as we allow it to dissipate. This
method of producing a sinusoidal current in an inductor using DC voltage is known as Sine Wave
PWM.
OK, we know how to produce a sinusoidal, unidirectional current using PWM. Lets look at how
this practice is applied to a real motor to produce both positive and negative currents. Getting
back to our three-phase motor, consider the diagram shown in figure 6. The Y-connected threephase motor is among the most common found in use today. Once again, there are three
separate windings (U, V, and W), however, they are each connected at a single point. We also
connect a switch block as shown in figure 6 to the other side of these coils. Each of these
switches are driven with Sine Wave PWM. In actual practice, these switches are IGBTs
(Insulated Gate Bipolar Transistors) connected to a high voltage power source. The PWM unit
drives the base of each IGBT using low power, low voltage signals.
If switch 1 and 2 of figure 6 are both closed, then current will flow from point A to point B,
producing positive current in winding U and negative current in winding V. The arrow marked 1 in
figure 6 illustrates this current flow. Likewise, if switch 1 remains closed while switch 2 is opened
and switch is 6 is closed, negative current flows through winding W. There is one guiding
principle in this arrangement. No two opposing switches (S1/S4, S5/S2, S3/S6) can be closed at
the same time or a short will be produced. Referring back to figure 5, we can see that two PWM
signals which are complementary and control a pair of switches such as S1 and S4, we can
produce both positive and negative sinusoidal current using only positive DC voltage.
Ultimately, we drive this motor by using Sine Wave PWM to produce three sets of sinusoidal
signals on switches S1, S3, and S5. These, of course, are 60o out of phase respectively. The
remaining switches (S2, S4, and S6) are driven with three sets of sinusoids, which are 180o out of
phase with their respective pairs. Due to the implementation of Sine Wave PWM, this can be
accomplished by simply driving any of switches S2, S4, or S6 with the inverse of the value
applied to its opposite (S1, S3, and S5). We call this complementary PWM.

Figure 6

4.0 Adaptive Control Algorithms


Now that weve considered the control signals which make a DC brushless motor turn, lets
consider the problem of controlling that motion. One problem the system designer faces is that
load on the motor is subject to change. Furthermore, age, calibration, and environment can have
an effect on the motors operation. Previously, we learned that the speed of the motor was a
function of the applied sine wave frequency and the power delivered by that sine wave. It may
seem reasonable to assume, then, that by knowing the amount of power required to turn a given
motor at a given speed, the system designer can determine exactly what type of control signal to
generate. Consider, however, the case of a motor connected to a spinning drill bit. When the drill
bit touches a surface, the operating conditions change.

Figure 7
Consequently, feedback mechanisms are typically employed to control motor speed. The classic
algorithm used for this purpose is shown is figure 7, the Proportional-Integral controller. In this
case, a reference signal, r(n) is generated to indicate the desired motor speed. For the sake of
this example, lets assume that signal is a numerical value related to the motor speed in RPS.
The reference signal is fed to a control unit which, in turn, produces the sinusoid, u(t), sent to the
motor. The actual motor speed, which may change based upon load, is measured by some
sensor which produces a numerical value on the same scale as r(n).
The Proportional-Integral Controller is described by
U(i) = Kp(Ri-Yi) + KI
Kp
Ki

i
j=0(Rj-Yj)

4.1

is the proportional gain


is the differential gain

The control unit considers two things in determining the signal to be applied to the motor next. A
proportional term considers only the difference between the present reference value and the
actual speed being measured. This term is weighted by a gain factor, Kp, derived using
knowledge of the specific motor under control.
The integral term considers the summation of all the error that has been measured previously.
This term serves to smooth out oscillations by damping the system. Consider, for example, the

case when the system measures the speed to be slightly less than the desired speed. The
proportional term would resolve to increase the applied power, speeding up the motor. If
however, the last several measurements had been showing the motor to be too fast (in other
words, we were slowing), the integral term would reduce or even prevent the introduction of more
power. In addition to this, the Integral term eliminates accumulated error. Since the amount of
energy introduced by the proportional term is proportional to the amount of error (how far the
motor speed is from the desired speed), its influence becomes very small when the motor is
close to the desired frequency. A very small error which has existed for many iterations of the
PID loop, however, will accumulate in the Integral term and produce a control change to correct
that error.
A third control term can be added to this equation, producing the Proportional-Integral-Derivative
algorithm or PID. The derivative term considers the rate at which the error is changing and helps
to improve settling time. One way to grasp the effect of the differential term is to imagine the
difference between a motor which is far from its target speed and one which is close. When the
motor is far below its target speed, we would like to accelerate at a maximum rate. If the rate at
which the motor accelerates is constant, then so too will be the rate at which the error changes
(i.e. the differential term). So, we would like to see the differential term increase to some constant
value. When we approach the target speed, wed like to begin reducing the rate at which the
motor is increasing its speed to prevent us from overshooting. In this case, wed like to see the
differential term decrease to zero. The full PID algorithm can be described by the equation:
u(t) = Kpe(t) + Ki eiT + Kd(de/dt)

4.2

Here,
Kp, Ki and Kd
T
e(t)

are gain factors for each of the three terms and are associated
with the motor's physical properties
is the sampling interval
is the error signal and equal to the difference between the target
speed and the measured speed

Notice that the integral term is described in discrete form as the summation of error terms,
measured at each sampling interval. Using a similar method, the differential term can be
discretely approximated as:
de/dt = (en - en-1 ) / T

4.3

Here en and en-1 are error signals calculated from the current and previous measurements.
This allows the analog PID algorithm to be approximated in discrete form as:
u(n) = Kpe(n) + Ki eiT + Kd[e(n) - e(n-1)] / T

4.4

In a control system, it is normally more important to know the change in control from interval to
interval, rather than the control signal itself. Thus, using induction, we can compute the control
signal for the (n-2)th interval as:
u(n-2) = Kpe(n-2) + Ki n-2 eiT + Kd[e(n-1) - e(n-2)] / T

4.5

This can be subtracted from the nth interval to determine the change in control signal. The
difference may be expressed as:
u(n) = u(n-1) + K1e(n) + K2e(n-1) + K3e(n-2)

4.6

where the constants,


K1 = Kp + Kd / T + KiT
K2 = Ki T - 2Kd / T
K3 = Kd / T - Kp

are predetermined using one of several methods which take into account knowledge of the
unique physical system.
Implementing the PID algorithm on a digital controller allows the user to also implement adaptive
control. This is to say that the constants (K1, K2, and K3) can be dynamically modified to
improve the response of the system. For example, a given motor may be known to have a
different response to a given amount of power at one speed compared to another or under a
specific kind of load. In addition, completely different types of algorithms can be implemented by
reprogramming the controller. Deadbeat and Optimal controllers are sometimes used to meet
specific criteria. The Deadbeat control algorithm provides a very quick settling time, which comes
at the cost of a large overshoot. Optimal algorithms seek trade-offs for specific performance and
cost criteria.
Lastly, we should consider that there are many ways to gather information about the system
under control. Conceptually, the simplest is to produce an optical pulse train, which is
proportional to the speed of the motor. We could, however, choose to measure the back EMF.
Remember that in a three phase Y-connected motor, two of the loops are active at any given time
and one is idle. Back EMF is the amount of voltage generated across the idle winding and is
produced by the magnet moving over it. By measuring back EMF we can determine the speed
of the motor. We may also choose to measure the current flowing in the motor windings and
make adjustments to produce Sine Wave PWM. This information may also become an input fed
back to the control algorithm. In the next section, we will look at an algorithm implemented on
Hitachis SH-1 processor using both speed and current measurements to control a three-phase
motor.

10

5.0 Motor Control Using the Hitachi SH-1


When it comes to implementing our motor control system three basic things need to be done.
First, we must be able to generate the PWM control signals that allow us to drive the motor.
Secondly, we must have a mechanism for gathering data about the current state of the motor.
Finally, we must have enough processing bandwith left over to execute a control algorithm such
as PID. Historically, DSPs have been used to execute the control algorithm. This is largely due
to the multiply-accumulate requirements of the integrating portion of the algorithm. Unfortunately,
DSPs arent known for their wealth of on-board peripherals enabling PWM signal generation.
Hitachis SH 7000 series is ideally suited for motor control functions for the following reasons:
1. On-board ITU can generate PWM including three phase complementary PWM.
2. Buffered ITU channels eliminate timing considerations during PWM updates.
3. On-board MAC unit allows for high speed PID calculation.
4. Phase counting mode of ITU simplifies speed and direction calculation.
5. Built-in A/D allows for back EMF or motor current measurements.
The SH 7000 family includes the SH/7020, SH/7021, SH/7032, and SH/7034 which have varying
amounts of on-board memory and optionally include A/D function. Each of these contains a five
channel ITU and operates up to 20 MHz. The SH-2 category includes the SH/704x devices.
These higher performance devices add on-board cache, 33 MHz operation, an enhanced 6
channel ITU and larger amounts of on-board memory. Any of these can implement a basic PID
well. Sticking with the lowest common denominator, we shall focus the remainder of this paper
on the SH/7034. Code that we generate for the SH/7034 may be ported to the other devices in
this family.
The physical system described in this application is patterened after a servo control
demonstration system produced by Hitachi, Ltd. The software written for that demonstration
system was used as a basis for developing the software presented here, however, this system
omits functions for keypad entry and LED display. A basic block diagram of our system is shown
in figure 8 and consists of the following:
1. SH-1 7034
20 MHz operation
On-board ITU for PWM generation
On-board A/D for current detection
Manufacturer: Hitachi, Ltd.
2. Power Supply
100 VAC Input
200 VAC Output
550 VA Output Power
Manufacturer: Sanyo Electric
3. IGBT Switch Block
200 V Input
1.5 A Output current
Manufacturer: Hitachi, Ltd. J100-002LF
4. Induction Motor
25 W Output Power
1.9 kgf-cm rated torque
3.0 kgf-cm starting torque
1300 RPM rated rotational speed
250 mA rated current

11

Manufacturer: Japan Servo Co. IH8S25-27


5. Optical Detector
5 VDC output
2 phase output
1024 Pulses/revolution
Manufacturer: Copal Electronics Co. RE38-1024-211-1
6. Current Detector
5 VDC output
Hall effect type
Manufacturer: URD Corporation HCS-10-SC
Following the block diagram presented in figure 8, the SH/7034 generates three-phase
complementary PWM using channels three and four of its internal Integrated Timer Unit (ITU).
These control signals are fed to an IGBT switch block connected to an induction motor. The
motor is fitted with a disk containing 1,024 slots. An optical detector detects the spinning of this
disk at two points and feeds the resulting pulse train back to channel 2 of the ITU. These two
signals allow the SH/7034 to determine the direction, position, and speed of the rotating shaft.
Finally, two Hall Effect sensors measure current flow in the U and V coils of the motor. Since
driving the motor ultimately requires the production of sinusodial currents in each coil, this
information is used to determine the PWM duty cycle necessary. The SH/7034 on-board A/D unit
evaluates outputs of the Hall Effect sensor.
An important aspect of performing motor control is the ability to generate PWM and determine
motor speed and position with little processor overhead. The next section discusses the basic
methodology used by the Hitachi ITU to perform these tasks. After this, we will consider the
mathematics behind the derivation of Sine Wave PWM from coil current information.

AN0
AN1

Hitachi
SH/7034

TIOCA3

U+

TIOCB3

U-

TIOCA4

V+

TOCXA4

V-

TIOCB4

W+

TOCXB4

W-

Hall Sensors
IGBT
Switch
Block

IM
Optical Encoders

TCLKA
TCLKB

Figure 8

12

5.1 The Hitachi Integrated Timer Unit


The ITU implemented on Hitachis SH/7034 provides five fully independent timer channels which
may be used separately or in conjunction. In this application, four timer channels are used to
provide three functions:
1. Channel 1 is used as a simple interval timer to kick off the PID algorithm.
2. Channel 2 is used to determine the speed, direction, and angular position of the motor shaft.
3. Channels 3 and 4 cooperatively work to produce three sets of complementary PWM
waveforms.
The use of channel 1 is straightforward and well describe this in section 5.3. Channel 2 is used
in phase counting mode to accomplish its task. Remember that the motor shaft was fitted with a
disk containing 1024 slots and a two-phase optical encoder was fitted to this disk. The pulse train
from each of these channels is fed to the TCLKA and TCLKB inputs of ITU channel 2. The
orientation of the optical encoder is such that a slot in the rotating disk passes one of the phases
at a slightly different time that a slot passes the other. Consequently, a pulse train similar to the
one shown in figure 9 is produced on the TCLK inputs. If TCLKA leads TCLKB, the ITU channel
2 counter increments when a clock transition occurs. Since there are 1024 slots in the disk, a
count of 4*1024 represents one revolution.
If the motor slows to a stop and reverses direction, TCLKB will then lead TCLKA and ITU channel
2 will decrement on each clock pulse. By comparing the value of the channel 2 counter between
sampling intervals, we can determine the direction the motor is spinning. We can also calculate
the exact position of the motor. If we arbitrarily consider the point at which the motor started to be
the origin, we know that the position of the motor is given by:
Position = 360o / Remainder(Total Count / (4 * 1024))

(5.1)

If we read the count of ITU channel 2 at regular intervals, lets say every 500 usec, we can
calculate the average speed during the interval as:
Speed = (Ending count Beginning count) / (50 * 10 6) * (4 * 1024)

(5.2)

Theres one important note with respect to the way we use channel 2 in this example. Since our
speed and position calculation is based on the counting of slots, our accuracy is a function of the
number of slots on the disk. If the difference between the ending count and beginning count in
our speed calculation is large, this may be adequate. However, if we increased the performance
of our system by reducing the sampling period below 500 usec, we may begin to care whether
the ending count just incremented or was just about to increment. Hitachis ITU provides a
solution for this, although it is not implemented in this example. Since we have not used channel
0, we may employ it to increase our accuracy.
Programming channel 0 to increment TCNT0 with the system clock and clear it on an input
capture does this. In this mode of operation, one of the signals, TCLKA or TCLKB is connected
to the Input Capture Port of channel 0. Each time this signal transitions, the fast incrementing
TCNT0 is cleared to zero. When the channel 1 timer interval expires, a quick read of TCNT0
provides an indication of the amount of time which has passed since the last increment of
TCNT2. This value, of course, is dependent on motor speed.
Channels 3 and 4 of the ITU are used to generate sinusoidal PWM signals. Referring back to
figure 5, we can produce a sinusoidal current in a motor coil by superimposing a high frequency
chopping wave over the target sinusoid. When the sinusoid intersects our chopping wave, we
turn the PWM output on or off depending upon the direction of the chopping wave. When
Channels 3 and 4 of Hitachis ITU are set to work in complementary PWM mode, six registers

13

begin to operate in the following manner to accomplish this task.


1. TCNT3 and TCNT4, the counter registers of each channel become tied and are incremented
or decremented by the clock of channel 3. Referring again to figure 5, the value of these
registers define the chopping wave.
2. GRA3 determines the amplitude of the chopping wave. When the incrementing value of
TCNT3 reaches the static value of GRA3, the registers TCNT3 and TCNT4 automatically
switch from incrementing to decrementing. In a similar fashion, when the decrementing value
in TCNT4 underflows, the registers switch to incrementing. TCNT4 never reaches the value
contained in GRA3 and TCNT3 never reaches zero.
3. GRB3, GRA4, and GRB4 each control a set of complementary PWM signals. It is important
to note, from figure 5, that the value in TCNT3 at any given time is ALWAYS greater than the
value in TCNT4. When TCNT3 matches the value of a control register such as GRB3, one
signal in the pair transitions. Likewise, when TCNT4 matches the value of the same register
the other signal in the pair transitions. On the rising side of the chopping wave TCNT3 will
match first and on the falling side, TCNT4 will match first. The difference between TCNT3
and TCNT4 determines the non-overlapping time of the pair. By adjusting the value of the
control register (GRB3, GRA4, or GRB4) between zero and GRA3, the width of the PWM
pulse can be adjusted. Following the description given in section 3.0, it should be obvious
how sinusoidal PWM is produced by simply changing the value of a control register.

Motor Reverses
Direction

TCLKA

TCLKB

TCNT2

Figure 9

Time
14

A few precautions must be considered, however, in adjusting the value in the control registers.
First, once weve determined that the value in the control register should change, we should wait
until the chopping wave has reached GRA3 or zero. Otherwise, we may change the value after
TCNT3 matched the control register, but before TCNT4 matched. Luckily, Hitachis ITU provides
an automatic mechanism for doing this. A set of buffer registers is provided for each of the
control registers. These registers are written with the new value and the ITU will automatically
perform the update at the next peak or valley of the chopping wave. A few special cases of
control register updating also need to be considered. If T is the difference between TCNT3 and
TCNT4, the non-overlapping distance, then let us define:

Max(TCNT3) = GRA3 + 1 = the maximum value attained by TCNT3


Max(TCNT4) = GRA3 + 1 T = the maximum value attained by TCNT4
Min(TCNT4) = 0xffff = the minimum value attained by TCNT4
Min(TCNT3) = T-1 = the minimum value attained by TCNT3

Then the following special precautions must be applied during the control register update:
If a control register is currently set to a value between Max(TCNT3) and Max(TCNT4), and the
next value is going to be outside this range, it must be done when TCNT4 underflows rather then
when TCNT3 overflows. The buffer register can still be used to update the control register, but
care must be taken to update the buffer register between the time of a TCNT3 overflow and
TCNT4 underflow.
If a control register is currently set to a value between Min(TCNT3) and Min(TCNT4), and the
next value is going to be outside this range, it must be done when TCNT3 overflows rather then
when TCNT4 underflows. The buffer register can still be used to update the control register, but
care must be taken to update the buffer register between the time of a TCNT4 underflow and
TCNT3 overflow.
If a control register is to be updated in such a way as to create a 0% duty cycle, writing a value
greater than GRA3 to the buffer register can do this. Care must be taken, however, to do it while
the chopping wave is decrementing. This is the time between a TCNT3 overflow and a TCNT4
underflow.
If a control register is to be updated in such a way as to create a 100% duty cycle, writing a value
greater than GRA3 to the buffer register can do this. Care must be taken, however, to do it while
the chopping wave is incrementing. This is the time between a TCNT4 underflow and a TCNT3
overflow.

15

5.2 The Two Directional Current Model for Three Phase Current
In section 3.0, we noted that the motor turned by virtue of sinusoidal currents, each 60o out of
phase with the other flowing in the three motor coils. We defined these three coils as U, V, and
W and determined that the duty cycle of the PWM signal controlled whether the current flowing in
each coil increased or decreased. Temporarily forgetting about the problem of controlling the
motor speed, then we must periodically determine where the motor shaft is in its angular rotation
(0-3600) and what the current flow is at that time in each coil. Using this information, we can then
determine what change to make in the current flow to continue producing the appropriate sine
wave.
The motor in our example is fitted with two Hall Effect sensors that measure the current flow in
the U and V coils. It is possible to determine the current flow in all three coils using a
mathematical transform. This reduces the total computation and measurement requirements of
the system. Referring back to figure 4, the amount of instantaneous current flow in each coil can
be described as:
iu = I sin t
iv = I sin (
t 60o)
iw = I sin (
t 120o)

(5.3)
(5.4)
(5.5)

Here t is the angular position of the shaft and I is the maximum current. The two-phase model
transforms the total current into a vertical D-axis and horizontal Q-axis. These currents are a
function of , the position of the shaft considering current loss in the motor. The two-phase
model currents derived from equations 5.3 to 5.5 are:
id()
) = (2)
-2 (sin * iv + sin (
+ 4/3
) * iv)
iq(
) = id(
+ /2)

(5.6)
(5.7)

For this discussion, we will ignore current loss within the motor, thus
= t
id = 0
iq = -(3/2 * I)-2

(5.8)
(5.9)
(5.10)

Although the theoretical value of id is zero in equation 5.9, the actual current is not zero due to
the back EMF produced in the inactive winding. We can also see that the current iq is
proportional to the maximum coil current, I. I is the current produced when we set a duty cycle of
0% or 100% in the ITU control register.
Remember that in our system, we use Hall Effect sensors to measure iu and iv. We also know
the exact shaft position, , from equation 5.1. Thus we can determine the actual value of id and
iq in the motor at the present time. There are two things that must be done at this point. If the
motor speed is exactly equal to our target value, the current flow in each coil must be adjusted to
continue producing a sinusoidal current of the appropriate phase for the shaft position at that
time. The measured value of id, the back EMF current, is used to determine what change to
make. Secondly, a PID algorithm is performed using the speed information calculated in equation
5.2. The PID algorithm determines what additional change should be made to coil current, to
speed up or slow the motor. Its output value is called iq* (the calculation of iq* is explained in
the Speed Control Code below). The measured iq and the target iq* are used to determine
what change to make. Therefore, we have
iderr = 0 id

(5.11)

16

iqerr = iq* - iq

(5.12)

A proportional integration of these error values is performed producing


Vzd = Kp * iderr + id + Ki * iderr
Vzq = Kp * iqerr + iq + Ki * iqerr

(5.13)
(5.14)

The summations here represent the summation of all previous iderr and iqerr. Ki and Kp are
gain constants. We have chosen Ki=89 and Kp=3 for our demonstration system. Next, we must
correct for back EMF distortion. Remember that the current values we have measured with the
A/D converter include information about both the current we have supplied via our switch block
and currrent which was induced by back EMF. Back EMF can be determined from the measured
current, iv, when the motor position is such that the input power from the switch block is zero.
We account for the distortion produced by back EMF to determine a target Vd and Vq through
non-interacting control.
Vd = Vzd + * L * iq
Vq = Vzq + * (M * Vemf L * id)

(5.15)
(5.16)

In this case,
= the location of the motor
L = the coil inductance which is a physical property of the motor
M = the complementary inductance which is a physical property of the motor
Vemf = the back EMF
Lastly, we must convert the the two-phase voltages we have calculated back to a three-phase
model. Reversing the procedure used in equations 5.3 to 5.7, we produce
Vu = (2/3)-2 (Vd * sin + Vq * sin (
+ /4))
Vv = (2/3)-2 (Vd * sin (
+ 2/3)
/3) + Vq * sin (
+ 11
/12))
Vw = -Vu Vv

(5.17)
(5.18)
(5.19)

Vu, Vv, and Vw become our new control register values in the ITU.

17

6.0 SH/7034 Code Example


The code presented here was written and compiled using the Hitachi MCS tool chain, version
3.0g and developed using Hitachis HiView integrated development environment. Simulations
were performed using the HiView integrated debugging simulator and stubs to an SH-1 Low Cost
Evaluation Board. Each section of code contains a comment header explaining its function, logic
flow, and relationship to the rest of the program. A brief description of these routines is provided
below.
Pid.h and 7032.h Header files
The 7032.h header file is provided in the \samples directory of the Hitachi MCS C Compiler.
The header file contains structures and unions which define each of the SH-1 registers at a word,
byte, and bit level. These are also mapped to their respective addresses with a dereferenced
pointer to ease reading and writing of SH-1 registers. The 7032 header file is included by Main.c.
The Pid.h header, also included in Main.c, contains all the unique constants, definitions and
globals used in this program. The code was designed with a degree of flexibility for adaptation to
different physical platforms. Constants declared here allow for varying dead time values, Hall
sensor arrangements and PID constants.
Vect.asm
HiView initially builds a shell for this code. Vect.asm is the first routine executed and the section
Vect should be linked at address 0x0000. Interrupt handlers defined in Main.c are imported into
Vect.asm at its start. Data statements at the label Start define the vector table according to the
Hitachi 7034 Hardware Manual. The assembler resolves the symbol name of each routine to its
address which positionally located in the vector table.
The initial Program Counter is loaded from Vector 0, which contains the address of the label
Begin. Begin is located within Vect.asm and it becomes the starting point of the program.
Vect.asm then initializes the stack pointer and branches to the routine Init.c. Main.c is later called
by Init.c and when Init.c returns, Vect.asm puts the processor into a sleep state.
Init.c, Initsct.c, and Sect.asm
Init.c is a simple routine entirely built by HiView. It is called by Vect.asm and, in turn, calls the
routine Initsct.c and Main.c. Initsct.c copies the contents of the D_ROM section from ROM area
to RAM area. These sections are defined in Sect.asm and are for C initialized variables.
Furthermore, Initsct.c initializes the BSS segment (C data area) to zero. From here, control is
passed to Main.c, which contains the actual PID code.
Main.c
The PID algorithm is primarily interrupt driven and contains a very simple Main routine. Main.c
calls an initialization routine, which sets up the ITU, ports, A/D, interrupt controller, and system
registers. After initialization, Main.c enters an infinite loop. The initialization routine has set ITU
channel 1 to generate an interrupt every 500 usec. When the interrupt handler executes, speed,
PID and current correction calculations are done.

18

6.1 PID.h
/*
Name:
Version:
Date:
Author:

PID.h
1.0
7/97
Ken Schultz

This header file contains definitions and global variable declarations


unique to the PID demonstration code.
*/
char temp_char;
int temp_int;
long temp_long;

/* used as a temporary holder */


/* used as a temporary holder */
/* used as a temporary holder */

/* Constants */
const unsigned int Ki = 89;
const unsigned int Kp = 3;
const unsigned int Kd = 10;
const unsigned int T = 1;
const unsigned int windings = 5;
const unsigned int Rl = 2;
const unsigned int const240 = (240*512)/360;
const unsigned int const90 = (90*512)/360;
const unsigned int const330 = (330*512)/360;
const unsigned int DeadTime = 0x20;
const unsigned int T3_min = 0x1f;
const unsigned int T3_max = 0x2d6;
const unsigned int T4_max = 0x2b7;

/* integral gain factor */


/* proportional gain factor */
/* differential gain factor */
/* sampling interval value */
/* windings on hall sensor for current */
/* load resistor on Hall sensor, Kohm */
/* used in coil current calc as */
/* index into the sin table for d and */
/* q current calculation */
/* gap between T3CNT and T4CNT */
/* the lowest value possible in TCNT3 */
/* target value for GRA3 */
/* the highest value possible in TCNT4 */

/* Globals */
signed int i_correction;
/* an output from PID_Calc, our new current command */
signed int Vd;
/* d phase voltage for current correction routine */
signed int Vq;
/* q phase voltage for current correction routine */
unsigned int ITU2_flag;
/* count of how many times ITU2 overflowed */
unsigned int last_ITU2;
/* how many times ITU2 overflowed last iteration*/
unsigned int target_speed;
/* the speed we are commanding the motor to turn */
unsigned int sel_u, sel_v, sel_w;/* flags indicating which phase to adjust next */
unsigned int current_speed;
/* calculated value from Speed_Calc routine */
unsigned int current_position; /* calculated value from Speed_Calc routine */
signed int K[3];
/* array of calculated PID gain factors */
signed int error[3];
/* array to hold current and previous speed errors */
signed int error_id[3];
/* array for Current Correction PID */
signed int error_iq[3];
/* array for Current Correction PID */
signed long sygd;
/* used by coil current calculation */
signed long sygq;
/* used by coil current calculation */
unsigned int data_u;
/* the next u phase ITU value from coil current calc */
unsigned int data_v;
/* the next v phase ITU value from coil current calc */
unsigned int data_w;
/* the next w phase ITU value from coil current calc */
unsigned char U100_set;
/* flag used by T3INT to know that phase must be set */

19

unsigned char V100_set;


unsigned char W100_set;
/* Name:
* Author:
* Date:
* Version:
* Function:
*/

/* flag used by T3INT to know that phase must be set */


/* flag used by T3INT to know that phase must be set */

SinInit.h
Stacia Lawson
8/25/97
1.0
This header initializes the Sine Wave table for the PID algorithm

unsigned int Sin[512] =


{
0x016a, 0x016e, 0x0170, 0x0172, 0x0177, 0x017b, 0x0180, 0x0184, 0x0189, 0x018d,
0x0191, 0x0196, 0x019a, 0x019f, 0x01a3, 0x01a7, 0x01ac, 0x01b0, 0x01b5, 0x01b9,
0x01bd, 0x01c2, 0x01c6, 0x01ca, 0x01ce, 0x01d3, 0x01d7, 0x01db, 0x01df, 0x01e4,
0x01e8, 0x01ec, 0x01f0, 0x01f4, 0x01f8, 0x01fe, 0x0200, 0x0204, 0x0208, 0x020e,
0x0210, 0x0214, 0x0218, 0x021c, 0x0220, 0x0224, 0x0228, 0x022b, 0x022f, 0x0233,
0x0237, 0x023a, 0x023e, 0x0241, 0x0245, 0x0249, 0x024c, 0x024f, 0x0253, 0x0256,
0x025a, 0x025d, 0x0260, 0x0263, 0x0267, 0x026a, 0x026d, 0x0270, 0x0273, 0x0276,
0x0279, 0x027c, 0x027f, 0x0282, 0x0285, 0x0287, 0x028a, 0x028d, 0x028f, 0x0292,
0x0294, 0x0297, 0x0299, 0x029c, 0x029e, 0x02a0, 0x02a3, 0x02a5, 0x02a7, 0x02a9,
0x02ab, 0x02ad, 0x02af, 0x02b1, 0x02b3, 0x02b5, 0x02b7, 0x02b8, 0x02ba, 0x02bc,
0x02bd, 0x02bf, 0x02c0, 0x02c2, 0x02c3, 0x02c4, 0x02c6, 0x02c7, 0x02c8, 0x02c9,
0x02ca, 0x02cb, 0x02cc, 0x02cd, 0x02ce, 0x02cf, 0x02cf, 0x02d0, 0x02d1, 0x02d1,
0x02d2, 0x02d2, 0x02d3, 0x02d3, 0x02d3, 0x02d4, 0x02d4, 0x02d4, 0x02d4, 0x02d4,
0x02d4, 0x02d4, 0x02d4, 0x02d4, 0x02d3, 0x02d3, 0x02d3, 0x02d2, 0x02d2, 0x02d1,
0x02d1, 0x02d0, 0x02cf, 0x02cf, 0x02ce, 0x02cd, 0x02cc, 0x02cb, 0x02ca, 0x02c9,
0x02c8, 0x02c7, 0x02c6, 0x02c4, 0x02c3, 0x02c2, 0x02c0, 0x02bf, 0x02bd, 0x02bc,
0x02ba, 0x02b8, 0x02b7, 0x02b5, 0x02b3, 0x02b1, 0x02af, 0x02ad, 0x02ab, 0x02a9,
0x02a7, 0x02a5, 0x02a3, 0x02a0, 0x029e, 0x029c, 0x0299, 0x0297, 0x0294, 0x0292,
0x028f, 0x028d, 0x028a, 0x0287, 0x0285, 0x0282, 0x027f, 0x027c, 0x0279, 0x0276,
0x0273, 0x0270, 0x026d, 0x026a, 0x0267, 0x0263, 0x0260, 0x025d, 0x025a, 0x0256,
0x0253, 0x024f, 0x024c, 0x0249, 0x0245, 0x0241, 0x023e, 0x023a, 0x0237, 0x0233,
0x022f, 0x022b, 0x0228, 0x0224, 0x0220, 0x021c, 0x0218, 0x0214, 0x0210, 0x0210,
0x020c, 0x0208, 0x0204, 0x0200, 0x01fc, 0x01f8, 0x01f4, 0x01f0, 0x01ec, 0x01e8,
0x01e4, 0x01df, 0x01db, 0x01d7, 0x01d3, 0x01ce, 0x01ca, 0x01c6, 0x01c2, 0x01bd,
0x01b9, 0x01b5, 0x01b0, 0x01ac, 0x01a7, 0x01a3, 0x019f, 0x019a, 0x0196, 0x0191,
0x018d, 0x0189, 0x0184, 0x0180, 0x017b, 0x0177, 0x0172, 0x016e, 0x016a, 0x0165,
0x0161, 0x015c, 0x0158, 0x0153, 0x014f, 0x014a, 0x0146, 0x0142, 0x013d, 0x0139,
0x0134, 0x0130, 0x012c, 0x0127, 0x0123, 0x011e, 0x011a, 0x0116, 0x0111, 0x010d,
0x0109, 0x0105, 0x0100, 0x0fc, 0x0f8, 0x0f4, 0x0ef, 0x0eb, 0x0e7, 0x0e3,
0x0df, 0x0db, 0x0d7, 0x0d3, 0x0cf, 0x0cb, 0x0c7, 0x0c3, 0x0bf, 0x0bb,
0x0b7, 0x0b3, 0x0af, 0x0ab, 0x0a8, 0x0a4, 0x0a0, 0x09c, 0x099, 0x095,
0x092, 0x08e, 0x08a, 0x087, 0x084, 0x080, 0x07d, 0x079, 0x076, 0x073,
0x070, 0x06c, 0x069, 0x066, 0x063, 0x060, 0x05d, 0x05a, 0x057, 0x054,
0x051, 0x04e, 0x04c, 0x049, 0x046, 0x044, 0x041, 0x03f, 0x03c, 0x03a,
0x037, 0x035, 0x033, 0x030, 0x02e, 0x02c, 0x02a, 0x028, 0x026, 0x024,
0x022, 0x020, 0x01e, 0x01c, 0x01b, 0x019, 0x017, 0x016, 0x014, 0x013,
0x011, 0x011, 0x010, 0x0f, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
0x07, 0x06, 0x05, 0x04, 0x04, 0x03, 0x02, 0x02, 0x01, 0x01,
0x00, 0x00, 0x00, 0x0, 0x0, 0x0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x04, 0x04, 0x05,

20

0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0f, 0x010,
0x011, 0x013, 0x014, 0x016, 0x017, 0x019, 0x01b, 0x01c, 0x01e, 0x020,
0x022, 0x024, 0x026, 0x028, 0x02a, 0x02c, 0x02e, 0x030, 0x033, 0x035,
0x037, 0x03a, 0x03c, 0x03f, 0x041, 0x044, 0x046, 0x049, 0x04c, 0x04e,
0x051, 0x054, 0x057, 0x05a, 0x05d, 0x060, 0x063, 0x066, 0x069, 0x06c,
0x070, 0x073, 0x076, 0x079, 0x07d, 0x080, 0x084, 0x087, 0x08a, 0x08e,
0x092, 0x095, 0x099, 0x09c, 0x0a0, 0x0a4, 0x0a8, 0x0ab, 0x0af, 0x0b3,
0x0b7, 0x0bb, 0x0bf, 0x0c3, 0x0c7, 0x0cb, 0x0cf, 0x0d3, 0x0d7, 0x0db,
0x0df, 0x0e3, 0x0e7, 0x0eb, 0x0ef, 0x0f4, 0x0f8, 0x0fc, 0x0100, 0x0105,
0x0109, 0x010d, 0x0111, 0x0116, 0x011a, 0x011e, 0x0123, 0x0127, 0x012c, 0x0130,
0x0134, 0x0139, 0x013d, 0x0142, 0x0146, 0x014a, 0x014f, 0x0153, 0x0158, 0x015c,
0x0161, 0x016a
};
/* end of Sin Table Initialization */

21

6.2 7032.h
/************************************************************************/
/*
SH7032 Include File
Ver 1.0
*/
/************************************************************************/
struct st_sci {
/* struct SCI
*/
union {
/* SMR
*/
unsigned char BYTE;
/* Byte Access */
struct {
/* Bit Access */
unsigned char CA :1;
/*
C/A
*/
unsigned char CHR :1;
/*
CHR
*/
unsigned char PE :1;
/*
PE
*/
unsigned char OE :1;
/*
O/E
*/
unsigned char STOP:1;
/*
STOP
*/
unsigned char MP :1;
/*
MP
*/
unsigned char CKS :2;
/*
CKS
*/
}
BIT;
/*
*/
}
SMR;
/*
*/
unsigned char
BRR;
/* BRR
*/
union {
/* SCR
*/
unsigned char BYTE;
/* Byte Access */
struct {
/* Bit Access */
unsigned char TIE :1;
/*
TIE
*/
unsigned char RIE :1;
/*
RIE
*/
unsigned char TE :1;
/*
TE
*/
unsigned char RE :1;
/*
RE
*/
unsigned char MPIE:1;
/*
MPIE
*/
unsigned char TEIE:1;
/*
TEIE
*/
unsigned char CKE :2;
/*
CKE
*/
}
BIT;
/*
*/
}
SCR;
/*
*/
unsigned char
TDR;
/* TDR
*/
union {
/* SSR
*/
unsigned char BYTE;
/* Byte Access */
struct {
/* Bit Access */
unsigned char TDRE:1;
/*
TDRE
*/
unsigned char RDRF:1;
/*
RDRF
*/
unsigned char ORER:1;
/*
ORER
*/
unsigned char FER :1;
/*
FER
*/
unsigned char PER :1;
/*
PER
*/
unsigned char TEND:1;
/*
TEND
*/
unsigned char MPB :1;
/*
MPB
*/
unsigned char MPBT:1;
/*
MPBT
*/
}
BIT;
/*
*/
}
SSR;
/*
*/
unsigned char
RDR;
/* RDR
*/
char
wk[2];
/*
*/
};
/*
*/
struct st_ad {
/* struct A/D
*/
unsigned short
DRA;
/* ADDRA
*/
unsigned short
DRB;
/* ADDRB
*/
unsigned short
DRC;
/* ADDRC
*/
unsigned short
DRD;
/* ADDRD
*/
union {
/* ADCSR
*/
unsigned char BYTE;
/* Byte Access */
struct {
/* Bit Access */
unsigned char ADF :1;
/*
ADF
*/
unsigned char ADIE:1;
/*
ADIE
*/
unsigned char ADST:1;
/*
ADST
*/
unsigned char SCAN:1;
/*
SCAN
*/
unsigned char CKS :1;
/*
CKS
*/

22

unsigned char CH
}
BIT;
CSR;

:3;

}
union {
unsigned char BYTE;
struct {
unsigned char TRGE:1;
}
BIT;
}
CR;
};
struct st_itu {
union {
unsigned char BYTE;
struct {
unsigned char
unsigned char
unsigned char
unsigned char
unsigned char
unsigned char
}
BIT;
}
TSTR;
union {
unsigned char BYTE;
struct {
unsigned char
unsigned char
unsigned char
unsigned char
unsigned char
unsigned char
}
BIT;
}
TSNC;
union {
unsigned char BYTE;
struct {
unsigned char
unsigned char
unsigned char
unsigned char
unsigned char
unsigned char
unsigned char
unsigned char
}
BIT;
}
TMDR;
union {
unsigned char BYTE;
struct {
unsigned char
unsigned char
unsigned char
unsigned char
unsigned char
unsigned char
}
BIT;
}
TFCR;
char
wk[45];
union {
unsigned char BYTE;
struct {
unsigned char
unsigned char

wk :3;
STR4:1;
STR3:1;
STR2:1;
STR1:1;
STR0:1;

wk :3;
SYNC4:1;
SYNC3:1;
SYNC2:1;
SYNC1:1;
SYNC0:1;

wk :1;
MDF :1;
FDIR:1;
PWM4:1;
PWM3:1;
PWM2:1;
PWM1:1;
PWM0:1;

wk :2;
CMD :2;
BFB4:1;
BFA4:1;
BFB3:1;
BFA3:1;

wk :6;
OLS4:1;

/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*

CH

ADCR
Byte Access
Bit Access
TRGE

struct ITU
TSTR
Byte Access
Bit Access
STR4
STR3
STR2
STR1
STR0

TSNC
Byte Access
Bit Access
SYNC4
SYNC3
SYNC2
SYNC1
SYNC0

TMDR
Byte Access
Bit Access
MDF
FDIR
PWM4
PWM3
PWM2
PWM1
PWM0

TFCR
Byte Access
Bit Access
CMD
BFB4
BFA4
BFB3
BFA3

TOCR
Byte Access
Bit Access
OLS4

*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/

23

unsigned char OLS3:1;


}
BIT;
TOCR;

}
};
struct st_itu0 {
union {
unsigned char BYTE;
struct {
unsigned char
unsigned char
unsigned char
unsigned char
}
BIT;
}
TCR;
union {
unsigned char BYTE;
struct {
unsigned char
unsigned char
unsigned char
unsigned char
}
BIT;
}
TIOR;
union {
unsigned char BYTE;
struct {
unsigned char
unsigned char
unsigned char
unsigned char
}
BIT;
}
TIER;
union {
unsigned char BYTE;
struct {
unsigned char
unsigned char
unsigned char
unsigned char
}
BIT;
}
TSR;
unsigned short
TCNT;
unsigned short
GRA;
unsigned short
GRB;
};
struct st_itu3 {
union {
unsigned char BYTE;
struct {
unsigned char
unsigned char
unsigned char
unsigned char
}
BIT;
}
TCR;
union {
unsigned char BYTE;
struct {
unsigned char
unsigned char
unsigned char
unsigned char
}
BIT;

wk :1;
CCLR:2;
CKEG:2;
TPSC:3;

wk :1;
IOB:3;
:1;
IOA:3;

wk
:5;
OVIE :1;
IMIEB:1;
IMIEA:1;

wk :5;
OVF :1;
IMFB:1;
IMFA:1;

wk :1;
CCLR:2;
CKEG:2;
TPSC:3;

wk :1;
IOB:3;
:1;
IOA:3;

/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*

OLS3

struct ITU0
TCR
Byte Access
Bit Access
CCLR
CKEG
TPSC

TIOR
Byte Access
Bit Access
IOB
IOA

TIER
Byte Access
Bit Access
OVIE
IMIEB
IMIEA

TSR
Byte Access
Bit Access
OVF
IMFB
IMFA

TCNT
GRA
GRB
struct ITU3
TCR
Byte Access
Bit Access
CCLR
CKEG
TPSC

TIOR
Byte Access
Bit Access
IOB
IOA

*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/

24

}
TIOR;
union {
unsigned char BYTE;
struct {
unsigned char
unsigned char
unsigned char
unsigned char
}
BIT;
}
TIER;
union {
unsigned char BYTE;
struct {
unsigned char
unsigned char
unsigned char
unsigned char
}
BIT;
}
TSR;
unsigned short
TCNT;
unsigned short
GRA;
unsigned short
GRB;
unsigned short
BRA;
unsigned short
BRB;
char
wk[2];

wk
:5;
OVIE :1;
IMIEB:1;
IMIEA:1;

wk :5;
OVF :1;
IMFB:1;
IMFA:1;

};
union un_dmac {
unsigned short
struct {
unsigned
unsigned
unsigned
unsigned
unsigned
unsigned
}

WORD;
short
short
short
short
short
short
BIT;

wk
PR

:6;
:2;
:5;
AE :1;
NMIF:1;
DME :1;

};
struct st_dmac0 {
void
*SAR;
void
*DAR;
char
wk1[2];
unsigned short TCR;
char
wk2[2];
union {
unsigned short WORD;
struct {
unsigned short
unsigned short
unsigned short
unsigned short
unsigned short
unsigned short
unsigned short
unsigned short
unsigned short
unsigned short
unsigned short
}
BIT;
}
CHCR;
};
struct st_intc {
union {
unsigned short WORD;

DM:2;
SM:2;
RS:4;
AM:1;
AL:1;
DS:1;
TM:1;
TS:1;
IE:1;
TE:1;
DE:1;

/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*

*/
TIER
*/
Byte Access */
Bit Access */
*/
OVIE
*/
IMIEB
*/
IMIEA
*/
*/
*/
TSR
*/
Byte Access */
Bit Access */
*/
OVF
*/
IMFB
*/
IMFA
*/
*/
*/
TCNT
*/
GRA
*/
GRB
*/
BRA
*/
BRB
*/
*/
*/
union DMAC
*/
Word Access */
Bit Access */
*/
PR
*/
*/
AE
*/
NMIF
*/
DME
*/
*/
*/
struct DMAC0 */
SAR
*/
DAR
*/
*/
TCR
*/
*/
CHCR
*/
Word Access */
Bit Access */
DM
*/
SM
*/
RS
*/
AM
*/
AL
*/
DS
*/
TM
*/
TS
*/
IE
*/
TE
*/
DE
*/
*/
*/
*/
struct INTC */
IPRA
*/
Word Access */

25

union

union

union

union

union

struct {
unsigned short
unsigned short
unsigned short
unsigned short
}
BIT;
}
IPRA;
{
unsigned short WORD;
struct {
unsigned short
unsigned short
unsigned short
unsigned short
}
BIT;
}
IPRB;
{
unsigned short WORD;
struct {
unsigned short
unsigned short
unsigned short
unsigned short
}
BIT;
}
IPRC;
{
unsigned short WORD;
struct {
unsigned short
unsigned short
unsigned short
unsigned short
}
BIT;
}
IPRD;
{
unsigned short WORD;
struct {
unsigned short
unsigned short
unsigned short
}
BIT;
}
IPRE;
{
unsigned short WORD;
struct {
unsigned short
unsigned short
unsigned short
unsigned short
unsigned short
unsigned short
unsigned short
unsigned short
unsigned short
unsigned short
unsigned short
}
BIT;
}
ICR;

};
struct st_ubc {
void
unsigned long
union {

*BAR;
BAMR;

UU:4;
UL:4;
LU:4;
LL:4;

UU:4;
UL:4;
LU:4;
LL:4;

UU:4;
UL:4;
LU:4;
LL:4;

UU:4;
UL:4;
LU:4;
LL:4;

UU:4;
UL:4;
LU:4;

NMIL :1;
:6;
NMIE :1;
IRQ0S:1;
IRQ1S:1;
IRQ2S:1;
IRQ3S:1;
IRQ4S:1;
IRQ5S:1;
IRQ6S:1;
IRQ7S:1;

/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*

Bit Access
IRQ0
IRQ1
IRQ2
IRQ3

IPRB
Word Access
Bit Access
IRQ4
IRQ5
IRQ6
IRQ7

IPRC
Word Access
Bit Access
DMAC0,1
DMAC2,3
ITU0
ITU1

IPRD
Word Access
Bit Access
ITU2
ITU3
ITU4
SCI0

IPRE
Word Access
Bit Access
SCI1
PRT,A/D
WDT,REF

ICR
Word Access
Bit Access
NMIL
NMIE
IRQ0S
IRQ1S
IRQ2S
IRQ3S
IRQ4S
IRQ5S
IRQ6S
IRQ7S

struct UBC
BAR
BAMR
BBR

*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/

26

unsigned short
WORD;
struct {
unsigned short wk:8;
unsigned short CD:2;
unsigned short ID:2;
unsigned short RW:2;
unsigned short SZ:2;
}
BIT;
}
BBR;
};
struct st_bsc {
union {
unsigned short
WORD;
struct {
unsigned short DRAME:1;
unsigned short IOE :1;
unsigned short WARP :1;
unsigned short RDDTY:1;
unsigned short BAS :1;
}
BIT;
}
BCR;
union {
unsigned short
WORD;
struct {
unsigned short RW7:1;
unsigned short RW6:1;
unsigned short RW5:1;
unsigned short RW4:1;
unsigned short RW3:1;
unsigned short RW2:1;
unsigned short RW1:1;
unsigned short RW0:1;
unsigned short
:6;
unsigned short WW1:1;
}
BIT;
}
WCR1;
union {
unsigned short
WORD;
struct {
unsigned short DRW7:1;
unsigned short DRW6:1;
unsigned short DRW5:1;
unsigned short DRW4:1;
unsigned short DRW3:1;
unsigned short DRW2:1;
unsigned short DRW1:1;
unsigned short DRW0:1;
unsigned short DWW7:1;
unsigned short DWW6:1;
unsigned short DWW5:1;
unsigned short DWW4:1;
unsigned short DWW3:1;
unsigned short DWW2:1;
unsigned short DWW1:1;
unsigned short DWW0:1;
}
BIT;
}
WCR2;
union {
unsigned short
WORD;
struct {
unsigned short WPU :1;
unsigned short A02LW:2;
unsigned short A6LW :2;

/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*

Word Access */
Bit Access */
*/
CD
*/
ID
*/
RW
*/
SZ
*/
*/
*/
*/
struct BSC
*/
BCR
*/
Word Access */
Bit Access */
DRAME
*/
IOE
*/
WARP
*/
RDDTY
*/
BAS
*/
*/
*/
WCR1
*/
Word Access */
Bit Access */
RW7
*/
RW6
*/
RW5
*/
RW4
*/
RW3
*/
RW2
*/
RW1
*/
RW0
*/
*/
WW1
*/
*/
*/
WCR2
*/
Word Access */
Bit Access */
DRW7
*/
DRW6
*/
DRW5
*/
DRW4
*/
DRW3
*/
DRW2
*/
DRW1
*/
DRW0
*/
DWW7
*/
DWW6
*/
DWW5
*/
DWW4
*/
DWW3
*/
DWW2
*/
DWW1
*/
DWW0
*/
*/
*/
WCR3
*/
Word Access */
Bit Access */
WPU
*/
A02LW
*/
A6LW
*/

27

}
BIT;
}
WCR3;
union {
unsigned short
WORD;
struct {
unsigned short CW2 :1;
unsigned short RASD:1;
unsigned short TPC :1;
unsigned short BE :1;
unsigned short CDTY:1;
unsigned short MXE :1;
unsigned short MXC :2;
}
BIT;
}
DCR;
union {
unsigned short
WORD;
struct {
unsigned short PEF :1;
unsigned short PFRC:1;
unsigned short PEO :1;
unsigned short PCHK:2;
}
BIT;
}
PCR;
union {
unsigned short
WORD;
struct {
unsigned short wk
:8;
unsigned short RFSHE:1;
unsigned short RMODE:1;
unsigned short RLW :2;
}
BIT;
}
RCR;
union {
unsigned short
WORD;
struct {
unsigned short wk :8;
unsigned short CMF :1;
unsigned short CMIE:1;
unsigned short CKS :3;
}
BIT;
}
RTCSR;
unsigned short
RTCNT;
unsigned short
RTCOR;
};
union un_sbycr {
unsigned char
BYTE;
struct {
unsigned char SBY:1;
unsigned char HIZ:1;
}
BIT;
};
struct st_pa {
union {
unsigned short
WORD;
struct {
unsigned short B15:1;
unsigned short B14:1;
unsigned short B13:1;
unsigned short B12:1;
unsigned short B11:1;
unsigned short B10:1;
unsigned short B9 :1;
unsigned short B8 :1;

/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*

DCR
Word Access
Bit Access
CW2
RASD
TPC
BE
CDTY
MXE
MXC

PCR
Word Access
Bit Access
PEF
PFRC
PEO
PCHK

RCR
Word Access
Bit Access
RFSHE
RMODE
RLW

RTCSR
Word Access
Bit Access
CMF
CMIE
CKS

RTCNT
RTCOR
union SBYCR
Byte Access
Bit Access
SBY
HIZ

struct PA
PADR
Word Access
Bit Access
Bit 15
Bit 14
Bit 13
Bit 12
Bit 11
Bit 10
Bit 9
Bit 8

*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/

28

unsigned short B7
unsigned short B6
unsigned short B5
unsigned short B4
unsigned short B3
unsigned short B2
unsigned short B1
unsigned short B0
}
BIT;
DR;

:1;
:1;
:1;
:1;
:1;
:1;
:1;
:1;

}
};
struct st_pc {
union {
unsigned short
WORD;
struct {
unsigned short wk:8;
unsigned short B7:1;
unsigned short B6:1;
unsigned short B5:1;
unsigned short B4:1;
unsigned short B3:1;
unsigned short B2:1;
unsigned short B1:1;
unsigned short B0:1;
}
BIT;
}
DR;
};
struct st_pfc {
union {
unsigned short
WORD;
struct {
unsigned short B15:1;
unsigned short B14:1;
unsigned short B13:1;
unsigned short B12:1;
unsigned short B11:1;
unsigned short B10:1;
unsigned short B9 :1;
unsigned short B8 :1;
unsigned short B7 :1;
unsigned short B6 :1;
unsigned short B5 :1;
unsigned short B4 :1;
unsigned short B3 :1;
unsigned short B2 :1;
unsigned short B1 :1;
unsigned short B0 :1;
}
BIT;
}
PAIOR;
union {
unsigned short
WORD;
struct {
unsigned short B15:1;
unsigned short B14:1;
unsigned short B13:1;
unsigned short B12:1;
unsigned short B11:1;
unsigned short B10:1;
unsigned short B9 :1;
unsigned short B8 :1;
unsigned short B7 :1;
unsigned short B6 :1;
unsigned short B5 :1;

/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*

Bit
Bit
Bit
Bit
Bit
Bit
Bit
Bit

7
6
5
4
3
2
1
0

struct PC
PCDR
Word Access
Bit Access
Bit 8
Bit 7
Bit 6
Bit 5
Bit 4
Bit 3
Bit 2
Bit 1
Bit 0

struct PFC
PAIOR
Word Access
Bit Access
Bit 15
Bit 14
Bit 13
Bit 12
Bit 11
Bit 10
Bit 9
Bit 8
Bit 7
Bit 6
Bit 5
Bit 4
Bit 3
Bit 2
Bit 1
Bit 0

PBIOR
Word Access
Bit Access
Bit 15
Bit 14
Bit 13
Bit 12
Bit 11
Bit 10
Bit 9
Bit 8
Bit 7
Bit 6
Bit 5

*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/

29

unsigned short
unsigned short
unsigned short
unsigned short
unsigned short
}
BIT;
PBIOR;

B4
B3
B2
B1
B0

:1;
:1;
:1;
:1;
:1;

}
union {
unsigned short
WORD;
struct {
unsigned short MD15:2;
unsigned short MD14:2;
unsigned short MD13:2;
unsigned short MD12:2;
unsigned short MD11:2;
unsigned short MD10:2;
unsigned short MD9 :2;
unsigned short
:1;
unsigned short MD8 :1;
}
BIT;
}
PACR1;
union {
unsigned short
WORD;
struct {
unsigned short wk :1;
unsigned short MD7:1;
unsigned short
:1;
unsigned short MD6:1;
unsigned short
:1;
unsigned short MD5:1;
unsigned short
:1;
unsigned short MD4:1;
unsigned short MD3:2;
unsigned short MD2:2;
unsigned short MD1:2;
unsigned short MD0:2;
}
BIT;
}
PACR2;
union {
unsigned short
WORD;
struct {
unsigned short MD15:2;
unsigned short MD14:2;
unsigned short MD13:2;
unsigned short MD12:2;
unsigned short MD11:2;
unsigned short MD10:2;
unsigned short MD9 :2;
unsigned short MD8 :2;
}
BIT;
}
PBCR1;
union {
unsigned short
WORD;
struct {
unsigned short MD7:2;
unsigned short MD6:2;
unsigned short MD5:2;
unsigned short MD4:2;
unsigned short MD3:2;
unsigned short MD2:2;
unsigned short MD1:2;
unsigned short MD0:2;
}
BIT;

/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*

Bit
Bit
Bit
Bit
Bit

4
3
2
1
0

PACR1
Word Access
Bit Access
PA15MD
PA14MD
PA13MD
PA12MD
PA11MD
PA10MD
PA9MD
PA8MD

PACR2
Word Access
Bit Access
PA7MD
PA6MD
PA5MD
PA4MD
PA3MD
PA2MD
PA1MD
PA0MD

PBCR1
Word Access
Bit Access
PB15MD
PB14MD
PB13MD
PB12MD
PB11MD
PB10MD
PB9MD
PB8MD

PBCR2
Word Access
Bit Access
PB7MD
PB6MD
PB5MD
PB4MD
PB3MD
PB2MD
PB1MD
PB0MD

*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/

30

}
PBCR2;
char
wk[30];
union {
unsigned short
WORD;
struct {
unsigned short CASHMD:2;
unsigned short CASLMD:2;
}
BIT;
}
CASCR;
};
struct st_tpc {
union {
unsigned char BYTE;
struct {
unsigned char
unsigned char
unsigned char
unsigned char
unsigned char
}
BIT;
}
TPMR;
union {
unsigned char BYTE;
struct {
unsigned char
unsigned char
unsigned char
unsigned char
}
BIT;
}
TPCR;
union {
unsigned char BYTE;
struct {
unsigned char
unsigned char
unsigned char
unsigned char
unsigned char
unsigned char
unsigned char
unsigned char
}
BIT;
}
NDERB;
union {
unsigned char BYTE;
struct {
unsigned char
unsigned char
unsigned char
unsigned char
unsigned char
unsigned char
unsigned char
unsigned char
}
BIT;
}
NDERA;
union {
unsigned char BYTE;
struct {
unsigned char
unsigned char
unsigned char
unsigned char

wk
:4;
G3NOV:1;
G2NOV:1;
G1NOV:1;
G0NOV:1;

G3CMS:2;
G2CMS:2;
G1CMS:2;
G0CMS:2;

B15:1;
B14:1;
B13:1;
B12:1;
B11:1;
B10:1;
B9 :1;
B8 :1;

B7:1;
B6:1;
B5:1;
B4:1;
B3:1;
B2:1;
B1:1;
B0:1;

B15:1;
B14:1;
B13:1;
B12:1;

/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*

CASCR
Word Access
Bit Access
CASHMD
CASLMD

struct TPC
TPMR
Byte Access
Bit Access
G3NOV
G2NOV
G1NOV
G0NOV

TPCR
Byte Access
Bit Access
G3CMS
G2CMS
G1CMS
G0CMS

NDERB
Byte Access
Bit Access
NDER15
NDER14
NDER13
NDER12
NDER11
NDER10
NDER9
NDER8

NDERA
Byte Access
Bit Access
NDER7
NDER6
NDER5
NDER4
NDER3
NDER2
NDER1
NDER0

NDRB (H'F4)
Byte Access
Bit Access
NDR15
NDR14
NDR13
NDR12

*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/

31

unsigned char
unsigned char
unsigned char
unsigned char
}
BIT;
NDRB1;

}
union {
unsigned char BYTE;
struct {
unsigned char
unsigned char
unsigned char
unsigned char
unsigned char
unsigned char
unsigned char
unsigned char
}
BIT;
}
NDRA1;
union {
unsigned char BYTE;
struct {
unsigned char
unsigned char
unsigned char
unsigned char
unsigned char
}
BIT;
}
NDRB2;
union {
unsigned char BYTE;
struct {
unsigned char
unsigned char
unsigned char
unsigned char
unsigned char
}
BIT;
}
NDRA2;
};

B11:1;
B10:1;
B9 :1;
B8 :1;

B7:1;
B6:1;
B5:1;
B4:1;
B3:1;
B2:1;
B1:1;
B0:1;

wk :4;
B11:1;
B10:1;
B9 :1;
B8 :1;

wk:4;
B3:1;
B2:1;
B1:1;
B0:1;

/*
NDR11
/*
NDR10
/*
NDR9
/*
NDR8
/*
/*
/* NDRA (H'F5)
/* Byte Access
/* Bit Access
/*
NDR7
/*
NDR6
/*
NDR5
/*
NDR4
/*
NDR3
/*
NDR2
/*
NDR1
/*
NDR0
/*
/*
/* NDRB (H'A6)
/* Byte Access
/* Bit Access
/*
/*
NDR11
/*
NDR10
/*
NDR9
/*
NDR8
/*
/*
/* NDRA (H'A7)
/* Byte Access
/* Bit Access
/*
/*
NDR3
/*
NDR2
/*
NDR1
/*
NDR0
/*
/*
/*

*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/

32

#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define

SCI0
(*(volatile
SCI1
(*(volatile
AD
(*(volatile
ITU
(*(volatile
ITU0
(*(volatile
ITU1
(*(volatile
ITU2
(*(volatile
ITU3
(*(volatile
ITU4
(*(volatile
DMAC
(*(volatile
DMAC0
(*(volatile
DMAC1
(*(volatile
DMAC2
(*(volatile
DMAC3
(*(volatile
INTC
(*(volatile
UBC
(*(volatile
BSC
(*(volatile
SBYCR
(*(volatile
PA
(*(volatile
PB
(*(volatile
PC
(*(volatile
PFC
(*(volatile
TPC
(*(volatile
st_itu1 st_itu0
st_itu2 st_itu0
st_itu4 st_itu3
st_dmac1 st_dmac0
st_dmac2 st_dmac0
st_dmac3 st_dmac0
st_pb st_pa

struct
struct
struct
struct
struct
struct
struct
struct
struct
union
struct
struct
struct
struct
struct
struct
struct
union
struct
struct
struct
struct
struct

st_sci
st_sci
st_ad
st_itu
st_itu0
st_itu0
st_itu0
st_itu3
st_itu3
un_dmac
st_dmac0
st_dmac0
st_dmac0
st_dmac0
st_intc
st_ubc
st_bsc
un_sbycr
st_pa
st_pa
st_pc
st_pfc
st_tpc

*)0x5FFFEC0)/* SCI0
*)0x5FFFEC8)/* SCI1
*)0x5FFFEE0)/* A/D
*)0x5FFFF00)/* ITU
*)0x5FFFF04)/* ITU0
*)0x5FFFF0E)/* ITU1
*)0x5FFFF18)/* ITU2
*)0x5FFFF22)/* ITU3
*)0x5FFFF32)/* ITU4
*)0x5FFFF48)/* DMAC
*)0x5FFFF40)/* DMAC0
*)0x5FFFF50)/* DMAC1
*)0x5FFFF60)/* DMAC2
*)0x5FFFF70)/* DMAC3
*)0x5FFFF84)/* INTC
*)0x5FFFF90)/* UBC
*)0x5FFFFA0)/* BSC
*)0x5FFFFBC)/* SBYCR
*)0x5FFFFC0)/* PA
*)0x5FFFFC2)/* PB
*)0x5FFFFD0)/* PC
*)0x5FFFFC4)/* PFC
*)0x5FFFFF0)/* TPC
/* Change Struct
/* Change Struct
/* Change Struct
/* Change Struct
/* Change Struct
/* Change Struct
/* Change Struct

Address*/
Address*/
Address*/
Address*/
Address*/
Address*/
Address*/
Address*/
Address*/
Address*/
Address*/
Address*/
Address*/
Address*/
Address*/
Address*/
Address*/
Address*/
Address*/
Address*/
Address*/
Address*/
Address*/
ITU1
*/
ITU2
*/
ITU4
*/
DMAC1 */
DMAC2 */
DMAC3 */
PB->PA */

33

6.3 VECT.asm
;-----------------------------------------------------------------------------;
; VECT.ASM
;
; SH Series Assembler Startup Program
; Copyright (c) 1995, Hitachi Micro Systems,Inc.
;
; Set up the vector table and irq for a simple SH C program.
;
;----------------------------------------------------------.SECTION
.IMPORT
.EXPORT
.EXPORT
.EXPORT
.IMPORT
.IMPORT
.IMPORT
.IMPORT

VECT,CODE,ALIGN=4
__INIT
START
__DOSLEEP
BEGIN
_ITU2_OVF
_TM1
_T3INT
_T4INT

;----------------------------------------------------------; Start of vector table.


START:
.DATA.L
.DATA.L
.DATA.L

BEGIN
STACK
BEGIN

; vector 0, initial PC
; vector 1, initial SP
; vector 2, manual reset

.DATA.L

STACK

; vector 3, manual reset

.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L

NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect

; vector 4, illegal instruction


; vector 5, reserved
; vector 6, illegal slot instr.
; vector 7, reserved
; vector 8, reserved
; vector 9, CPU Address Error
; vector 10, DMA Address Error
; vector 11, NMI
; vector 12, User Break
; vector 13, Reserved
; vector 14, Reserved
; vector 15, Reserved
; vector 16, Reserved
; vector 17, Reserved
; vector 18, Reserved
; vector 19, Reserved
; vector 20, Reserved
; vector 21, Reserved
; vector 22, Reserved
; vector 23, Reserved
; vector 24, Reserved

PC
SP

34

.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L

NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect
NoVect

; vector 25, Reserved


; vector 26, Reserved
; vector 27, Reserved
; vector 28, Reserved
; vector 29, Reserved
; vector 30, Reserved
; vector 31, Reserved
; vector 32, Trap user vector
; vector 33, Trap user vector
; vector 34, Trap user vector
; vector 35, Trap user vector
; vector 36, Trap user vector
; vector 37, Trap user vector
; vector 38, Trap user vector
; vector 39, Trap user vector
; vector 40, Trap user vector
; vector 41, Trap user vector
; vector 42, Trap user vector
; vector 43, Trap user vector
; vector 44, Trap user vector
; vector 45, Trap user vector
; vector 46, Trap user vector
; vector 47, Trap user vector
; vector 48, Trap user vector
; vector 49, Trap user vector
; vector 50, Trap user vector
; vector 51, Trap user vector
; vector 52, Trap user vector
; vector 53, Trap user vector
; vector 54, Trap user vector
; vector 55, Trap user vector
; vector 56, Trap user vector
; vector 57, Trap user vector
; vector 58, Trap user vector
; vector 59, Trap user vector
; vector 60, Trap user vector
; vector 61, Trap user vector
; vector 62, Trap user vector
; vector 63, Trap user vector
; vector 64, IRQ0
; vector 65, IRQ1
; vector 66, IRQ2
; vector 67, IRQ3
; vector 68, IRQ4
; vector 69, IRQ5
; vector 70, IRQ6
; vector 71, IRQ7
; vector 72, DMAC0
; vector 73
; vector 74, DMAC1
; vector 75
; vector 76, DMAC2
; vector 77
; vector 78, DMAC3
; vector 79
; vector 80, ITU0-IMIA

35

.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L

NoVect ; vector 81, ITU0-IMIB


NoVect ; vector 82, ITU0-OVIO
NoVect ; vector 83, ITU0-Reserved
NoVect ; vector 84, ITU1-IMIA
NoVect ; vector 85, ITU1-IMIB
NoVect ; vector 86, ITU1-OVIO
NoVect ; vector 87, ITU1-Reserved
_TM1 ; vector 88, ITU2-IMIA
NoVect ; vector 89, ITU2-IMIB
_ITU2_OVF ; vector 90, ITU2-OVIO
NoVect ; vector 91, ITU2-Reserved
NoVect ; vector 92, ITU3-IMIA
NoVect ; vector 93, ITU3-IMIB
_T3INT ; vector 94, ITU3-OVIO
NoVect ; vector 95, ITU3-Reserved
NoVect ; vector 96, ITU4-IMIA
NoVect ; vector 97, ITU4-IMIB
_T4INT ; vector 98, ITU4-OVIO
NoVect ; vector 99, ITU4-Reserved
NoVect ; vector 100
NoVect ; vector 101
NoVect ; vector 102
NoVect ; vector 103
NoVect ; vector 104
NoVect ; vector 105
NoVect ; vector 106
NoVect ; vector 107
NoVect ; vector 108
NoVect ; vector 109
NoVect ; vector 110
NoVect ; vector 111
NoVect ; vector 112
NoVect ; vector 113
NoVect ; vector 114
NoVect ; vector 115
NoVect ; vector 116, reserved

;----------------------------------------------------------; startup code


BEGIN:
MOV
O_STACK,R15
MOV.L
O_INIT,R0
JSR
@R0
NOP
.DATA.W
0
; invalid instruction to create a break
.DATA.W
0
; invalid instruction to create a break
.DATA.W
0
; invalid instruction to create a break
.DATA.W
0
; invalid instruction to create a break
.DATA.W
0
; invalid instruction to create a break
BRA BEGIN
NOP
__DOSLEEP: SLEEP
BRA __DOSLEEP

36

NOP

O_STACK:
O_INIT:

.ALIGN 4
.DATA.L
.DATA.L

STACK
__INIT

;----------------------------------------------------------; Return Handler for No Vector


.DATA.W
.DATA.W
NoVect:

0
0

RTE

; return from exception

.DATA.W
.DATA.W
;----------------------------------------------------------; Stack.
.SECTION
.RES.L

0
0

S,STACK,ALIGN=4
256

;locate fff fffe

STACK:
.END

37

6.4 Init.c
/* init.c: program initialization */
extern void _INIT(void);
extern void _INITSCT(void);
extern void _DOSLEEP(void);
extern void main(void);
#if defined(USES_SIMIO) || defined(LCEVB)
extern void _INIT_IOLIB(void);
extern void _CLOSEALL(void);
#endif
void _INIT()
{
_INITSCT();
#if defined(USES_SIMIO) || defined(LCEVB)
_INIT_IOLIB();
#endif
main();
#if defined(USES_SIMIO) || defined(LCEVB)
_CLOSEALL();
#endif
_DOSLEEP();

6.5 Initsct.c
extern int *_D_ROM, *_B_BGN, *_B_END, *_D_BGN, *_D_END;
extern void _INITSCT();
void _INITSCT()
{
int *p, *q;
for (p=_B_BGN; p<_B_END; p++)
*p=0;
for (p=_D_BGN, q=_D_ROM; p<_D_END; p++, q++)
*p=*q;
}

38

6.6 Sect.asm
.SECTION
.SECTION
.SECTION
.SECTION
__D_ROM
__D_BGN
__D_END
__B_BGN
__B_END

.DATA.L
.DATA.L
.DATA.L
.DATA.L
.DATA.L

.EXPORT
.EXPORT
.EXPORT
.EXPORT
.EXPORT
.END

D,DATA,ALIGN=4
R,DATA,ALIGN=4
B,DATA,ALIGN=4
C,DATA,ALIGN=4

(STARTOF D)
(STARTOF R)
(STARTOF R) + (SIZEOF R)
(STARTOF B)
(STARTOF B) + (SIZEOF B)

__D_ROM
__D_BGN
__D_END
__B_BGN
__B_END

39

6.7 Main.c
/*
MAIN.CVersion 1.0 7/97 Ken Schultz
INPUTS: None
OUTPUTS: None
Function:
After initialization code has set the stack pointer and initialized
the segments, control is passed to Main. Main does the following:
1. Call Initialization routine to set up ITU, ports, interrupts.
2. Start the counters running after all set up is complete.
3. Enter an infinite loop.
All of the control function is triggered to execute by interrupt
handlers. This program uses uses 5 main interrupt handlers:
1. IMIA2 executes when ITU 2 underflows. This simply causes us to
decrement a flag so we can keep track of the total ITU2 count.
2. OVF2 executes when ITU2 overflows. Much like IMIA2, we now
increment the flag to keep track of the total. count.
3. TM1 executes when ITU1 matches GRA2. Timer 1 is set up to produce
and interrupt once every 500 usec if the SH/7034 is running at 20MHz.
The TM1 handler evokes the code to execute an iteration of the PID and
adjust the motor control vaules.
4. T3INT executes when a PWM buffer register needs to be specifically
updated during the transition from chopping wave rising to falling.
This interrupt is only enabled if a buffer register update has been
made.
5. T4INT executes when a PWM buffer register needs to be specifically
updated during the transition from chopping wae falling to rising.
This interrrupt is only enabled if a buffer register update has been
made.
Main include the following header files:
1. 7032.h defines structures which allow us to reference register
using symbolic names.
2. SHCPU.h defines volitale pointers which allow us to make memory
mapped access to SH registers using symbolic names.
3. PID.h defines symbolic names unique to this program.
Other header files may be conditionally included, however, they are
only used to include functions and definitions need when using the
simulator or evaluation board monitor.

40

*/
#if defined(USES_SIMIO) || defined(LCEVB)
#include <stdio.h>
#endif
#ifdef LCEVB
#define PBIOR (*(volatile short int *)(0x5ffffc6))
#define PBCR1 (*(volatile short int *)(0x5ffffcc))
#define PBCR2 (*(volatile short int *)(0x5ffffce))
#define PBDR (*(volatile short int *)(0x5ffffc2))
#endif
#include "7032.h"
#include "pid.h"

/* structured reg. defs */


/* definitions and Globals */

#pragma interrupt (ITU2_OVF)


#pragma interrupt (TM1)
#pragma interrupt (T3INT)
#pragma interrupt (T4INT)

main()
{
Init();
ITU.TSTR.BYTE = 0xfe;
for (;;);

/* initialize peripherals */
/* start timers running */
/* run forever */

}
Init (void)
{
/*
Name:
Version:
Date:
Author:

Init
1.0
7/25/97
Ken Schultz/Hitachi Ltd.

Function: The initialization routine sets up the following:


1. A/D converter for AN0, AN1 to work in continuous scan mode.
2. ITU general registers. These set channel 2 for phase
counting mode and channels 3 & 4 for complementary PWM mode.
The Init code stops short of actually starting the timers.
This is done later after all initialization is complete.
3. ITU channel 1 for a 500 usec continuous count.
4. ITU channel 2 for maximum count duration
5. ITU Channel 3/4 setting amplitude of chopping wave and
initial position of general registers.
6. Ports to allow ITU clocks as inputs, PWM pins as outputs

41

*/
/* Next, initialize the Bus Controller. This initializations */
/* were chosen for compatibility with the SH-1 eval board. The */
/* Wait State Control register is not initialized since it uses */
/* 1 wait state by default values. */
/* No DRAM=0, Area 6 nonmultiplexed = 0, No Warp mode = 0 */
/* 50% duty cycle on RD = 0, LBS/HBS enabled = 1 */
BSC.BCR.WORD = 0x0800;

/* Set up A/D converter */


AD.CSR.BYTE = 0x39;
AD.CR.BYTE = 0x7f;

/* scan mode, 134 state time */


/* auto scan, no ext. trigger */

/* Set up ITU General Registers */


ITU.TSTR.BYTE = 0x00;
ITU.TSNC.BYTE = 0xe0;
ITU.TMDR.BYTE = 0x60;
ITU.TFCR.BYTE = 0x6e;
ITU.TOCR.BYTE = 0xff;

/* all counters stopped */


/* all channels run independently */
/* channel 2 in phase counting mode */
/* OVF set for overflow only */
/* ITU3/4 in compl. PWM mode */
/* ITU3/4 buffer registers active */
/* controls inverting of pairs and */
/* can make them non-complementary */
/* set to keep pairs complementary */

/* Set up ITU Channel 1 for 500 usec interrupt rate */


ITU1.TCR.BYTE = 0x43;

ITU1.TIOR.BYTE = 0x2a;
temp_char = ITU1.TSR.BYTE;
ITU1.TSR.BYTE = 0xf8;
ITU1.TIER.BYTE = 0x79;
ITU1.GRA = 0x04e2;
ITU1.TCNT = 0x0000;

/* TCNT cleared when GRB matches */


/* reset value of GRB=0 */
/* increment at clock/8 */
/* generate '1' on GRB/GRA match */
/* TSR must be read before written */
/* clear all flags */
/* enable int. when GRA1 = TCNT1 */
/* at 20MHz/8 this is 500 usec */
/* initial count value */

/* Set up ITU Channel 2 for Phase Counting mode */


/* This counter is used to calculate speed, direction, and */
/* position of the motor shaft */
ITU2.TCR.BYTE = 0x40;

ITU2.TIOR.BYTE = 0x2a;
temp_char = ITU2.TSR.BYTE;
ITU2.TSR.BYTE = 0xf8;
ITU2.TIER.BYTE = 0x7d;
ITU2.GRA = 0xffff;
ITU2.TCNT = 0x0000;

/* TCNT cleared when GRB matches */


/* reset value of GRB=0 */
/* increment at TCLKA/B rate */
/* generate '1' on GRB/GRA match */
/* TSR must be read before written */
/* clear all flags */
/* enable int. for overflow */
/* max duration before overflow */
/* initial count value */

42

/* Set up ITU Channel 3 and 4 for Complementary PWM operation */


ITU3.TCR.BYTE = 0x00;
temp_char = ITU3.TSR.BYTE;
ITU3.TSR.BYTE = 0x00;
ITU3.TIER.BYTE = 0x00;
ITU3.GRA = T3_max;
ITU3.GRB = 0x0065;
ITU3.BRB = 0x0065;
ITU3.TCNT= 0x64;
ITU4.TCR.BYTE = 0x00;
temp_char = ITU4.TSR.BYTE;
ITU4.TSR.BYTE = 0x00;
ITU4.TIER.BYTE = 0x00;
ITU4.GRA = 0x0065;
ITU4.BRA = 0x0065;
ITU4.GRB = 0x0065;
ITU4.BRB = 0x0065;
ITU4.TCNT = ITU3.TCNT-DeadTime;

/* TCNT not cleared by match */


/* count rising edges only */
/* use the system clock */
/* TSR must be read before written */
/* clear all interupt flags */
/* disable interrupt on GRA3 match */
/* size of chopping wave */
/* initial value for U phase */
/* initial value for U phase */
/* starting count for PWM */
/* TCNT not cleared by match */
/* TSR must be read before written */
/* clear flags */
/* T4INT masked for now */
/* initial value for V phase */
/* initial value for V phase */
/* initial value for W phase */
/* initial value for W phase */

/* Set up the Interrupt Priority Registers for the ITU */


INTC.IPRC.WORD = 0x00ab;
INTC.IPRD.WORD = 0xced0;

/* ITU0 has priority a */


/* ITU1 has priority b */
/* ITU2 has priority c */
/* ITU3 has priority e */
/* ITU4 has priority d */

/* Set up the Ports for Input and Output */


/* The following I/O are being set as an output to enable */
/* the function of complementary PWM on channels 3 and 4
/* TIOCA3 -> Port B, bit 2
/* TIOCB3 -> Port B, bit 3
/* TIOCA4 -> Port B, bit 4
/* TIOCXA4-> Port B, bit 6
/* TIOCB4 -> Port B, bit 5
/* TIOCXB4-> Port B, bit 7
/* TCLKA and TCLKB set as input for phase counting mode
/* AN0 and AN1 set as input for A/D converter, however
/* these are set automatically and there is no port C
/* I/O control register
*/

PA.DR.WORD = 0x0000;
PB.DR.WORD = 0x0000;

*/
*/
*/
*/
*/
*/
*/
*/
*/
*/

/* Port A data reg output zero */


/* Port B data reg output zero */

/* set paior and pbior, port a and b i/o control reg */


/* This register determines if a pin on port is input or */
/* output. 0 for input, 1 for output */

43

PFC.PAIOR.WORD = 0xcfff;
PFC.PBIOR.WORD = 0xff3f;

/* set I/O as above */


/* set I/O as above */

/* set port control regs */


/* These control the exact function of individual pins */
/* They determine if the pins are dedicated to ITU or A/D */
/* or if they are GP I/O */
PFC.PACR1.WORD = 0x0a02;
PFC.PACR2.WORD = 0xaa00;
PFC.PBCR1.WORD = 0x0000;
PFC.PBCR2.WORD = 0xaaa0;
/* Initialize some control variables and set int masks */
sel_u = 0x00;
sel_v = 0x00;
sel_w = 0x00;
target_speed = 0x1ff;

/* flag for indicating update */


/* flag for indicating update */
/* flag for indicating update */
/* # of slot counts expected */

/* Next, calculate the values for PID gain constants. In */


/* this calculation the sampling period, T, was normalized to */
/* one. */
K[0] = Kp + Kd/T + Ki*T;
K[1] = Ki*T - 2*Kd/T;
K[2] = Kd/T - Kp;
/* This is the end of the initialization routine */
}

Speed_Calc(void)
{
/*
Name:
Verion:
Date:
Author:
Inputs:

Outputs:

Speed_Calc
1.0
7/27/97
Ken Schultz/Hitachi Ltd.
ITU2_flag = the number of overflows of TCNT2
TCNT2 = the current count of the ITU2 counter
Last_ITU2 = the dword ITU2 count from last iteration
Current_Speed = the speed calculated this time
Current_Positon = the position calculated this time

Function:
Speed_Calc is called by TM1 every 500 usec. Speed_Calc uses data
from ITU channel 2 to determine the motors speed and location.
When ITU2 was put into phase counting mode, TCNT2 began to
increment 4 times for each slot that passed the optical sensor or
decrement 4 times if the motor changed direction. Each time
TCNT2 overflows from 0xffff to 0x0000, ITU2_OVF has incremented
ITU2_flag. Thus the dword composed of ITU2_flag and TCNT2

44

represent the current slot count, ITU2_Count. Since there are


1024 slots on the disk of our motor, there are 4096 counts in each
revolution of motor. Also, the time between executing
this routine is precisely 500 usec. Thus, we can calculate speed
(Hz) and position (degrees) using:
Current_Speed = (ITU2_Count - Last_ITU2)/(500 usec * 4096)
The division by the constant (500 usec * 4096) normalizes our speed
to Hz, however, it would be inefficent to perform this calculation
on every iteration of the control loop. Instead, we'll convert our
target speed value to an expected count change since it is likely
to change less often.
Current_Position = 360/Remainder(ITU2_count/4096)
Again, the division into 360 normalizes the postion value into
human terms, degrees. It's wasteful to do this everytime. We
simply need to know the number of before we complete the next
revolution.
These values are stored for use by the PID and Coil_Current
calculation routines.
*/
unsigned long ITU2_Count;

/* local for current ITU2 value */

ITU2_Count = (ITU2_flag*0x10000) + ITU2.TCNT;


current_speed = ITU2_Count - last_ITU2;
/* the simple way to get the */
/* remainder of division by 4K */
current_position = ITU2_Count && 0x00000fff;
last_ITU2 = ITU2_Count;
}

PID_Calc(void)
{
/*
Name:
Version:
Date:
Author:
Inputs:

Outputs:
Function:

PID_Calc
1.0
7/27/97
Ken Schultz/Hitachi Ltd.
Current_Speed
Current_Position
Target_Speed
i_correction = new current value to Current_Calc

This is where an actual PID calculation is performed on the


motor speed. This routine outputs the global, i_correction.
It is used by the Coil_Current routine. The coil
current routine will always adjust the coil current to some
degree based on the current motor position in order to continue
producing a sinusodial current. That action simply keeps the
motor spinning. The i_correction we calculate here is used to

45

modify the coil current that would normally be produced in order


to adjust the speed. If the system is running at exactly the
desired speed and has been for some time, the output of this
routine would be zero. Note that at the beginning of the
routine, i_correction holds the contents from our last iteration
and thus is equal to u(n-1). Also, we put the gain factors, K,
and the error values, Error, into arrays. This guarantees they
are in contiguous memory locations to facilitate use of the
MAC instruction by the compiler.
*/
error[0] = target_speed - current_speed;
/* Calculate u(n) = u(n-1) + K1*e(n) + K2*e(n-1) + K3*e(n-2) */
i_correction += K[0]*error[0] + K[1]*error[1] + K[2]*error[2];
error[2] = error[1];
/* for next iteration */
error[1] = error[0];
/* for next iteration */
}

Coil_Current_Calc(void)
{
/*
Name:
Coil_Current_Calc
Version:
1.0
Date:
8/17/97
Author:
Ken Schultz/Hitachi Ltd.
Inputs:
i_correction = new current value from PID
current_position
sygd
sygq
sin = array of sin values
Outputs:
data_u
data_v
data_w
Function:
Coil_Current_Correction runs at each iteration of the PID loop.
It's function is to read current data on the u and v phase and
determine the voltage present in those phase currently. This
information, combined with a knowledge of the current position
allows us to perform a three phase to two phase transformation.
Since we know the current position of the motor (determined during
speed_calc), we know what the correct voltages should be at this
position and can perform a correction on the ITU values to obtain
the correct voltage in each phase for this position. In addition,
we use the value of "i_correction" determined in the PID routine
make an additional adjustment for speed correction.
Remember that if we the motor is spinning at exactly the correct
speed, we still need to do coil current correction just to produce
a sinusoidal current in each phase. Thus, even if "i_correction"
is zero, we must still execute this routine. In the end, this

46

routine determines the new data values to be loaded into the ITU
buffer registers. The T3INT and T4INT routines are used to
actually load the buffer registers at the appropriate time.
NOTE: The sine table used in this routine uses values ranging
between 0 and 0x2d4. A value of 0x16a is used to represent sin(0)
and 0x2d4 for sin(90). A value of 0x000 is used for sin(240).
*/
signed long id;
signed long iq;
unsigned int an0_data;
unsigned int an1_data;
unsigned int an0_current;
unsigned int an1_current;
signed int sin240;
signed int sin90;
signed int sin330;
signed int voltage_u, voltage_v, voltage_w;

/* Perform A/D conversion to get new values of iv and iu */


do {
;;
}

/* wait till conver. done */


while (AD.CSR.BYTE && 0x80 == 0);
AD.CSR.BYTE|= 0x7f;
/* clear ADF bit, strt new conv.*/
an0_data = AD.DRA;
/* read AN0 value */
an1_data = AD.DRB;
/* read AN1 value */
/* convert the voltage values from A/D into a current
This is dependent on the external circuit and type of
Hall Effect sensor used. We are using Kohms for Rl, thus
the current range is 0 to 5K. */
an0_current = (windings * an0_data) / Rl;
an1_current = (windings * an1_data) / Rl;
/* calculate entry points into sin table for current_position,
position + 240, position + 90, position + 330. Since the
sin table has 512 entries, we must convert from degrees.
This is done by (240*512)/360, (90*512)/360, and (330*512)/360.
These constants were previously stored. Since current_position
was calculated in the range 0 to 4096, we must divide this
down by 8. */
current_position = current_position >> 3; /* div by 8 by shift */
sin240 = current_position - const240;
if (sin240 << 0) {
sin240 += 0x1ff; }
/* make is modulo 512 */

47

sin90 = current_position + const90;


if (sin90 >> 0x1ff) {
sin90 -= 0x1ff; }
/* make it modulo 512 */
sin330 = current_position + const330;
if (sin330 >> 0x1ff) {
sin330 -= 0x1ff; }
/* make it modulo 512 */

/* calculate the d and

q axis values */

id = 2 * (an0_current * Sin[current_position]-an1_current * Sin[sin240]);


iq = 2 * (an0_current * Sin[sin90] - an1_current * Sin[330]);
/* Perform Porportional Integration on the error current */
/* Calculate u(n) = u(n-1) + K1*e(n) + K2*e(n-1) + K3*e(n-2) */
error_id[0] = 0 - id;
error_iq[0] = i_correction - iq;

Vd += K[0]*error_id[0] + K[1]*error_id[1] + K[2]*error_id[2];


error_id[2] = error_id[1]; /* for next iteration */
error_id[1] = error_id[0]; /* for next iteration */
Vq += K[0]*error_iq[0] + K[1]*error_iq[1] + K[2]*error_iq[2];
error_iq[2] = error_iq[1]; /* for next iteration */
error_iq[1] = error_iq[0]; /* for next iteration */
/* Account for Back EMF using non-interacting control */

/* Convert results back to 3-phase voltage model */


voltage_u = (2*(Vd*Sin[sin90]-Vq*Sin[current_position]))/3;
voltage_v = (2*(Vd*Sin[sin330]-Vq*Sin[sin240]))/3;
voltage_w = 0 - voltage_u - voltage_w;
/* Convert 3-phase voltages to timer values */
/* NOTE: TRANSFORMATION IS NOT DONE YET!!!! */
data_u = voltage_u;
data_v = voltage_v;
data_w = voltage_w;
/* enable T3INT interrupt */
temp_char = ITU3.TSR.BYTE; /* make sure int is off */
ITU3.TSR.BYTE = 0x00;
ITU3.TIER.BYTE = 0x01;
/* enable the IMFA int */
}

void ITU2_OVF(void)

48

{
/*
Name:
Version:
Date:
Author:
Inputs:
Outputs:
Function:

ITU2_OVF
1.0
7/27/97
Ken Schultz/Hitachi Ltd.
ITU2_flag
ITU2_flag

ITU2_OVF is the interrupt handler called when TCNT2 overflows.


Since ITU2 has been set in phase counting mode, TCNT2 increments
based on the relationship between TCLKA and TCLKB. These signals
are inputs from the optical encoder connected to the motor. Our
motor has 1,024 slots on a disk connected to the motor shaft.
The phase relationship between TCLKA and TCLKB affect whether
TCNT2 increments or decrements. The total count of TCNT2,
including the number of overflows between the times TM1 executes
allows us to calculate position and speed. This routine simply
increments a flag to keep track of the total count. If the value
of ITU2_flag and TCNT2 is increasing from one TM1 period to
another, then the motor is spinning in the forward direction.
*/
if (ITU2.TCNT > 0x7fff) {
ITU2_UNDER();
}
else {
ITU2_flag++;
temp_char = ITU2.TSR.BYTE;
ITU2.TSR.BYTE = 0xf8;
}

/* an underflow must have occurred */


/* 0x10000 counts have passed */
/* TSR must be read before written */
/* clear all flags */

ITU2_UNDER(void)
{
/*
Name:
Version:
Date:
Author:
Inputs:
Outputs:
Function:

ITU2_UNDER
1.0
8/1/97
Ken Schultz/Hitachi Ltd.
ITU2_Flag
ITU2_Flag

ITU2_UNDER is the interrupt handler called when TCNT2 underflows.


Since ITU2 has been set in phase counting mode, TCNT2 decrements
based on the relationship between TCLKA and TCLKB. These signals
are inputs from the optical encoder connected to the motor. Our
motor has 1,024 slots on a disk connected to the motor shaft.
The phase relationship between TCLKA and TCLKB affect whether
TCNT2 increments or decrements. The total count of TCNT2,
including the number of overflows between the times TM1 executes
allows us to calculate position and speed. This routine simply

49

increments a flag to keep track of the total count. If the value


of ITU2_flag and TCNT2 is going down from one TM1 period to
another, then the motor is spinning in reverse.
*/
ITU2_flag--;
/* 0x10000 counts have passed */
temp_char = ITU2.TSR.BYTE; /* TSR must be read before written */
ITU2.TSR.BYTE = 0xf8;
/* clear all flags */
}

void TM1(void)
{
/*
Name:
TM1
Version:
1.0
Date:
8/1/97
Author: Ken Schultz/Hitachi Ltd.
Inputs:
None
Outputs:
None
Function:
This is the interrupt handler scheduled when ITU1 has a compare
match with GRA1. GRA1 was set by the initialization routine
such that the TCNT value will have a match every 500 usec when
the SH-1 is operating at 20 MHz. TM1 calls the Speed_Calc routine
which determines the motor speed and position (angle of rotation).
After this, a PID calculation is done. Next, we call a routine
to adjust the current in each coil based upon the position
of the shaft. This adjustment is necessary just to keep the
sinusoidal current flow. The PID routine adds a correction factor
to the normal adjustment to correct for speed error. The net
result of all the subroutines called here is that the buffer
registers of ITU3 and ITU4 will be modified. The interrupt
handlers T3INT and T4INT will take care of servicing the ITU.
NOTE: If you are solving a postion control problem, such as
holding a robot arm in a precise location, rather than maintaining
a specific speed, this code can be adapted. In this case, you
would not be interested in speed error, but position error. In
fact, you may want a speed of zero. The Speed_Calc routine also
determines position as a part of it's calculation.
*/
ITU1.TCNT = 0x0000;

/* initial count value */

Speed_Calc;
PID_Calc;
Coil_Current_Calc;

/* determine motor speed now */


/* calc. speed error and correction */
/* determine new coil current values */

temp_char = ITU1.TSR.BYTE; /* TSR must be read before written */


ITU1.TSR.BYTE = 0xf8;
/* clear all flags */
}

50

void T3INT(void)
{
/*
Name:
Version:
Date:
Author:
Inputs:
Outputs:
Function:

T3INT
1.0
8/19/97
Ken Schultz/Hitachi Ltd.
data_u, data_v, data_w
U100_set, V100_set, W100_set

This program intends to update the general registers from the


buffer registers primarily when TCNT4 underflows. To do this, we
may load the buffer registers with a new value any time after
TCNT3 matches GRA3 and before TCNT4 actually underflows. We use
interrupt produced by TCNT3 to time the event and know that it is
time to load the buffer registers with the values calculated in
Coil_Current_Correction. We only need to update the buffer
registers once each time we run the PID loop, so Coil_Current_
Correction enables the interrupts and this routine shuts them
off again.
This routine assumes that:
a. U phase uses TIOCA3, TIOCB3 --> GRB3
b. V phase uses TIOCA4, TOCXA4 --> GRA4
c. W phase uses TIOCB4, TOCXB4 --> GRB4
There are the following special cases where we can't use T3INT
to set the new buffer values:
1. If we wish to produce a duty cycle of 100%, which is done by
loading any value greater than Max(TCNT4), we must have the GR
loaded exactly when T3INT occurs. Since it is already too late
when T3INT occurs, we will instead wait until T4INT to set the
new buffer register value.
The logic in this routine is to explicitly set 0x7fff to obtain a
0% duty cycle if the new buffer value is below the minimum value
for TCNT3. This keeps us out of the prohibited zone between
TCNT3(Min) and TCNT4(Min). If the new value is greater than the
maximum value for TCNT4, then we enable an interrupt for T3INT
and set a 100% duty cycle at that time. Otherwise, we just
write the new buffer value.
*/
/* process the U phase */
if (data_u << T3_min) {
ITU3.BRB = 0x7fff;
/* set for 0% duty cycle */
}
else {
if (data_u >> T4_max) {

51

U100_set = 0x01;
temp_char = ITU4.TSR.BYTE;
ITU4.TSR.BYTE = 0x00;
ITU4.TIER.BYTE = 0x04;

/* flag for T4INT routine */


/* read/clear Timer 4 ints */

ITU3.BRB = data_u;

/* put data into buffer reg */

/* enable the OVF interrupt */

}
else {
}
}
/* process the V phase */
if (data_v << T3_min) {
ITU4.BRA = 0x7fff;
}
else {
if (data_v >> T4_max) {
V100_set = 0x01;
temp_char = ITU4.TSR.BYTE;
ITU4.TSR.BYTE = 0x00;
ITU4.TIER.BYTE = 0x04;
}
else {
ITU4.BRA = data_v;
}
}

/* set for 0% duty cycle */

/* flag for T4INT routine */


/* read/lear Timer 4 ints */
/* enable the OVF interrupt */

/* put data into buffer reg */

/* process the W phase */


if (data_w << T3_min) {
ITU4.BRB = 0x7fff;
}
else {
if (data_w >> T4_max) {
W100_set = 0x01;
temp_char = ITU4.TSR.BYTE;
ITU4.TSR.BYTE = 0x00;
ITU4.TIER.BYTE = 0x04;

/* set for 0% duty cycle */

/* flag for T4INT routine */


/* read then clear Timer 4 ints */
/* enable the OVF interrupt */

}
else {
ITU4.BRB = data_w;

/* put data into buffer reg */

}
}
/* disable the Timer 3 interrupts, coil current correct */
/* will reenable on the next iteration. */
ITU3.TIER.BYTE = 0x00;

/* disable T3 ints */

}
void T4INT(void)
{
/*
Name:

T4INT

52

Version:
Date:
Author:
Inputs:
Outputs:
Function:

1.0
8/1/97
Ken Schultz/Hitachi Ltd.
U100_set, V100_set, W100_set

This interrupts handler is used to set a given phase to a 100%


duty cycle. Since the buffer value must be tansistioned at the
T3 = GRA3 time, we use the T4 underflow time to time our loading
of the buffer register. The input flags for this int. handler
were set during a previous processing of T3INT.
*/
if (U100_set == 0x01) {
ITU3.BRB = 0x7fff;
U100_set = 0x00;
}

/* set for 100% duty cycle */


/* reset flag */

if (V100_set == 0x01) {
ITU4.BRA = 0x7fff;
V100_set = 0x00;
}

/* set for 100% duty cycle */


/* reset flag */

if (W100_set == 0x01) {
ITU4.BRB = 0x7fff;
W100_set = 0x00;
}

/* set for 100% duty cycle */


/* reset flag */

/* clear interrupt and disable */


ITU4.TIER.BYTE = 0x00;
}

53

6.8 Map File


H SERIES LINKAGE EDITOR Ver. 5.3A

LINK COMMAND LINE

LNK -LIB=c:\hitachi\tchain\hitachi\shc\lib\shclib.lib -DEB -P=p.m ST=VECT(0),B(0ffff000) -ENT=BEGIN -SU=C:\WINDOWS\TEMP\hvw53

LINK SUBCOMMANDS

INPUT DebSH\init.obj
INPUT DebSH\main.obj
INPUT DebSH\initsct.obj
INPUT DebSH\lowlvl.obj
INPUT DebSH\lowsrc.obj
INPUT DebSH\vect.obj
INPUT DebSH\sect.obj
OUTPUT DebSH\pid1.abs
EXIT

54

H SERIES LINKAGE EDITOR Ver. 5.3A


PAGE :

1
***

LIST

***

SECTION
LENGTH

NAME

START

LINKAGE EDITOR LINK MAP

END
UNIT NAME

MODULE NAME

ATTRIBUTE

CODE

NOSHR

VECT
H'00000202

H'00000000

H'00000201
vect

vect
* TOTAL ADDRESS *
H'00000202

ATTRIBUTE

DATA

H'00000000

H'00000201

H'0FFFF000

H'0FFFF07E

NOSHR

B
H'0000007F

main
main
H'0FFFF080

H'0FFFF283

H'00000204
lowsrc
lowsrc
H'0FFFF284

H'0FFFF284

H'00000000
sect
sect
H'0FFFF284

H'0FFFF413

H'00000190
_iob
_iob
H'0FFFF414

H'0FFFF417

H'00000004
_errno
_errno
* TOTAL ADDRESS *
H'00000418

ATTRIBUTE

CODE

H'0FFFF000

H'0FFFF417

NOSHR

55

P
H'0000003C

H'0FFFF418

H'0FFFF453
init

init
H'0FFFF454

H'0FFFFD77

H'00000924
main
main
H'0FFFFD78

H'0FFFFDE3

H'0000006C
initsct
initsct
H'0FFFFDE4

H'0FFFFE43

H'00000060
lowlvl
lowlvl
H'0FFFFE44

H'100000DB

H'00000298
lowsrc
lowsrc
H'100000DC

H'10000183

H'000000A8
__divlu
__divlu
H'10000184

H'100001C1

H'0000003E
__muli
__muli
H'100001C4

H'10000227

H'00000064
__s_scmp
__s_scmp
H'10000228

H'100002E5

H'000000BE
__sftl
__sftl
H'100002E8

H'100003FD

H'00000116
__sftra
__sftra
H'10000400

H'100004BD

H'000000BE
__sftrl
__sftrl

56

H SERIES LINKAGE EDITOR Ver. 5.3A


PAGE :

2
***

LIST

***

SECTION
LENGTH

NAME

START

LINKAGE EDITOR LINK MAP

END
UNIT NAME

MODULE NAME

ATTRIBUTE

CODE

NOSHR

P
H'0000004C

H'100004C0

H'1000050B
fclose

fclose
H'1000050C

H'10000573

H'00000068
freopen
freopen
H'10000574

H'100005E9

H'00000076
__q_scmp
__q_scmp
H'100005EC

H'100006A3

H'000000B8
_flclose
_flclose
H'100006A4

H'100007FF

H'0000015C
_flopen
_flopen
H'10000800

H'10000897

H'00000098
free
free
* TOTAL ADDRESS *
H'00001480

ATTRIBUTE
C
H'00000034

DATA

H'0FFFF418

H'10000897

H'10000898

H'100008CB

NOSHR

main
main
H'100008CC

H'100008EA

H'0000001F
lowsrc
lowsrc

57

H'100008EC

H'100008FF

H'00000014
sect
sect
H'10000900

H'10000916

H'00000017
_flopen
_flopen
* TOTAL ADDRESS *
H'0000007F

ATTRIBUTE

DATA

D
H'00000800

H'10000898

H'10000916

H'10000918

H'10001117

NOSHR

main
main
H'10001118

H'1000111B

H'00000004
lowlvl
lowlvl
H'1000111C

H'1000111F

H'00000004
lowsrc
lowsrc
H'10001120

H'10001120

H'00000000
sect
sect
H'10001120

H'10001123

H'00000004
_freeptr
_freeptr
* TOTAL ADDRESS *
H'0000080C

H'10000918

H'10001123

58

H SERIES LINKAGE EDITOR Ver. 5.3A


PAGE :

3
***

LIST

***

SECTION
LENGTH

NAME

START

LINKAGE EDITOR LINK MAP

END
UNIT NAME

MODULE NAME

ATTRIBUTE

STACK NOSHR

S
H'00000400

H'10001124

H'10001523
vect

vect
* TOTAL ADDRESS *
H'00000400

ATTRIBUTE

DATA

R
H'00000000

H'10001124

H'10001523

H'10001524

H'10001524

NOSHR

sect
sect
* TOTAL ADDRESS *
H'00000000

H'10001524

H'10001524

59

H SERIES LINKAGE EDITOR Ver. 5.3A


PAGE :

1
***

DEFINED SYMBOLS LIST

LINKAGE EDITOR EXTERNALLY

***
SYMBOL

ADDR

TYPE

H'000001D4

DAT

H'00000000

DAT

H'0FFFF7DC

ENT

H'100008BC

DAT

H'0FFFFAB0

ENT

H'0FFFFB02

ENT

H'0FFFF018

DAT

H'0FFFF46C

ENT

H'0FFFF038

DAT

H'100008A0

DAT

H'10000898

DAT

H'1000089C

DAT

H'0FFFF752

ENT

H'100008AC

DAT

H'1000042C

DAT

H'10000918

DAT

H'0FFFF6BA

ENT

H'100008A4

DAT

H'0FFFFB68

ENT

H'100008C4

DAT

H'100008C0

DAT

H'0FFFFCFC

ENT

NAME

BEGIN
START
_Coil_Current_Calc
_DeadTime
_ITU2_OVF
_ITU2_UNDER
_ITU2_flag
_Init
_K
_Kd
_Ki
_Kp
_PID_Calc
_Rl
_SFTRL1
_Sin
_Speed_Calc
_T
_T3INT
_T3_max
_T3_min
_T4INT

60

_T4_max
H'100008C8

DAT

H'0FFFFB40

ENT

H'0FFFF07C

DAT

H'0FFFF07D

DAT

H'0FFFF010

DAT

H'0FFFF014

DAT

H'0FFFF07E

DAT

H'100008F8

DAT

H'100008FC

DAT

H'0FFFFEDE

ENT

H'000001EA

DAT

H'100008F0

DAT

H'100008F4

DAT

H'100008EC

DAT

H'0FFFF418

ENT

H'0FFFFD78

ENT

H'0FFFFE44

ENT

H'1000111C

DAT

H'0FFFF080

DAT

H'100000DC

DAT

H'0FFFF414

DAT

H'100005EC

ENT

H'100006A4

ENT

H'10001120

DAT

H'0FFFF284

DAT

H'10000184

DAT

H'10000574

DAT

H'10000248

DAT

_TM1
_U100_set
_V100_set
_Vd
_Vq
_W100_set
__B_BGN
__B_END
__CLOSEALL
__DOSLEEP
__D_BGN
__D_END
__D_ROM
__INIT
__INITSCT
__INIT_IOLIB
___brk__
___heap__
__divlu
__errno
__flclose
__flopen
__freeptr
__iob
__muli
__quick_strcmp
__sftl

61

__sftra
H'10000308

DAT

62

H SERIES LINKAGE EDITOR Ver. 5.3A


PAGE :

2
***

DEFINED SYMBOLS LIST

LINKAGE EDITOR EXTERNALLY

***
SYMBOL

ADDR

TYPE

H'10000420

DAT

H'10001118

DAT

H'100001C4

DAT

H'0FFFFE10

ENT

H'0FFFFDE4

ENT

H'0FFFFFD6

ENT

H'100008B0

DAT

H'100008B8

DAT

H'100008B4

DAT

H'0FFFF034

DAT

H'0FFFF030

DAT

H'0FFFF070

DAT

H'0FFFF074

DAT

H'0FFFF078

DAT

H'0FFFF044

DAT

H'0FFFF050

DAT

H'0FFFF05C

DAT

H'100004C0

ENT

H'10000800

ENT

H'1000050C

ENT

H'0FFFF00C

DAT

H'0FFFF01C

DAT

NAME

__sftrl
__simio
__slow_strcmp
_charget
_charput
_close
_const240
_const330
_const90
_current_position
_current_speed
_data_u
_data_v
_data_w
_error
_error_id
_error_iq
_fclose
_free
_freopen
_i_correction
_last_ITU2

63

_lseek
H'0FFFFFE8

ENT

H'0FFFF454

ENT

H'0FFFFF54

ENT

H'10000578

DAT

H'0FFFFFFE

ENT

H'1000009A

ENT

H'0FFFF024

DAT

H'0FFFF028

DAT

H'0FFFF02C

DAT

H'0FFFF068

DAT

H'0FFFF06C

DAT

H'0FFFF020

DAT

H'0FFFF000

DAT

H'0FFFF004

DAT

H'0FFFF008

DAT

H'100008A8

DAT

H'10000046

ENT

_main
_open
_quick_strcmp1
_read
_sbrk
_sel_u
_sel_v
_sel_w
_sygd
_sygq
_target_speed
_temp_char
_temp_int
_temp_long
_windings
_write

64

Você também pode gostar