Microprocessor Applications for Laboratory Learning

advertisement
Microprocessor Applications for Laboratory
Learning
by
David Earl Robison
Submitted to the Department of Electrical Engineering and
Computer Science
in partial fulfillment of the requirements for the degree of
Master of Engineering in Electrical Engineering and Computer
Science
at the
MASSACHUSETTS INSTITUTE OF TECHNOLOGY
May 2001
5S?
c
© David Earl Robison, MMI. All rights reserved.
The author hereby grants to MIT permission to reproduce and
distribute publicly paper and electronic copies of this th( iRASSACHUSETTS
document in whole or in part.
INSTITUTE
OFTEGHNOLQGY
JUL 11 2001
.IBRARIES
Author ..........................
Department of Electrical Engineering and Computer Science
May 23, 2001
Certified by...........
Steven B. Leeb
Associate Professor
Tbsis Supervisor
Accepted by ......
Arthur C. Smith
Chairman, Department Committee on Graduate Theses
BARKER.
2
Microprocessor Applications for Laboratory Learning
by
David Earl Robison
Submitted to the Department of Electrical Engineering and Computer Science
on May 23, 2001, in partial fulfillment of the
requirements for the degree of
Master of Engineering in Electrical Engineering and Computer Science
Abstract
In this thesis, I designed, implemented, and verified a number of projects for
use in the Microprocessor Project Laboratory. I selected the development system
for the course, designing and building hardware components where necessary. I
also developed new project ideas, in addition to implementing and revising several projects used by the laboratory course in previous years. The finished set
of laboratory projects included microprocessor applications from several different fields: flourescent lamp technology, waveform generation, robotics, feedback
control, digital signal processing, and programmable logic.
Thesis Supervisor: Steven B. Leeb
Title: Associate Professor
3
4
Acknowledgments
I would like to thank my Lord and Savior, Jesus Christ. He has been my strength
when I was weak, my reason for pressing onward when I felt like giving up. In the
times that I have failed, His grace and forgiveness have brought me healing and
restoration.
I would like to thank my family, and all those people who have offered me
their love and support through all the hard times.
I would also like to thank Prof. Steve Leeb, for providing the ideas and support
necessary to complete this project.
And finally, I would like to thank Mr. David Grainger, and the Grainger
Foundation, as well as Dr. Emanuel Landsman, and the Landsman Foundation,
for the donations which have made this project possible.
5
6
Contents
1
Introduction
15
1.1
Design Considerations
. . . . . . . .
. . . . . . . . . . . . . . .
16
1.2
Main Tasks . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
17
1.3
Organization
. . . . . . . . . . . . .
. . . . . . . . . . . . . . .
17
2 A Library of Useful Hardware Tools
19
2.1
Choosing a Microprocessor . . . . . .
19
2.2
Microprocessor Accessories . . . . . .
20
2.3
R 31JP . . . . . . . . . . . . . . . . .
23
2.4
Interfacing the R31JP
. . . . . . . .
24
2.4.1
Power and Signal Connections
24
2.4.2
Robustness
. . . . . . . . . .
24
2.4.3
Additional Features . . . . . .
25
2.4.4
Daughter Card for the R31JP
26
2.5
Interfacing Peripherals . . . . . . . .
26
2.5.1
Memory-Mapped I/O Chips .
27
2.5.2
Telephone Keypad
. . . . . .
27
2.5.3
Liquid Crystal Display . . . .
30
2.5.4
Speaker
. . . . . . . . . . . . . . . . . . . . . . . . . .
3 Fluorescent Lamps
30
33
7
3.1
4
Theory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
33
3.1.1
Dynamics of a Fluorescent Bulb . . . . . . . . . . . . . . .
33
3.1.2
LC Ballast . . . . . . . . . . . . . . . . . . . . . . . . . . .
34
3.2
Hardware
3.3
An Interactive Fluorescent System
. . . . . . . . . . . . . . . . .
35
3.4
Motivation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
35
3.5
Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . .
36
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
35
Generating Waveforms
39
4.1
Motivation. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
39
4.2
Hardware
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
40
4.3
Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . .
40
Techniques for Generating Waveforms . . . . . . . . . . . .
40
Telephone Dialing . . . . . . . . . . . . . . . . . . . . . . . . . . .
42
4.3.1
4.4
5 Motor and Robot Control
5.1
Motivation.
5.2
Hardware
5.3
43
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
43
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
44
5.2.1
Current for a DC Motor . . . . . . . . . . . . . . . . . . .
44
5.2.2
Robot Arms . . . . . . . . . . . . . . . . . . . . . . . . . .
45
Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . .
46
5.3.1
Voltage for a DC Motor
. . . . . . . . . . . . . . . . . . .
46
5.3.2
Creating a PWM Waveform . . . . . . . . . . . . . . . . .
47
5.3.3
Monitoring the Robot Keypad . . . . . . . . . . . . . . . .
49
5.3.4
Recording Robot Motion . . . . . . . . . . . . . . . . . . .
50
6 Feedback Control
53
6.1
Motivation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
53
6.2
Hardware
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
54
6.3
Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . .
54
8
7 Programmable Logic
57
7.1
M otivation ................
57
7.2
Hardware and Development Tools . . .
58
7.2.1
Hardware Description Language
58
7.2.2
Compilation and Synthesis Tools
59
7.2.3
Programmable Logic Devices
.
60
7.2.4
Device Programmer . . . . . . .
60
7.2.5
Conclusions . . . . . . . . . . .
60
Implementation . . . . . . . . . . . . .
61
7.3.1
Implementing Designs in VHDL
61
7.3.2
Design Projects . . . . . . . . .
66
7.3
8 Voice Recorder
85
8.1
Motivation . . . . . . . . . . .
85
8.2
Hardware
. . . . . . . . . . .
86
8.3
8.2.1
Microphone Circuitry
86
8.2.2
Speaker Circuitry . .
86
Implementation . . . . . . . .
86
8.3.1
Record and Playback .
86
8.3.2
Sampling Rate and the Nyquist Frequency
91
8.3.3
FIR Filters
. . . . . .
92
8.3.4
Filtering Strategy . . .
93
8.3.5
Filter Implementation
94
8.3.6
Timing Constraints . .
117
9 Conclusions
119
A Schematics
121
A.1 R31JP Daughter Card ...........................
121
A.2 Fluorescent Lamp Ballast
121
. . . . . . . . . . . . . . . . . . . . .
9
A.3 Keypad
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
121
A.4 Speaker
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
125
A.5 M emory-m apped I/O Devices . . . . . . . . . . . . . . . . . . . .
125
10
List of Figures
7-1
Schematic for XC9536 Square Wave Generator . . . . . . . . . . .
72
7-2
Schematic for XC9536 Pulse Width Modulator . . . . . . . . . . .
75
7-3
Schematic for XC9536 LED Driver
. . . . . . . . . . . . . . . . .
82
7-4
Schematic for XC9536 Parallel Output Port
8-1
Schematic for Microphone and ADC
. . . . . . . . . . . .
82
. . . . . . . . . . . . . . . .
87
A-1 R31JP Daughter Card . . . . . . . . . . . . . . . . . . . . . . . .
122
A-2 Interactive Ballast for a Fluroescent Lamp . . . . . . . . . . . . .
123
A-3 Schematic for Keypad and MM74C922
. . . . . . . . . . . . . . .
124
A-4 Schematic for DAC and Speaker . . . . . . . . . . . . . . . . . . .
125
A-5 Address Decoding For Memory-Mapped I/O . . . . . . . . . . . .
126
A-6 8254 Counter/Timer . . . . . . . . . . . . . . . . . . . . . . . . .
127
A-7 8255 Parallel Port . . . . . . . . . . . . . . . . . . . . . . . . . . .
128
A-8 AD558 digital-to-analog converter . . . . . . . . . . . . . . . . . .
129
A-9 ADC0848 Analog-to-Digital Converter
130
11
. . . . . . . . . . . . . . .
12
List of Tables
5.1
Achievable Ranges for Various PWM Generators . . . . . . . . . .
49
7.1
Available Pins on Programmable Devices . . . . . . . . . . . . . .
66
7.2
Programmable Logic Specifications
66
8.1
Maximum Sampling Rates for Various Filter Implementations
13
. . . . . . . . . . . . . . . . .
. .
117
14
Chapter 1
Introduction
The MIT Department of Electrical Engineering and Computer Science offers a
laboratory course entitled "Microprocessor Project Laboratory", better known as
"6.115". Before the spring of 2001, however, this class had not been offered for
more than a year.
Over the years, courses come and go. Certain fields of study which may have
been significant 10 years ago have now become obsolete, or have lost their importance. Not so with microprocessors. Microprocessors have become a vital feature
of today's electronic landscape. From jet airplanes to cars to microwaves to cell
phones, they have made possible many technologies, appliances, and features that
people take for granted every day. Therefore, at an institute like MIT, students
must be given the opportunity to learn about microprocessors, and be equipped
to take that technology to the next level.
My thesis project was to re-create and re-design the laboratory experiments
and equipment necessary to begin offering the "Microprocessor Project Laboratory" in the spring of 2001. Given several ideas for possible laboratory exercises,
my task was to revise, modify, and implement those ideas, integrating them into
a series of experiments and projects.
15
1.1
Design Considerations
It would be fairly easy for a microprocessor laboratory course to be taught as if it
were a user's manual, a guide for how to do various tasks. The class would teach
students how to use a microprocessor, how to program in assembly, how to wire
up chips and peripheral devices. But the challenge is to create a laboratory course
which teaches students to think critically about microprocessors, and forces them
to be creative, to find new ways to do things, and to stretch the technology to its
limit.
The first design requirement, therefore, was to create microprocessor experiments which force students to think critically about the problem, and explore the
various limitations of the system involved.
The second requirement was to expose students to a representative sampling
of major microprocessor applications over the course of the semester, including
digital user interfaces, feedback control, signal processing, waveform generation,
and robotics.
A laboratory course may be able to meet these first two requirements, but if
the class causes students to hate the subject material, it has somehow failed at
its objective. Our hope is that students would enjoy taking 6.115, and would be
excited about what they have learned. This hope is the third design requirement:
the microprocessor laboratory (and the experiments associated with it) should
build interest and enthusiasm in the subject.
Many of the lab experiments considered for 6.115 required additional hardware
and equipment. But in a large laboratory class like 6.115 (expected enrollment
was between 75 and 100 students), equipment sees a lot of wear and tear over
the course of a semester. Therefore, to avoid replacing equipment after every
term, any item approved for use in 6.115 had to be rugged, hard to break, and
dependable. It also needed to be cheaply bought or easily built, given the large
number of students expected in the course.
16
This becomes the fourth (and most practical) design requirement: laboratory
equipment must be easily attainable or easily manufactured in large quantities,
hard to damage, and easy to repair.
In brief summary, there were four ideas that governed the development of
microprocessor projects for 6.115:
" Encourage students to think
* Explore a variety of practical microprocessor applications
" Generate enthusiasm for the microprocessor system design
" Accomplish all of the above with cheap, rugged, and long-lasting equipment
1.2
Main Tasks
Ideas for lab exercises which met the design requirements stated above were subjected to a deeper investigation.
The three stages or tasks involved in these
investigations are as follows:
1. Design and build the necessary hardware and interfaces
2. Demonstrate the feasibility of the proposed lab exercise
3. Demonstrate the reliability of the system involved
These three tasks had to be satisfactorily completed before a laboratory exercise could be acceptable for use in 6.115.
1.3
Organization
This report is divided into chapters, each of which discusses lab exercises considered for use in 6.115. Within each chapter, the motivation for the lab exercise will
17
be described. That will be followed by a discussion of interesting features of the
hardware and interface. There will also be a summary about the feasibility and
reliability of the lab exercise's implementation, making note of key features in the
design.
Chapter 2 describes a basic set of hardware that is necessary or useful for a
laboratory class in microprocessor technology.
Chapter 3 discusses a lab exercise involving fluorescent lamp technology.
Chapter 4 discusses a lab exercise focused on generating analog waveforms.
Chapter 5 discusses a lab exercise about motors, and robot arm control.
Chapter 6 discusses a lab exercise in feedback control, including both a firstorder and a second-order system.
Chapter 7 discusses a lab exercise focused on programmable logic devices.
Chapter 8 discusses a lab exercise about voice recording and digital signal
processing.
Chapter 9 contains a conclusion and summary of all the work completed within
the scope of this thesis project.
18
Chapter 2
A Library of Useful Hardware
Tools
Before starting to think about the specific laboratory exercises for the 6.115 curriculum, it is necessary to put together a library of basic hardware and software,
starting with the microprocessor.
2.1
Choosing a Microprocessor
When teaching a laboratory class about microprocessors, the first problem is to
decide which microprocessor to use. One approach would be to use a whole collection of different microprocessors, giving students a broad perspective of the
possibilities. But, in the end, this would only be tedious-the students would be
required to master the specifications for all the different chips, and then spend
hours re-wiring their circuits each time they switch between processors. It would
also be prohibitively expensive. A much better approach is to use a single microprocessor, allowing the course to focus more on microprocessor applications and
less on particular microprocessor specifications.
Previously, Intel's 8051 was the microprocessor of choice for 6.115. It is an
19
old part, so it lacks many of the extra features present in more recent designs.
But the Intel 8051 is very popular: there are more 8051-family microprocessors in
deployment around the world than there are of any other microprocessor. Using
the 8051 in a teaching environment will prepare students for what they'll see in
industry. Its popularity also lends another advantage: it is well-tested, tried and
true. Its simplicity also makes it a good teaching tool; with fewer details and
features, the 8051 is easier to understand, and it allow a student to focus on
general microprocessor concepts, instead of being buried in the complexity of a
more advanced chip.
A more advanced version of the 8051, Intel's 80C251, was also considered for
use in 6.115. In the end, however, the additional features were outweighed by the
increased complexity, and the 8051 was chosen as the official microprocessor of
6.115.
2.2
Microprocessor Accessories
The minimum microprocessor setup involves a bit more than just the 8051 itself.
There are several items and peripherals which must be added to the system in
order to provide basic functionality. Here is a description of those requirements:
11.0592 MHz Crystal The 8051, at the very least, requires a clock input; thus,
an oscillator crystal is necessary. The frequency of the oscillator could be
in the range of 10-15 MHz. An 11.0592 MHz crystal is best suited for this
purpose, because it allows for easy serial communication with a PC.
MAX232, DB9 Connector If the 8051's serial port will be used to communicate with a PC, a MAX232 chip and a serial connector are necessary. The
8051 use TTL logic levels (0 and 5v), but the standard for serial communication is something very different. The MAX232 translates back and forth
between the different voltage levels. And the serial connector is necessary,
20
in order to connect a serial cable (DB9 connector) between a PC and the
8051 setup.
EEPROM Unless factory-burned 8051 chips are specially ordered for 6.115,
with the desired program permanently written into the internal ROM, there
needs to be an external memory chip to contain the programs written by
students.
For this purpose, an EEPROM-Electronically Erasable Pro-
grammable Read Only Memory-will do well, because it is easily erased
and re-programmed.
RAM The 8051 contains 128 or 256 bytes of internal random-access memory
(depending on the version). For some applications, this amount of memory is
suitable, but if more data storage space is needed, another external memory
chip is needed.
The EEPROM is not sufficient, because it is read-only;
therefore, it is necessary to add RAM-Random Access Memory.
74HCT573 The 8051 has an interesting configuration for accessing external
memory. The 8 bit data bus, and the lower 8 bits of the 16-bit address
bus, are multiplexed together onto the same 8 pins of the 8051. The 8051
requires the use of an external latch: the address bus is latched onto an
external chip at the beginning of a machine cycle, so that the data bus can
take control of the 8051 pins for the remainder of the cycle. To perform
this operation, an 8-bit latch is required, and the 74HCT573 fulfills these
requirements nicely.
This is the minimum set of accessories; before a student can begin to do meaningful work, or even test simple programs, each of these chips must be correctly
wired and connected to the 8051. As to how this would be accomplished, there
were three options to choose from:
. Ask the students wire and connect the chips.
21
* Design and build a printed circuit board to meet the needs of the class, with
all the necessary hardware mentioned above.
" Buy a printed circuit board which contains all the necessary hardware.
Simply requiring each of the students to wire their own system is the easiest
choice, from the professor's point of view. Each student would receive a lab kit for
connecting and wiring chips; it would be a simple matter to have them build the
minimum system in their lab kit. But consider the students' perspective: before
they begin to program their microprocessor, they must use 75-100 separate wires
to connect all the various buses, control signals, and power lines. This process is
tedious, and includes a high probability of error. A large portion of the students'
(and teaching assistants') time would be spent de-bugging the system. It would be
a week into the term before anyone could start any of the microprocessor projects.
With that in mind, giving the students a circuit board, with the 8051 and
the minimal hardware all included, appears to be a much better solution. One
possibility was to design and build such a system ourselves. It would have been
costly and time-consuming, but it may have been worth it in the long run.
But another option was to find and buy a ready-made 8051 development system. If such a system was commercially available, and if it closely matched the
requirements for 6.115, then it would be the best solution. A product was found
which met these specifications: Rigel Corporation [7] sells a circuit board, the
R31JP, which was nearly perfect for use in 6.115. The cost of the board (minus
an educational discount) was far less than the cost (in materials and man-hours)
of designing and building the system ourselves. The R31JP included all the necessary hardware mentioned above, and in addition, contained some additional
circuitry to help in interfacing other peripheral chips. So the R31JP became the
"official" 6.115 development system.
22
2.3
R31JP
The R31JP is a very useful development system- it contains a microprocessor and
enough peripheral components to get you started on some interesting projects.
Here are some of the features which make it attractive:
Dynamic memory space The R31JP contains an EEPROM chip and a RAM
chip. This memory can be set up in any number of configurations, using
a switch and a CPLD. In the default configuration, program memory and
data memory occupy the same continuous memory space. It is also possible,
while in this default configuration, to swap the locations of the RAM and
EEPROM within the memory space. This is very useful, because it allows
for the EEPROM to be programmed with a semi-permanent operating system program. This operating system will then allow the user to down-load
program files to the RAM, and then run them. This eliminates the trouble
of having to re-burn an EEPROM each time a little change is made in the
assembly code.
Serial Port The R31JP contains the necessary hardware for connecting to a personal computer. The appropriate DB9 connector is included on the R31JP
board, as well as the appropriate serial line driver chip (MAX232 or equivalent).
Memory-mapped I/O Space If both the serial port and external memory will
be used, there are only 12 available I/O pins left for interfacing to peripheral
chips and hardware. This is not quite enough. One advantageous feature
on the R31JP is the memory-mapped I/O space- it already has a block of
memory which is devoted to external I/O. If the 8051 reads or writes to an
address in the memory-mapped I/O space, the data bus is automatically
re-routed to external peripheral chips.
23
No Wiring Necessary All of this comes ready-made on printed circuit board,
saving students from the tedious task of having to connect and wire a dozen
different components.
2.4
Interfacing the R31JP
When adapting the R31JP for use in the microprocessor lab (6.115), there were
a few problems encountered.
2.4.1
Power and Signal Connections
The R31JP needs to connect the NUBUS lab kit, in some fashion. The R31JP
would be used to control the systems developed by the students, and the lab kit
would be used to build those systems, so there needs to be an interface between
them. Some sort of adapter is necessary, because the lab kit comes equipped
with two 50-pin IDC connectors, while the R31JP contains 2 rows of header pins.
There needs to be an adapter which can covert the header pins into an IDC
cable/connector.
The R31JP requires a regulated 5 volt power supply. The most convenient
option is to use the lab kit power supplies for the R31JP, rather than buying
another power supply just for that purpose. If the R31JP is connected to the lab
kit somehow, it should be a simple matter to include power in that connection,
so that the R31JP feeds directly off of the lab kit.
2.4.2
Robustness
The system being developed will be used by hundreds of students over the years.
There will be a lot of abuse, and everything that can go wrong with our equipment
will go wrong. To that end, it is important to make things robust.
24
When connecting the R31JP to the lab kit, a few things were added to make
things more robust:
Power Regulation The power on the R31JP is coming directly from the lab
kit. And if a student plugs in the power in the wrong way, the R31JP
will suffer severe damage. To prevent such a wiring mistake from causing
damage, a power regulator was added between the R31JP and the lab kit.
This power supply takes 12V as input, and regulates it down to +5V. It is
a very inefficient power supply, generating a significant amount of heat, but
it prevents wiring mistakes from destroying the R31JP.
Signal Buffering If all the important signals on the R31JP are connected to the
lab kit, it allows the user to back-drive these signals, possibly damaging the
chips on the R31JP, or perhaps stalling the microprocessor. To prevent this,
a little protection was added-the WR#, RD#, XIOSEL#, and RESET
signals were all buffered, to prevent any back-driving by peripheral chips.
2.4.3
Additional Features
At this point, it became clear that another printed circuit board-some sort of
daughter card for the R31JP-would be necessary to connect the R31JP and the
lab kit. Once the decision was made to add an extra circuit board to the system,
it was time to add any other features which might be useful within the scope of
6.115.
This was an excellent opportunity to add blinking lights. All the signals on
Port 1 of the 8051 were connected to buffers, which lit up a bank of LEDs, such
that the LED bank displayed the data on Port 1. This bank of LEDs would serve
as visual aid, and also as a quick debugging tool.
25
2.4.4
Daughter Card for the R31JP
All of the proposed features and additions to the R31JP were integrated into a
printed circuit board design (see Figure A-1). This board was designed to sit on
top of the R31JP, plugging into the header pins as a sort of daughter card. The
cable connectors on the daughter card allow for quick and simple interfacing with
the NUBUS lab kit.
2.5
Interfacing Peripherals
When using the R31JP, there are two ways to interface peripheral chips and
components.
* Use the 8051 I/O ports. This is the simplest and easiest way to connect
peripheral chips, because the 8051 can read and write to all the I/O bits
individually. However, there is only a small number of available I/O pins on
the 8051, so it is only possible to interface a few chips this way.
9 Use the Memory-mapped I/O space. On the R31JP, the addresses FE00h
through FEFFh (hexadecimal) are reserved for memory-mapped I/O. When
the 8051 reads or writes to one of these addresses, the two memory chips are
de-activated, and the XIOSEL# line is pulled low. The XIOSEL# signal
can be used to activate peripheral devices. By decoding the lower bits of
the address, and combining them with the XIOSEL# line, it is possible to
fit several chips (up to 256) into this memory-mapped I/O space. The 8051
would select between these different devices by specifying the address of a
particular device.
When interfacing chips in the memory-mapped I/O space, a 74LS138 logic
chip can be used to decode the addresses bus and create separate chip select lines
for each of the peripheral devices (see Figure A-5 for a schematic).
26
A library of useful devices was developed for use of 6.115.
Many of these
devices required additional design and modification, in order to interface them
with the lab kit and the R31JP. The following sections contains a description of
the library of hardware devices and peripherals that were assembled for the course.
2.5.1
Memory-Mapped I/O Chips
The following chips can all be interfaced into the 8051's memory mapped I/O
space, without too much difficulty. Detailed schematics are available in the Appendix A.
* AD558 Digital-to-Analog Converter
* ADC0804 Analog-to-Digital Converter
* ADC0848 Analog-to-Digital Converter
* 8254 Counter-Timer
* 8255 Parallel I/O port
2.5.2
Telephone Keypad
A telephone-style keypad was found, available in quantity for a reasonable price.
The keypad has 8 I/O lines (one for each row and column on the keypad), and
can be plugged into the lab kit by using 8 pins of a 16-pin DIP cable/connector.
The keypad functions as a matrix: there is a wire for each of the columns, and
a wire for each of the rows. When an individual key is pressed, the corresponding
column wire and row wire are shorted together.
It would be possible to simply connect the keypad directly to the 8051. However, for it to work properly, the 8051 must be continuously polling the keypad,
to see if any of the keys are being pressed. With this setup, the following code
could be used to read key presses:
27
For this code segment, assume the following connections:
Keypad column 1 <-> P1.0
Keypad column 2 <-> P1.1
Keypad column 3 <-> P1.2
Keypad column 4 <-> P1.3
Keypad row 1 <-> P1.4
Keypad row 2 <-> P1.5
Keypad row 3 <-> P1.6
Keypad row 4 <-> P1.7
10
;
;
;
;
;
Keypad Polling Routine
This routine checks to see if any of the
keys are being pressed. If there is a key
being pressed, the index associated with
that key is placed in the accumulator.
poll-keypad:
20
; RO will be a place holder-it will keep track
; of which key is being polled at any given
; time. When a key is pressed, RO will
; contain the index of that key.
mov RO, #00h
clr 00h
; 00h is set when a key is pressed
mov P1, #OFFh
clr P1.4
jnb P1.0, key-pressed
inc RO
jnb P1.1, key-pressed
inc RO
jnb P1.2, key-pressed
inc RO
jnb P1.3, key-pressed
inc RO
Setup Port 1 for input
Pull row 1 'low'
If any key in row 1 is being
pressed, the column row
will also be 'low'.
mov P1, #OFFh
clr P1.4
jnb P1.0, key-pressed
inc RO
jnb P1.1, key-pressed
inc RO
jnb P1.2, key-pressed
inc RO
jnb P1.3, key-pressed
inc RO
; Setup Port 1 for input
; Pull row 2 'low'
mov P1, #OFFh
clr P1.4
; Setup Port 1 for input
; Pull row 3 'low'
30
40
; If any key in row 2 is being
; pressed, the column row
; will also be 'low'.
28
50
jnb
inc
jnb
inc
jnb
inc
jnb
inc
P1.0,
RO
P1.1,
RO
P1.2,
RO
P1.3,
RO
key-pressed
key-pressed
; If any key in row 3 is being
; pressed, the column row
; will also be 'low'.
key-pressed
key-pressed
60
mov P1, #OFFh
cdr P1.4
jnb P1.0, key-pressed
inc RO
jnb P1.1, key-pressed
inc RO
jnb P1.2, key-pressed
inc RO
jnb P1.3, key-pressed
inc RO
ret
;
;
;
;
;
Setup Port 1 for input
Pull row 3 'low'
If any key in row 3 is being
pressed, the column row
will also be 'low'.
70
key-pressed:
; Since RO was incremented after each individual key
; was polled, RO will now contain an index associated
; with the key that was pressed.
mov A, RO
setb 00h
ret
Fortunately, there is an integrated circuit which will perform all this task
automatically. The MM74C922 polls the keypad, and can generate an interrupt
when there is a key press, signaling to the 8051 that there is data to be read.
In this configuration, the 8051 could connect to the MM74C922 through Port 1
or the memory-mapped I/O space. Appendix A includes a schematic, describing
how the system is connected (see Figure A-3). The driver code would be:
; Get Key Routine
; This routine retrieves data from the MM74C922 (keypad decoder).
getkey:
mov P1, #OFFh
cdr P3.4
mov A, P1
setb P3.4
ani A, #OFh
; Configure Port 1 for input
; Enable data output on MM74C922
; Read data
; Disable data output
; Clear the top 4 bits (unimportant data)
29
10
mov DPTR, #keytab
movc A, c A+DPTR ; Load appropriate data from key table
ret
keytab:
; This key table maps values onto the different keys.
; This particular version of the table maps values to
; the keys as follows:
20
1 2
4 5
7 8
0 0
db
db
db
db
db
db
db
db
db
db
db
db
db
db
db
db
2.5.3
3
6
9
0
A
B
C
D
01h
02h
03h
OAh
04h
05h
06h
OBh
07h
08h
09h
OCh
00h
00h
00h
ODh
30
40
Liquid Crystal Display
The Liquid Crystal Display can be connected to the 8051 using the 8255 parallel
port. The 8255 can be used to manipulate the control lines and the data bus on
the LCD.
2.5.4
Speaker
The 8051 microprocessor is capable of driving a speaker, and creating various
sound waveforms, with the help of the DAC and a LM386 amplifier. The LM386 is
designed specifically for use with a speaker or other audio devices. The speaker can
30
be connected to the LM386 as recommended in the first example of the LM386's
application notes. Appendix A contains a complete schematic of the system (see
Figure A-4).
31
32
Chapter 3
Fluorescent Lamps
One clever way to introduce students to relevant microprocessor issues-
physical
systems, real-time computation, interrupts, feedback-is to use a fluorescent lamp.
3.1
3.1.1
Theory
Dynamics of a Fluorescent Bulb
A fluorescent bulb is a valuable innovation-it consumes a fraction of the power
required for standard incandescent bulbs. However, to light up a fluorescent bulb,
it cannot be connected directly to an AC or DC power supply. The bulb requires
ballast.
The inside of a fluorescent bulb is a partial vacuum, filled with a small concentration of gas. When the bulb is not turned on, this gas tube could be modeled
as an open circuit, or an infinite resistance. To light the bulb, a very high voltage
(200-300V) must be applied across the tube, in order to ionize the gas inside.
Once the gas is ionized, current begins to flow, and energy is emitted from
the bulb in the form of light (photons).
But at this point, the electrical char-
acteristic of the bulb changes dramatically-from an infinite resistance to a very
small resistance, practically a short circuit. When in this state, the fluorescent
33
bulb becomes very unstable. The incremental resistance is actually negative-as
current flows through the gas, it causes the gas to be ionized even further, with
further decreases the resistance the gas chamber, causing even more current to
flow. This pattern could escalate until the fluorescent bulb explodes because of
excessive current and heat dissipation.
3.1.2
LC Ballast
In order to properly control a fluorescent bulb, a ballast is necessary. This ballast
must be able to provide a very high voltage to strike the bulb and ionize the gas.
But this ballast must also be able to limit the current flowing through the bulb,
after it has been struck and lit.
An resonant inductor-capacitor (LC) circuit is the perfect solution. The fluorescent bulb can be combined with an inductor and a capacitor, as shown in
Figure . When the bulb is off, its very high resistance causes the circuit to behave like a simple series-LC circuit. If we apply an AC voltage to the system, and
tune its frequency to the resonant frequency of the LC circuit, we can create a
very high voltage across the capacitor, and across the bulb. If all the parameters
are correct, this should cause the fluorescent bulb to be lit.
Then, once the bulb has been lit, the LC circuit limits the current through the
bulb. Because of the very small resistance across the bulb, the capacitor becomes
irrelevant, and the system behaves like an inductor and resistor in series.
This LC ballast is used to drive the fluorescent bulbs in most industrial systems.
34
3.2
Hardware
3.3
An Interactive Fluorescent System
As part of the course development for 6.115, a unique version of the LC ballast
was developed.
The full schematic of this fluorescent lamp LC ballast can be
found in Appendix A (see Figure A-2). When designing the lamp ballast, the goal
was to create an interactive lab station, allowing a student to control the inputs
to the system while observing the outputs. With the fluorescent lamp providing
a visual aid, this lab station has an appealing reward for all who are able to find
the resonant frequency.
The final product contained many attractive features:
* Socket for FT4 fluorescent bulbs
" Resonant LC circuit with removable inductor and capacitor
* Isolation for the high-voltage portion of the system
" Driver circuitry, converting a TTL low-current input into a high-voltage,
high-current signal to drive the LC circuit
" Input protection diodes, to prevent a user's wiring errors from damaging the
system.
* Scaled version of the bulb voltage, available as output to the user
3.4
Motivation
This fluorescent lamp lab station is very useful for studying resonant circuits
and fluorescent bulb dynamics. But it can also be made relevant to study of
microprocessors, and is worthy of inclusion in the 6.115 curriculum.
35
One of the biggest applications that microprocessors are used for is embedded control. Microprocessors are perfect for controlling systems which cannot
be trusted to run perfectly on their own. The fluorescent lamp is an excellent
example. Every fluorescent lamp comes equipped with an LC ballast. However,
depending on the manufacturing techniques, the resonant frequency of that ballast is not guaranteed to be very exact-it could be anywhere within a certain
range of frequencies. In order to successfully light the lamp, there must be some
mechanism which finds that resonant frequency.
That's where the microprocessor comes in: it can be used to sweep through
a range of frequencies, find the resonant frequency of the ballast, and ensure the
lamp is lit.
As a laboratory exercise, this design problem would force students to deal with
many important issues:
* Real-time programming and control
" Timing constraints
* Interrupts
* Closed-loop systems
3.5
Implementation
Here's how the system works: by generating a TTL square wave, the R31JP can
drive the lamp system, and attempt to light the bulb. However, the lamp will never
be lit if the microprocessor is blindly sweeping through a range of frequencies. The
microprocessor needs some sort of feedback.
To provide the necessary feedback to the microprocessor, the voltage across
the lamp can be rectified and converted into a trigger signal. The trigger signal
can be used to alert the microprocessor when the lamp voltage exceeds a certain
36
threshold. This should give the microprocessor all the information necessary for
finding the resonant frequency of the LC circuit and lighting the lamp.
37
38
Chapter 4
Generating Waveforms
4.1
Motivation
When driving the fluorescent lamp, students are forced to explore the issues of
microprocessor timing, as they try to create square waves at very specific frequencies. But an even more powerful method for teaching issues of timing and
real-time programming is to have students create a waveform generator.
When attempting to create high-frequency waveforms, students will discover
that they are held back by the speed of the microprocessor and the inefficiencies
of their code. Hopefully, in the course of completing this lab exercise, students
will learn how to write efficient code, and also come to understand the limitations
of the 8051 microprocessor.
An exercise in waveform-generation will also provide hands-on experience in
sound systems, since generating waveforms is the core function of any stereo system.
A laboratory exploring the generation of various waveforms will be a valuable
learning experience for the 6.115 students.
39
4.2
Hardware
By using the microprocessor together with a DAC (Digital-to-Analog Converter),
it is possible to create analog voltage waveforms. Of course, the quality of these
signals will be limited by quantization effects, due to time and magnitude quantization. But the quantization noise can be reduced by simply adding an analog
filter to the system.
In addition to the DAC, a speaker can be added to the system. (A schematic
for the speaker circuitry can be found in Figure A-4.)
Over the course of this
laboratory exercise, as students generate various analog signals, their work will be
more tangible if students are permitted to listen to the signals they create. With
a speaker incorporated into the system, it is possible to convert voltage waveforms
into sound waveforms. Students will then be able to observe their waveforms in
both the electrical form and the audio form.
The speaker will also be necessary for the telephone dialing exercise included
in this lab assignment.
4.3
4.3.1
Implementation
Techniques for Generating Waveforms
If done in the right manner, it is fairly simple to write 8051 assembly code which
generates a waveform.
The MOVC command allows data to be loaded from the program memory
space. The address used to access the code data is computed using the 16-bit
data pointer (DPTR) plus an 8-bit offset. This feature can be used to create
a circular buffer. The data pointer can be loaded with the first address of the
buffer; to access all of the data in the buffer sequentially, simply increment the
8-bit offset after each use of the MOVC command. When the offset is equal to
40
255, incrementing it will cause it to overflow and return to 0, essentially creating
a 256-byte circular buffer.
This circular buffer can be used to generate periodic waveforms, according to
the following procedure:
1. Convert one period of the desired waveform into 256 equally spaced data
points.
2. Convert each data point into an 8-bit number
3. Encode those 256 8-bit data points into a program, such that they will be
loaded into 256 sequential memory locations.
4. Using the MOVC command, the data pointer (DPTR), and an 8-bit offset,
create a program loop which will periodically read a data value from the
256-byte buffer, then write it out to the DAC, incrementing the offset after
each write.
As part of this lab exercise, students will be encouraged to generate waveforms
at arbitrary frequencies, and they will therefore be forced to see the limits of the
microprocessor and the code that they've written. There are two basic methods for
varying the frequency of one of these waveforms. The first method is to change the
frequency of the code loop which writes data out to the DAC. The other method
is to change how fast you increment through a period-instead of incrementing
the offset by one after each write, the offset can be incremented by some higher
number, such that the offset steps through the table more rapidly. With either
method, there are limitations. In the first case, the limitation is the speed of the
microprocessor. In the second case, the quality of the signal is compromised as
the frequency is increased.
41
4.4
Telephone Dialing
Once students have mastered the art of generating waveforms with a microprocessor, an interesting problem to tackle is the problem of creating telephone tones.
For a telephone to work properly, a depressed key must generate two distinct tones
at very specific frequencies.
To accomplish this task, it is possible to use a simple sine wave generating
program, with just a few modifications. However, it is important to be precisefor commercial dialing to work properly, the generated tones must be within 2%
of the specified frequencies. In order to meet these specifications, a 256-byte sine
table can be used, along with a 16-bit counter. The first 8 bits of the counter
will be used to look up a value in the table; the last 8 bits are retained to reduce
round-off error, and are used when incrementing the counter.
As for the problem of simultaneously generating two distinct frequencies, it
can be done by adding and scaling the two waveforms. Two separate counters
and increments are maintained, one for each of the desired frequencies. During
each program loop, both counters are incremented, and each is used to look up
a value in the sine table. Those two values are scaled and added to produce the
proper output value for the dual-tone waveform.
42
Chapter 5
Motor and Robot Control
Motivation
5.1
Motor control is a microprocessor application which cannot be overlooked. With
increasing regularity, microprocessors are being embedded in physical systems.
These microprocessors provide processing power and govern the actions of the
system.
When embedded in such a system, there are two basic ways that a microprocessor can communicate with the physical system around it:
Actuators The microprocessor can "talk" to the physical system by providing
commands, and controlling various actuators.
Sensors The microprocessor can "listen" to the physical system, and observe its
status, by reading the signals from various sensors.
The purpose of this lab exercise is to focus on the actuators, and how to drive
them using the microprocessor, in an open-loop fashion (the next lab will combine
both actuators and sensors to do a study in closed-loop feedback control). Most of
the emphasis of this exercise will be on DC motors. Though it may seem trivial,
there are actually several subtleties involved in driving DC motors.
43
The study of motors also provides a nice lead-in to a study in simple roboticsat the end of the lab, the students will experiment with the control of a simple
robot arm.
DC motor control, as well as robot arm control, are both very important topics
in the field of microprocessor systems. It is, therefore, an essential component of
the 6.115 curriculum.
5.2
5.2.1
Hardware
Current for a DC Motor
The first issue, when driving a DC motor, is the amount of current required. A
DC motor could quite easily consume around 1 A of current (the actual current
is dependent on the motor model and the torque applied to the drive shaft). A
motor cannot be directly run from the microprocessor, because the microprocessor
can only supply around 10 or 20 mA of current. A high-current buffer is neededsomething which will give the DC motor all the current that it needs. For 6.115,
the answer was to use the LM18293 chip, a component designed specifically for
driving motors.
At this point, everything is in place-the LM18293 can be controlled directly
by the R31JP, or by a peripheral chip. And the motor can be connected directly to
the LM18293 output. Furthermore, the motor can be driven either in a unipolar
or a bipolar mode, depending on how it is connected.
To connect a motor in unipolar mode, simply ground one of the motor leads,
and connect the other to the output of an LM18293 buffer.
To connect a motor in bipolar mode, connect each of the motor leads to the
output of a separate LM18293 buffer.
By alternating the states of these two
buffers, you will be able to drive the motor in both directions. And when the two
buffers are set to the same state, the motor will be stopped.
44
5.2.2
Robot Arms
A collection of cheap, 5 degree-of-freedom robot arms were bought for use in 6.115.
These arms are available from OWI as "Robot Arm Trainers", and can be found
at any number of robot hobby stores (such as Carl's Electronics [1]). The robot
arm has a plastic frame, and is driven by low-quality DC motors, without any
sensors or feedback. But it does have its advantages: the low cost makes it easier
to afford more arms, enough to provide for a large class and keep a supply of
spares, as well. Furthermore, each of the motors is coupled with a gear box and a
slip clutch, allowing the motor to disconnect from the joint if too much external
torque is applied. This mechanism protects the motor and gear box from serious
damage, and it also allows the user to move the joints without back-driving the
motor.
This OWI robot arm has two parts: the arm itself, and a little keypad used to
control the arm. To make things interesting for the 6.115 students, we decided to
connect both the arm and the keypad directly to the R31JP (instead of to each
other). In this configuration, the microprocessor assumes complete control over
the robot arm, and is responsible for monitoring the user inputs on the keypad.
This design configuration brought up some interface issues: the robot arm
and keypad were not designed to connect to the R31JP and NUBUS lab kit. The
keypad can be connected fairly easily-it can be plugged directly into the NUBUS
lab kit, with the use of some header pins. The robot arm is slightly more difficult
to interface. In the default configuration, one lead from each of the motors is
connected to a common ground, while the other lead is left unconnected (with
the idea that it will be powered from a positive or negative voltage, to move it
forward and backward).
For 6.115, the motor terminals should all be unconnected, giving the user
complete control.
In order to use the LM18293 chip to drive the motor in a
bipolar configuration, the LM18293 must have control of both motor terminals.
45
To achieve this, a small printed circuit board was designed and built, which routes
all the motor terminals to a connector cable. This small circuit board is designed
to fit inside the robot arm, replacing the circuit board which was originally inside
the arm. The connector cable is a 16-pin cable with DIP connectors on either end;
the DIP connectors make it easy for the robot arm to interface with the NUBUS
lab kit.
It would have been possible to find robot arms with a better design and more
useful features (such as sensors for feedback control), but at this point in time,
the funds were not available. If, in the future, more funds are available for 6.115
course development, I would recommend investigation into more advanced robot
arms.
Lynxmotion [4] sells a five-axis robot arm which is driven entirely by servo
motors, allowing for precise and accurate position control. Available for $195,
this model is designed to be controlled via a serial port, but could probably be
adapted to interface with the R31JP. I recommend this model as a possibility for
future use in 6.115-much more than the OWI robot arm, it could be used to
perform precise and delicate tasks in a reliable fashion.
There is one engineer who claims to have designed a sensor system for the
OWI Robotic Arm Trainer, enabling closed-loop feedback and position control.
The limited information I found is on the Xantz Innovations website [9]. This
would be another excellent area for further investigation.
5.3
5.3.1
Implementation
Voltage for a DC Motor
As mentioned earlier, an ample amount of current must be supplied in order to
drive a DC motor. But even with an adequate current supply, there is still another
issue: DC motors are analog. There is not a single "on" voltage, and a single "off"
46
voltage. DC motors respond to a whole range of voltage inputs; these different
voltages will drive the motor at different speeds.
One possible method for driving DC motors would be to use a digital-to-analog
converter (DAC), feed that analog signal through a high-current buffer (probably
an op amp), then use the output to drive the motor. However, a simpler solution
exists, one which takes advantage of the motor's physical characteristics.
The inertia of the motor's drive shaft creates a mechanical low-pass filter.
Thus, if the motor input voltage is a high frequency signal with a DC offset, the
motor shaft will rotate smoothly, as if it were only being driven by the DC part of
the signal. This property can be exploited by digital systems to drive DC motors
at various speeds; the technique is called pulse width modulation.
A pulse-width modulated (PWM) waveform is a signal that alternates between
two different voltage levels.
The signal is usually set to have a fixed period;
however, the time spent at the high voltage relative to the time spent at the low
voltage (the duty cycle) is varied. Varying this relation will change the average
value of the signal. Driving a motor with a PWM signal (provided the frequency
is high enough) is essentially the same as driving the motor with a DC voltage
equal to the duty cycle times the high voltage.
5.3.2
Creating a PWM Waveform
There are several ways to generate PWM waveforms with the 8051 microprocessor,
and each has its own advantages and disadvantages. For this 6.115 exercise, the
students will be asked to explore these different methods of implementing PWM
waveforms.
There are a couple ways to create a PWM signal using just the 8051. The first
method involves using a counter/timer in the 8-bit auto reload mode. Suppose
you want a PWM signal with a period that is equal to 200 machine cycles on the
8051. To create such a signal with a duty cycle of 40the signal must be held high
47
for 80 cycles, then held low for 120 cycles. Here's where the timer comes in: first
we set the PWM signal high, then set up the timer to interrupt after 80 clock
cycles, by giving it the appropriate reload value. When the interrupt occurs, we
pull the PWM signal low, and change the timer reload value so that it is now set
to interrupt after 120 cycles. By alternating the timer reload value in this fashion,
and toggling an output pin on each interrupt, we can create the desired PWM
signal.
The second method for 8051 PWM generation involves more straightforward
calculation. A timer must be set up generate an interrupt at a specific frequency
(it is up to the user to decide what frequency this should be). Each time this
interrupt occurs, we increment a counter. This counter will count up through
an entire period of the PWM waveform (which would be something like 16, 64,
or 256 interrupts), and then it will roll over to zero and start again. Each time
the counter rolls over to zero, the PWM output pin is set to '1'. To create the
PWM waveform, we calculate a number (call it the "duty period") equal to the
duty cycle times the number of interrupts in a period. Every time the counter
is incremented, the current counter value is compared to the high period. If the
counter is greater than this number, the output pin is pulled low, and is left there
until the counter rolls over again.
One other method for generating PWM waveforms is to use a peripheral
chip.
The 8254 counter/timer works very well for this purpose.
One of the
counter/timers can be used to determine the period of the PWM, and another
counter/timer (the 8254 has three of them) can be used to determine the length
of the low portion of the PWM.
Table 5.1 shows a comparison of the each of these three methods, with the
respective ranges of frequency and duty cycle that each can achieve. Method 1 for
the 8051 is the method which uses a counter/timer in auto reload mode, alternating reload values to acheive a pwm waveform. Method 2 is the method which uses
48
Min Frequency
Max Frequency
Min Duty Cycle
Max Duty Cycle
8051 Method 1
80c1 Method 2
8254
(alternating reload)
(4-bit counter)
with 10 MHz clock
3.6 kHz
35 kHz
5% (at 3.6 kHz)
50% (at 35 kHz)
95% (at 3.6 kHz)
50% (at 35 kHz)
880 mHz
3.4kHz
0%
153 Hz
5 MHz
0%
93.8%
99.998% (at 153 Hz)
50% (at 5 MHz)
Table 5.1: Achievable Ranges for Various PWM Generators
a software-implemented counter to determine the PWM signal. Specifications for
the 8254 PWM genarator assume a 10 MHz clock crystal.
5.3.3
Monitoring the Robot Keypad
The robot keypad is used to distinguish between three different states: "forward",
"backward", and "off". The keypad consists of 5 terminals, representing the 5
motors in the robot arm. There are also two voltage rails representing forward
and backward motion. When a key is in the "off" position, it is not connected
to either voltage rail. When it is in the "forward" or "backward" position, it is
connected to the corresponding voltage rail.
Now, when connected straight to the robot arm, the keypad is a fairly straightforward system. However, attempting to read the robot keypad from the R31JP
presents an interesting challenge. The problem is to be able to distinguish between
the three states using binary logic.
Here is the solution: connect the keypad to Port 1 on the 8051.
We will
make use of the fact that Port 1 has internal pull-up resistors-this means that
the default input is 'high'.
Begin by setting all the Port 1 pins high. Then,
pull the "forward" voltage rail low, and read the value of the 5 terminal pins. If
any are connected to the "forward" voltage rail, they will be 'low'. Otherwise,
49
because of the pull-up resistors, the pins should all remain 'high'. Then, clear
Port 1 by setting all the pins 'high', and repeat the process, this time pulling the
"backward" voltage rail 'low', checking to see if any of the other pins are pulled
'low'. By alternating in this fashion, it is possible to determine the states of all
the keys on the keypad.
5.3.4
Recording Robot Motion
The capstone of this laboratory exercise, after tinkering with DC motors, will be
to record and automatically play back the robot arm's motion. This can be done
fairly easily.
An 8051 timer interrupt can be set up to generate the sampling/playback rate.
Each time an interrupt occurs, the 8051 will perform some action, depending on
the operating mode. Here's how the various operating modes in such a system
could work:
Regular Mode When interrupt occurs:
1. Poll keypad for user input
2. Send user command to robot arm
Record Mode When interrupt occurs:
1. Poll keypad for user input
2. Send user command to robot arm
3. Write copy of command data to memory
Playback Mode When interrupt occurs:
1. Read command data from memory
2. Send command to robot arm
50
The final problem for this lab exercise will be to combine robot arm code with
the PWM generating code. The resulting program should allow the user to drive,
record and play back robot motion at varying speeds.
51
52
Chapter 6
Feedback Control
6.1
Motivation
Electro-mechanical devices are used in a large range of commercial and industrial
systems. However, for many of these applications, it is necessary that various
system attributes be regulated to within a certain tolerance.
In practice, it is very difficult for an open-loop system to achieve that kind of
accuracy. Without sensors and feedback, a system is driving blindly, unaware of
the actual state of the system parameters. For any system requiring a high degree
of accuracy, closed-loop control is essential.
In closed-loop control, the relevant system parameters are periodically sampled, using sensors. The measured value is compared with the desired value; then,
the appropriate actuators are given new commands which are intended to compensate for the error. A closed-loop system, if well designed, will maintain a very
accurate and stable system. Even with external disturbances, the feedback will
bring the system back to the desired state.
The idea of closed-loop control is an important aspect of electro-mechanical
systems. Furthermore, microprocessors are very well-adapted for providing digital
feedback in these closed-loop systems. This makes feedback control an excellent
53
topic for study in 6.115.
6.2
Hardware
For a first-order system, we decided to use an RC circuit (resistor and capacitor
in series), because it is-by far-the easiest system to build, drive, and measure. With electro-mechanical systems (such as motors, engines, and other moving mechanisms), it is often more difficult to drive the system, and it is definitely
more difficult to measure the output. So for now, the RC system will have to suffice. And the RC circuit will serve as a very good approximation of a DC motor's
characteristics.
In the future, it would be more interesting to use an actual motor or some
other physical system for this portion of the lab exercise. But that addition will
be left as a project for future generations.
For studying second-order systems, a Buck converter lab station was used.
The Buck converter is a very efficient power converter which uses an RLC circuit.
Designed and built by Warit Wichakool [11], the lab station uses a PWM waveform
as input. The duty cycle of the PWM signal determines the ratio of the regulated
output voltage to the input voltage.
6.3
Implementation
In all closed-loop feedback systems, the physical system is being controlled to
achieve some desired result. The source of this "desired result" is either a realtime input coming directly from a user, or some programmed behavior which is
encoded in the system. For 6.115, adding a user input would mean wiring up
another A-to-D converter, since a user input is most easily implemented as a
variable analog voltage. So, to make the problem simpler, we decided to have all
54
the desired system behavior encoded within the feedback program.
An 8051 counter/timer interrupt could be reserved for generating data to represent the desired system behavior.
For the feedback control, another counter/timer interrupt on the 8051 could
be used to set the sampling and update rates. In order for the system to remain
stable, it is helpful to have the control system sampling and sending out commands
at a consistent rate.
The actual assembly code for closed-loop feedback control is fairly simple:
during each pass/check of the feedback system, first read the value of the system
variable (using the A-to-D converter). Then, subtract this value from the desired
value, and multiply by a specified gain. The result of this calculation is the new
value with which you drive the system, so the final step is to write this new value
out to the system actuator.
Of course, there may be some translation necessary, because the input (drive)
signal may not be in the same form, or on the same scale, as the output (sensor)
signal. For a detailed description, please see the code listed in the appendix.
55
56
Chapter 7
Programmable Logic
7.1
Motivation
Much of the focus of the new 6.115 course has been on interfacing peripheral
devices, controlling them to achieve a desired result. For most applications, it is
possible to find integrated circuits which contained all of the desired functionality,
and are suitable for interfacing with a microprocessor. But there may be cases in
which the ideal chip-one which contains all the desired functionality-is hard to
find. In this case, the best solution is to create that ideal device.
In recent years, there has been a growing trend to use programmable logic devices in hardware design. These programmable chips can be programmed with any
functionality, up to a certain level of complexity. Any hardware design engineer
who works with microprocessor systems will realize the value of these devicesthey are highly versatile and reusable. Programmable logic is an excellent topic
for exploration in 6.115, since it is becoming a crucial feature of digital hardware
systems.
57
7.2
Hardware and Development Tools
In order to begin working with programmable logic devices, there is a set of
minimum hardware and software requirements. Here is a basic overview of these
requirements:
" A Hardware Description Language
* A Compiler and a Synthesis Tool
" A Programmable Logic Chip
" A Device Programmer
7.2.1
Hardware Description Language
The first (and most crucial) step, when using programmable logic devices, is to
specify the functionality of the device, describing the logic to be implemented.
This can be done by writing instructions in any number of hardware description
languages. VHDL and ABEL were the two languages considered for possible use
in 6.115.
The VLSI Hardware Description Language (VHDL) is becoming an industry
standard for programmable logic design. Because of this, it seemed to be the
most practical option-of all the HDLs currently in use, VHDL is the one that
6.115 students will most likely see again, when working in the industry. Furthermore, VHDL is device independent. VHDL code can be written without committing to a specific device; a specific VHDL program could be implemented on any
programmable device, provided it has the necessary logic capabilities. Another
advantage of using VHDL is that it is also taught and used by 6.111 (MIT's digital electronics laboratory course) [6]. Using the same language for both courses
could reinforce students' knowledge and understanding of the language. The only
58
disadvantage of using VHDL is that the syntax takes a little longer to learn and
understand.
ABEL, on the other hand, has a much more straightforward and simple syntax. However, it is not necessarily device independent, since device data and pin
assignments are included in the code. Furthermore, it is not used as widely as
VHDL is.
If choosing between the two languages for use in 6.115, the author recommends
using VHDL instead of ABEL.
7.2.2
Compilation and Synthesis Tools
After encoding a design with a hardware description language, the next step is to
compile and synthesize the design. This process will convert it into a format that
can be programmed directly onto a device.
When looking for the appropriate software tools, two major manufacturers of
programmable devices were investigated: Cypress and Xilinx. These two companies distribute compiler and synthesis software, to be used in conjunction with
their respective programmable devices.
Cypress offers Warp, a VHDL compiler and synthesis package, but it is not
free [8]. MIT has a license for this software package, which enables students to
compile VHDL code within the Athena computing environment. However, this
licensed software can only be used for two different chips: a 22V10 and a Cypress
C3721 [5].
Xilinx, on the other hand, offers a suite of design, synthesis, and simulation
tools, completely free, which can be easily down-loaded from their web site [10].
This software package can be used to compile both VHDL and ABEL, and it is
capable of implementing the code on a standard 22v10 package, or on any of the
XILINX programmable logic devices. This software will not run on athena, but
it will run on any Windows machine (provided it meets the appropriate system
59
requirements).
7.2.3
Programmable Logic Devices
The two types of devices considered for 6.115 were the Cypress and Xilinx chips,
to be used with their respective compiler and synthesis tools. 6.111 uses a Cypress chip-the C3721-and it is readily available at the instrument desk in the
6.111/6.115 lab. This device is available in a 44-pin PLCC package, and can be
inserted into a NUBUS lab kit by using a PLCC-to-DIP adapter.
Xilinx offers a similar device-the XC9536-which is also small enough to be
used on a 6.115 lab kit. The XC9536 is the part used on the R31JP to control addressing modes and memory-mapped I/O. Making use of the XC9536 both for the
R31JP and for exercises in programmable logic would be advantageous: it reduces
the number of different hardware devices required for 6.115. It also provides an
excellent opportunity to reconfigure the R31JP: if students are equipped to program Xilinx devices, they will also be equipped to re-program the XC9536 which
resides on the R31JP, allowing them to re-design and re-configure that system.
7.2.4
Device Programmer
As it turns out, the 6.115 universal programmers which were being used to burn
EEPROMs are also capable of burning programmable logic devices, such as the
XC9536 or a 22V10. So there is no need to find an additional programmer.
7.2.5
Conclusions
In the end, the Xilinx software and the XC9536 were chosen to be used by 6.115,
for reasons stated above. The Xilinx software is free, and is quite flexible. Since
it supports both ABEL and VHDL, there is no need to choose between the different languages. And a large supply of Xilinx XC9536 chips have already been
60
purchased as spares for the R31JP board, so the parts are available and in stock.
Implementation
7.3
7.3.1
Implementing Designs in VHDL
Before implementing large scale designs, it is important to understand the basic
concepts and structure of VHDL and programmable logic. The sections that
follow contain a brief overview of those details.
VHDL Framework
When describing a design using VHDL, there is a basic framework which must
always be included. Many design entry tools, including the Xilinx WebPack software, will generate this framework automatically. Here is an example of that
framework, for 'halfadd', a design with two inputs ('a' and 'b') and two outputs
('sum' and 'c'):
In VHDL, two dashes ('--')
--
specify a comment line.
The following four lines add the standard logic libraries
This allows the program to use the
-- to this VHDL file.
-IEEE standard for digital logic.
library IEEE;
use IEEE.STDLOGIC_1164.ALL;
use IEEE.STDLOGIC_ARITH.ALL;
use IEEE.STDLOGIC_UNSIGNED.ALL;
--
--
The entry declaration describes the interface of a
--
new design component.
entity halfadd is
--
The port declaration within the entry declaration
specifies the name and type of each input and output
--
of this component.
--
port (a, b : in std-logic;
sum, c : out std-logic);
end halfadd;
61
--
The architecture declaration describes the internal
logic and functionality of this component.
Each architecture can be given its own name (in this case it
--
is 'comp').
---
architecture comp of halfadd is
begin
end comp;
A VHDL Case Study
To further describe and explain the syntax of VHDL, consider the following case
study: the problem is to create an 8-bit incrementer, a component which adds
one to an 8-bit number.
This problem can be broken down into two smaller problems. The first is to
design an adder-a component which adds two bits, producing a 2-bit result (a
sum bit and a carry bit). An adder of this type is commonly referred to as a
'half-adder'. Here is a VHDL implementation of such an adder:
-- File halfadd.vhd
library IEEE;
use IEEE.STDLOGIC_1164.ALL;
use IEEE.STD-LOGICARITH.ALL;
use IEEE.STD.LOGICUNSIGNED.ALL;
entity halfadd is
port (a, b : in stdlogic;
sum, c : out stdlogic);
end halfadd;
architecture comp of halfadd is
-- Purpose: add two bits, producing a sum and carry bit
--
All logic description occurs between the 'begin' and 'end'
--
statements.
begin
--
The following two statements are concurrent statements.
In a concurrent assignment statement, such as these, the
output will be updated and changed every time one of the
--
inputs change.
---
62
These two statements essentially implement an AND gate
-and an OR gate.
c <= a and b;
sum <= a xor b;
--
in
VHDL is
--
'<=
--
in C or Java.
an assignment operator,
similar to
'='
end comp;
The second part of building an 8-bit incrementer is to combine several one
bit adders into the proper configuration. An 8-bit incrementer is essentially an
8-bit adder, in simplified form. It is possible to string eight of the half-adders
together, in a ripple-carry design, to create the desired incrementer. Here is the
implementation of that design:
-- File addl_8bit.vhd
library IEEE;
use IEEE.STDLOGIC_1164.ALL;
use IEEE.STDLOGICARITH.ALL;
use IEEE.STDLOGICUNSIGNED.ALL;
entity addl_8bit is
Any inputs or outputs which are more than a single bit can
be declared as a "std-logic-vector".
Port ( a-in : in std_logicvector(7 downto 0);
out std-logic-vector(7 downto 0));
a_out
end addi_8bit;
---
architecture simple of addi_8bit is
Purpose: performs an increment operation on an
-8 bit number, using a chain of half adders.
--
--
When incorporating another VHDL component into a design,
a 'component' statement must be used within the
-architecture statement, but before the begin statement.
component halfadd
--
--
The port statement within a component declaration should
be identical to the port statement within the component's
--
original entity declaration.
--
port (a , b : in stdlogic;
sum, c : out std-logic);
end component;
63
--
Internal signals, nodes within the component which are neither
inputs or outputs, can be declared within the architecture
--
statement.
--
A signal is the equivalent an internal variable in C or Java.
signal carry : stdlogic-vector(7 downto 0);
--
begin
To instantiate a VHDL component, a "port map" statement is used.
In the first statement that follows, "halfadd" is the name of
--- the component that is being instantiated, and "hO" is the label
-- given to this specific instantiation.
hO: halfadd port map (a => a-in(O), b => '1',
sum => a-out(O), c => carry(O));
--
Inside the port map statement, all the inputs and outputs of
the component are mapped to nodes within the current
-"x => y" will map x to y, where x is an input
-- VHDL module.
-or output of the component, and y is a value or
-a node (signal, input, or output) within this VHDL module.
hi: halfadd port map (a => a-in(1), b => carry(O),
sum => a_ out(1), c => carry(1));
h2: halfadd port map (a => a-in(2), b => carry(i),
sum => a-out(2), c => carry(2));
h3: halfadd port map (a => a-in(3), b => carry(2),
sum => aout(3), c => carry(3));
h4: halfadd port map (a => a-in(4), b => carry(3),
sum => aout(4), c => carry(4));
h5: half add port map (a => a-in(5), b => carry(4),
sum => aout(5), c => carry(5));
h6: halfadd port map (a => a-in(6), b => carry(5),
sum => aout(6), c => carry(6));
h7: halfadd port map (a => a-in(7), b => carry(6),
sum => a-out(7), c => carry(7));
end simple;
--
From VHDL to the Target Device
At this point, the 8-bit incrementer is ready to be implemented on a programmable
device. A compiler/synthesis program (such as Xilinx WebPack) will check the
VHDL code for syntax errors, then attempt to create a JEDEC file for programming the specified device.
Unless directly specified, the synthesis program will arbitrarily assign pins to
the inputs and outputs of the VHDL module. In order to specify which pins are
64
assigned to the input and output signals, the specifications must be included in
a constraint or control file. The format and syntax of this file differs, depending
on the synthesis software. To assign pins with the Xilinx WebPack software, the
"vhdl-design.ucf" file must be edited, as in the following example:
//
addl-8bit.ucf
// UCF (User Constraint File) for addl_8bit.vhd, target device is a 22V10
NET "a-in<O>" LOC = "1p1";
NET "a-in<1>" LOC = "p2";
NET "ain<2>" LOC = "p3";
NET "a-in<3>" LOC = "p4";
NET "a-in<4>" LOC = "p5"1;
NET "a-in<5>" LOC = "p6";
NET "a-in<6>" LOC = "p7";
NET "a-in<7>" LOC = "p8";
NET "a-out<Q>" LOC = "p23";
NET "a_out<1>" LOC = "p22";
NET
NET
NET
NET
NET
NET
"a-out<2>"
"a-out<3>"
"a_out<4>"
"a-out<5>"
"a-out<6>"
"aout<7>"
LOC
LOC
LOC
LOC
LOC
LOC
= "p21";
= "p20";
= p19";
= "p18";
= "p17";
= "p16";
Although VHDL is device independent, pin assignment is completely device
dependent. Before assigning pins, it is important to understand which pins on the
target device are available for inputs, which pins are available for outputs, and
which pins are reserved for other purposes. In some cases, there are also specific
pins which must be used for clock or trigger inputs. Table 7.1 shows a listing of
the available pins for both the 22V10 (in a 24-pin DIP package) and the XC9536
(in a 44-pin PLCC package).
Device Selection
When selecting between different programmable devices, one must match the
requirements of the VHDL design with the capabilities of a programmable device.
Each programmable chip has a certain number of available I/O pins, a certain
number of available registers, and a finite amount of combinatorial logic capability.
65
Vcc
Ground
Input Pins
GAL22V10
XC9536
24-pin DIP
44-pin PLCC
24
12
1-11,13-23
21,32,41
10,23,31
1-9,11-14,18-20,22
24-29,33-40,42-44
1-9,11-14,18-20,22
24-29,33-40,42-44
Output Pins
Reserved
14-23
-
15-17,30
Table 7.1: Available Pins on Programmable Devices
I/O Pins
Macrocells
Registers
GAL22V10
22
10
10
XC9536
34
36
36
4 ns
250 MHz
5 ns
100 MHz
(one per macrocell)
Max Propagation Delay
Max Clock Speed
Table 7.2: Programmable Logic Specifications
The best device for a given application is the smallest or cheapest one which still
meets the requirements of the design.
Table 7.2 describes these limitations for the GAL22V10 [2] (from Lattice Semiconductor) and the XC9536 [3] (from Xilinx).
7.3.2
Design Projects
When introducing 6.115 students to programmable logic, the assignments should
be significant enough to generate interest and to familiarize the students with the
design environment. However, these assignments should not be so complex as to
be overwhelming. This section contains descriptions of several design ideas which
meet these requirements.
66
Square Wave Generator
In many of the 6.115 lab assignments, the students were asked to generate square
waves of varying frequencies.
This was performed either directly by the 8051
microprocessor, or with the 8254 counter/timer chip. An interesting assignment
would be to design and create such a device-
a counter/timer dedicated to gen-
erating square waves. A project of this sort would require students to think in
depth about timer logic design, and the constraints involved.
The code which follows is an implementation of this idea. The VHDL module
creates a square wave, using an 8-bit counter. Using an external clock as a trigger,
the counter is used to determine each half-period of the generated square wave.
When used with an external clock of frequency f, the range of possible output
frequencies is f/2 to f/512.
The first VHDL file, square-top.vhd, is a top-level structure which reads in a
data byte when prompted by an external trigger.
--
File square-top.vhd
library IEEE;
use IEEE.STDLOGIC_1164.ALL;
use IEEE.STDLOGICARITH.ALL;
use IEEE.STDLOGICUNSIGNED.ALL;
entity square-top is
-- This entity is the top-level entity in the square wave generator
in std-logic;
Port ( clock
in stdjlogic;
n_wr
in stdjlogic;
n-ce
databus : in std-logic-vector(7 downto 0);
square-out : out stdlogic);
end square-top;
architecture top of square-top is
component square_8bit
Port ( clk : in stdjlogic;
hperiod : in stdlogic-vector(7 downto 0);
s.out : out std-logic);
end component;
67
signal half-period : std-logicvector(7 downto 0);
begin
--------
Unlike concurrent statements, statements within a process
are not executed continuously.
Processes are only executed when an event occurs in the
sensitivity list. For process 'read-data', the
only signal in the sensitivity list is 'n.wr'.
Thus, the statements in 'read-data' will only be executed
when 'n-wr' changes state.
read-data: process (nwr)
-- This process latches input data.
-- The latch is enabled when n-ce is low,
-and the data latches on the rising edge of n.wr.
begin
-- Single quotes are used to denote ones and zeros ('1'
if (risingedge(nwr)) and (nce = '0') then
half-period <= data-bus;
end if;
end process read-data;
and '0')
square_8bit performs all the calculations for generating
square waves, using the byte of latched data ('halfperiod').
sq: square-8bit port map ( clk => clock, hperiod => half-period,
s_out => square-out);
end top;
---
The next VHDL file, square-8bit.vhd, uses an 8 bit counter to calculate each
half period of a square wave.
-- File square_8bit.vhd
library IEEE;
use IEEE.STD-LOGIC_1164.ALL;
use IEEE.STD-LOGICARITH.ALL;
use IEEE.STD-LOGICUNSIGNED.ALL;
entity square_8bit is
-- This entity uses a count-down timer to determine the
-half-period of a square wave.
port (clk : in stdlogic;
h.period : in stdlogic-vector(7 downto 0);
s_out : out stdjlogic);
square_8bit;
end
68
architecture top of square_8bit is
component subi_8bit
in std-logic-vector(7 downto 0);
Port ( sub-in
sub.out
out std-logic-vector(7 downto 0));
end component;
signal counter : stdjlogic-vector(7 downto 0);
signal next-counter : std-logicvector(7 downto 0);
signal square : std-logic;
begin
count-down: process (clk)
-This process updates the counter on every rising
edge of clk.
When the counter reaches zero, it is
--- reset to the initial value of "h-period", and the
"square" bit
--
is
inverted.
begin
if risingedge(clk) then
counter <= next-counter;
--
update the counter
--
Another note on processes in VHDL:
--
Changes which occur inside a process all take effect
at the same instant. So, for instance,
----
---
----
suppose a = x"00"
and b = x"01" at
the beginning of a process execution.
Then, suppose the process consists of the
following lines:
-- b <= a;
if (b = x"00") then
a <= x"44";
end if;
--
Here's what would result: b will be assigned the
value of x"00" at the end of the process.
However,
within the process, b maintains the value of x"01",
so the statement (b = x"00") evaluates to false,
--
and 'a'
----
is
equal to x"00" at the end of the process.
if (nextcounter = x"00") then
-- x"00" is a literal in hexidecimal format
counter <= h.period;
square <= not square;
end if;
end if;
end process countdown;
---
reset the counter
invert the square signal
si: subi_8bit port map ( subin => counter,
sub-out => nextcounter);
69
--
nextcounter = counter
-
1
s-out <= square;
-- write the internal "square" signal to the output "s-out"
end top;
The following VHDL file, subl_8bit.vhd, subtracts one from an 8 bit number,
using a set of one bit subtractors.
-- File subl_8bit.vhd
library IEEE;
use IEEE.STDLOGIC_1164.ALL;
use IEEE.STDLOGICARITH.ALL;
use IEEE.STDLOGICUNSIGNED.ALL;
entity subl_8bit is
-- This entity makes use of several subtracters ("halfsub")
-to subtract 1 from an 8-bit number.
Port ( sub_in
subout
end subi_8bit;
in std-logic-vector(7 downto 0);
out std-logic.vector(7 downto 0));
architecture simple of subi_8bit is
component halfsub
Port ( s_in, b_in : in std-logic;
s-out, bout : out stdlogic);
end component;
signal borrow : std-logic-vector(7 downto 0);
begin
hO: halfsub port map ( s-in => sub-in(O), bin => '1',
s-out => sub-out(O), b-out => borrow(O));
-To subtract 1 from subin, the borrow input for the first
halfsub
-is 1.
For all the other halfsub components, borrow in is
-connected to the borrow out from the previous halfsub stage.
hi: halfsub port map ( s.in => sub-in(1), bin =>
s-out => subout(1), b-out
h2: halfsub port map ( s-in => sub-in(2), bin =>
s-out => sub-out(2), bout
h3: halfsub port map ( sin => sub-in(3), bin =>
s_out => sub-out(3), b-out
h4: halfsub port map ( sin => sub-in(4), bin =>
s-out => sub-out(4), bout
70
borrow(O),
=> borrow(1));
borrow(1),
=> borrow(2));
borrow(2),
=> borrow(3));
borrow(3),
=> borrow(4));
h5: halfsub port map ( s-in => subin(5), b-in => borrow(4),
s-out => subout(5), b-out => borrow(5));
h6: halfsub port map ( s-in => subin(6), b-in => borrow(5),
s_out => subout(6), bout => borrow(6));
h7: halfsub port map ( s-in => sub-in(7), bin => borrow(6),
s_out => subout(7), bout => borrow(7));
end simple;
halfsub.vhd is the last VHDL file necessary for the square wave generator.
This code performs a one-bit subtraction.
-- File halfsub.vhd
library IEEE;
use IEEE.STDLOGIC_1164.ALL;
use IEEE.STDLOGIC_ARITH.ALL;
use IEEE.STDLOGICUNSIGNED.ALL;
entity halfsub is
d-- This entity performs one-bit subtraction, producing
-- both the difference bit and the borrow bit.
Port ( s-in : in stdlogic;
b_in : in stdjlogic;
s_out : out std-logic;
b_out : out std-logic);
end half sub;
-----
subtract in
borrow in
subtract out
borrow out
architecture simple of halfsub is
-- This architecture implements halfsub, according to
-the following truth table:
I s_out bout
-sin b-in
0
-0
0
I 0
1
0
1
I 1
-I 1
0
1
0
-0
I 0
1
-1
begin
s_out <= s-in xor b-in;
b-out <= bin and (not s-in);
end simple;
This code was implemented on the XC9536. Figure 7-1 describes how the
XC9536 was interfaced to the R31JP and the external clock.
71
+5V
01
WR
DO
QVCC
02
03
D4
D544
3
Chip Enable
VC
,2
44
4
4
D1
from
+5V
07
+5V
OE
W
IT
74LSt38
CE#
VCC
GND
OUT
CLOCK
SQUAREWAVE
C
,j-GND
XC9536
Figure 7-1: Schematic for XC9536 Square Wave Generator
Pulse Width Modulation
Another waveform that has been used frequently in 6.115 is a pulse width modulation waveform. As with the square wave generator, students would benefit from
an attempt to create their own version of a PWM waveform generating device.
A simple implementation of a PWM generator would be as follows: given an
external clock with frequency f, the period of the output waveform will be f/256.
The duty cycle will be b/256, where b is the value of the byte written to the
device. While the period is fixed, the duty cycle can be adjusted by writing the
appropriate byte to the logic device. This implementation is demonstrated in the
following VHDL code.
The first VHDL file, pwm-top.vhd, is the top level structure. It reads a data
byte when prompted by an external interrupt; that data is latched and passed on
to the PWM generating code.
-- File pwmtop.vhd
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
72
use IEEE.STDLOGICARITH.ALL;
use IEEE.STDLOGICUNSIGNED.ALL;
entity pwm-top is
-- This entity latches data input on the rising edge
The data input will be used to
-- of the write signal.
-create a pwm waveform with the sub-component "pwm_8bit".
Port ( clk
in std-logic;
n-wr : in stdjlogic;
in stdjlogic;
n_ce
in std-logic-vector(7 downto 0);
data-bus
out std-logic);
pwmout
end pwm-top;
architecture top of pwm-top is
component pwm_8bit
Port ( clk : in std.logic;
duty-period : in std-logic-vector(7 downto 0);
pwmout : out stdilogic);
end component;
signal duty-period : stdlogic-vector(7 downto 0);
-"duty-period" is the latched input data
begin
readdata: process (nwr)
begin
if (rising-edge(n-wr)) and (n-ce = '0') then
-- latch input data on the rising edge of nwr
duty-period <= data-bus;
end if;
end process read-data;
p: pwm_8bit port map ( clk => clk, duty-period => duty-period,
pwm-out => pwm-out);
-- pwm_8bit performs the pwm calculations
end top;
The next VHDL file, pwm-8bit.vhd, uses an 8 bit counter to generate a PWM
waveform.
-- File pwm_8bit.vhd
library ieee;
use ieee.std-logic-1164.all;
73
entity pwm_8bit is
port (clk : in std_logic;
duty-period : in std-logic.vector(7 downto 0);
pwm-out : out std-logic);
end pwm_8bit;
architecture top of pwm_8bit is
-- Purpose: uses a counter to create the pulse width
-- modulation waveform.
-- PWM period = 256 * clk period
-- Duty Cycle = duty-period / 256 (when duty-period !
-= 1 (when duty-period == 0)
0)
component addl_8bit
port (a-in : in std_logicvector(7 downto 0);
a-out : out std-logic-vector(7 downto 0));
end component;
signal counter : std-logicvector(7 downto 0);
signal counternext : std-logic-vector(7 downto 0);
signal pwm-next : stdlogic;
begin
count-duty: process (clk)
begin
if risingedge(clk) then
counter <= counternext;
--
update counter
-- counter will count up to 256, then roll over to 0
if (counter = x"00") then
pwmnout <= '1';
-- set output to '1' when counter rolls over to 0
elsif (counter = duty-period) then
pwm-out <= '0';
-set output to '0' when counter is equal to the
-- duty period.
end if;
---
---
Note: if duty-period = x"00", pwm-out will always
be '1' because the elsif statement will never
be executed. This is essentially a duty period of 256,
and a duty cycle of 100%.
end if;
end process count-duty;
al: addi_8bit port map ( ain => counter, a-out => counternext);
---
this component adds 1 to counter:
counter-next = counter + 1
74
9536pwm.-ch-1
- Tue May 15
08:58:12
2001
U,
WRI~p
DO
1-
VCC
vcc
vcC
2
Chip Enable from 74LS138
44
D
CE#
D2
03
04
05
D6
D7
40A
+5v
TVT
IN
9
-
7Y
14
+5V
I-
Y1
3r OE
VCC
GN D OUT
CLOCK
29
28
1F I
10
GND
GND
XND
-[=>PWMUOUT
30
TOO ITTCK ir
TMS IF
TDI
XC9536
Figure 7-2: Schematic for XC9536 Pulse Width Modulator
end top;
See Figure 7-2 for a schematic of the pwm generator as implemented on a
XC9536, interfaced to the R31JP and an external clock.
LED Driver
Though perhaps not as practical as other areas, experimenting with lights and
visual displays is one of the more enjoyable and rewarding aspects of electronics.
It would only be appropriate to include a PLD project involving LED displays.
There are an infinite number of possibilities for an assignments like this, so it
75
becomes an opportunity for creativity.
A PLD is quite appropriate for a project like this-controlling the LEDs with
a PLD allows the microprocessor to focus on other computation-intensive tasks.
Otherwise, the 8051's time and power would exhausted in running miscellaneous
timing loops and calculations for a set of blinking lights.
For the sample version of this assignment, I translated a byte into hexadecimal
characters, displaying the results on a pair of seven-segment alpha-numeric LED
displays. The code is fairly straightforward, involving a simple translation from a
data byte to a set of signals which command the LEDs.
The VHDL file hexlight.vhd is the top level of the VHDL code, responsible for
reading input bytes.
-- File hexlight.vhd
library IEEE;
use IEEE.STDLOGIC_1164.ALL;
use IEEE.STDLOGICARITH.ALL;
use IEEE.STDLOGICUNSIGNED.ALL;
entity hexlight is
Port ( databus : in stdlogicvector(7 downto 0);
n_wr : in stdjlogic;
n_ce : in std-logic;
n_ti : out stdjlogic;
--top LED segment
n_t0 : out std.logic;
n_ml : out stdlogic;
--middle LED segment
n_m0 : out std-logic;
n_bi : out std-logic;
--bottom LED segment
nb0 : out std-logic;
n_tll : out stdjlogic;
--top left LED segment
n_tl0 : out stdlogic;
n_bli : out stdlogic;
--bottom left LED segment
n-blO : out stdlogic;
n_tri : out std-logic;
--top right LED segment
n_trO : out stdlogic;
n_bri : out stdlogic;
--bottom right LED segment
n_brO : out stdlogic);
end hexlight;
architecture top of hexlight is
-Purpose: determines which LEDs should be turned on
-- to represent a byte in hexadecimal characters.
76
--
Uses hex_4bit for each of the hexadecimal digits.
component hex_4bit
port (datain : in stdilogic-vector(3 downto 0);
n-top-led : out stdlogic;
n-mid-led : out stdlogic;
n_bot-led : out stdlogic;
ntopleft-led : out stdjlogic;
n_botleftled : out std-logic;
n_toprightjled : out stdlogic;
n_botrightled : out std-logic);
end component;
signal hex-data : std-logic-vector(7 downto 0);
begin
writedata: process (n-wr)
begin
if (rising-edge(n-wr)) and (n-ce = '0') then
on the rising edge of "n.wr",
--latch "databus" into "hex-data"
hex-data <= data-bus;
end if;
end process writedata;
-- map the each nibble of "hexdata" to a "hex_4bit" component
hO: hex_4bit port map (data-in => hex-data(3 downto 0),
n-topled
=> ntO,
n_midjled => nmO,
n_botled => n~bO,
nwtopleftled => n_tlO,
n.botleft-led => n-blO,
n-topright-led => ntrO,
n_botright-led => nbrO);
hi: hex_4bit port map (data-in => hex-data(7 downto 4),
n-topled => nti,
n-midled => n-ml,
n_botled => nbi,
n-topleftled => n-tl1,
n_botleftled => n-bll,
n-toprightjled => ntri,
n-botright-led => nbri);
end top;
The second VHDL file for this project, hex_4bit.vhd, performs the necessary
calculation to translate 4 bit binary data into commands for each of the individual
LED segments on an alpha-numeric display.
77
-- File hex-4bit.vhd
library IEEE;
use IEEE.STDLOGIC_1164.ALL;
use IEEE.STDLOGICARITH.ALL;
use IEEE.STDLOGIC_UNSIGNED.ALL;
entity hex_4bit is
Port ( datain : in std-logic-vector(3 downto 0);
n.top-led : out stdjlogic;
n_midled : out std-logic;
n_botled : out stdjlogic;
n-topleftled : out stdjlogic;
n-botleft-led : out stdjlogic;
n-topright-led : out stdlogic;
n-botrightled : out stdilogic);
end hex_4bit;
architecture behavioral of hex_4bit is
-Purpose: turns on the appropriate LED segments to
-represent the 4 bit data as a hexadecimal character.
-LED signals are active low.
--
The 7-segment LED looks like this:
--
I
I
--
I
I
begin
process(data-in)
-This process sets each of the LED drivers to the appropriate
-value, according to the value of "datain".
begin
if (datain = x"O") then
n_top-led <= '0';
n-mid-led <= '1';
n_bot-led <= '0';
n_topleft-led <= '0';
n_botleftled <= '0';
n_toprightjled <= '0';
n_botrightled <= 'O';
elsif (data-in = x"1") then
n_topjled <= '1';
n_mid-led <= '1';
nbot-led <= '1';
n_topleft-led <= '1';
n-botleftjled <=
'1';
n_topright-led <= '0';
n_botrightjled <= '0';
elsif (data-in = x"2") then
78
n.topjled <= '0';
n_midled <= '0';
n-bot-led <= '0';
n-topleftjled <= '1';
n-botleft-led <= '0';
n-toprightjled <= '0';
n-botrightjled <= '1';
elsif (datain = x"3") then
n-topled <= '0';
n_midled <= '0';
n-botjled <= '0';
ntopleftjled <= '1';
n-botleftled <= '1';
n-toprightjled <= '0';
n-botrightjled <= '0';
elsif (datain = x"4") then
n-topjled <= '1';
n_midled <= '0';
n_botled <= '1';
n-topleftled <= '0';
n-botleft-led <= '1';
n-toprightjled <= '0';
n_botrightjled <= '0';
elsif (data-in = x"5") then
ntopjled <= '0';
n_midled <= '0';
n_botled <= '0';
n-topleftled <= '0';
n_botleftled <= '1';
n-toprightjled <= '1';
n-botrightjled <= '0';
elsif (datain = x"6") then
n-top-led <= '0';
n_midled <= '0';
n_botled <= '0';
n-topleftjled <= '0';
n-botleftled <= '0';
n-toprightjled <= '1';
nbotrightjled <= '0';
elsif (datain = x"7") then
n-top-led <= '0';
n_midled <= '1';
n_botled <= '1';
n-topleftled <= '1';
n_botleftled <= '1';
n-toprightjled <= '0';
n_botright-led <= '0';
elsif (datain = x"8") then
n-topjled <= '0';
n-midjled <= '0';
n_botled <= '0';
79
n_topleftjled <= '0';
n-botleftled <= '0';
n_topright-led <= '0';
n_botright-led <= '0';
elsif (data-in = x"9") then
n-top-led <= '0';
n_mid-led <= '0';
n-botjled <= '0';
n.topleft-led <= '0';
n-botleft-led <= '1';
n_topright-led <= '0';
n_botrightjled <= '0';
elsif (data-in = x"A") then
n-top-led <= '0';
n_midled <= '0';
n-bot-led <= '1';
n_topleft-led <= '0';
n_botleftled <= '0';
n-toprightjled <= '0';
n_botrightjled <= '0';
elsif (data-in = x"B") then
n-top-led <= '1';
n_midled <= '0';
n_botled <= '0';
n_topleftjled <= '0';
n_botleftled <= '0';
n_topright-led <= '1';
n_botrightjled <= '0';
elsif (data-in = x"C") then
n_topjled <= '0';
n_midled <= '1';
n_botled <= '0';
n_topleft-led <= '0';
n_botleftled <= '0';
n_toprightjled <= '1';
n.botrightjled <= '1';
elsif (data-in = x"D") then
n_topjled <= '1';
n_mid-led <= '0';
n_botled <= '0';
n_topleftjled <= '1';
n_botleftled <= '0';
ntoprightjled <= '0';
n_botright-led <= '0';
elsif (data-in = x"E") then
n_top-led <= '0';
n_midled <= '0';
n_botled <= '0';
n_topleftjled <= '0';
n_botleftled <= '0';
n_topright-led <= '1';
80
n-botright-led <= '1';
elsif (data-in = x"F") then
n-topjled <= '0';
n_midled <= '0';
n-botjled <= '1';
n.topleftled <= '0';
nbotleft-led <= '0';
n.topright-led <= '1';
n-botright-led <= '1';
end if;
end process;
end behavioral;
See Figure 7-3 for a schematic of the XC9536 LED driver. The XC9536 is
capable of supplying 24 mA of current on its output pins. This is enough to drive
the LEDs directly, without any buffer in between.
Output Port
The 8051/R31JP development system has just a few I/O ports, and for the
projects that are built in 6.115, those few I/O ports are not always enough. Thus
it is very useful to create additional input or output ports, to be added into the
memory-mapped I/O space. This problem becomes another useful PLD assignment: create an additional input or output device, similar to the 8255 peripheral
chip.
Here is a description of the code which follows: the input is a data byte and
two address bits; on the rising edge of the write signal, the data byte is latched
into the appropriate output port, determined by the address bits. The code was
targeted for the XC9536, and since this chip has only 34 pins which are available
to the user, one of the output ports is not a full byte-Port C contains only 6
bits. There were not enough I/O pins to allow for 24 bits of output.
-- File my8255.vhd
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
81
9536hexight.h-1
-T7,
May
15
08:53:41
2001
+5V1
L"
WR
C
VCC
DIm
Chip EnW@e from 74LS138
TDCCE
0
D2
-
0
LD40-40+L
Sch
Figure 7-3:
9536port.
ch-1
- Tu,
My
15
08:53:11
Mir
LEDDrve
XC9536
2001
+5V
U1
WR#
D0
01
D2
03
04
05
D06
07
31
--
PORTA,0
PORTA 1
PORTA.2
PORTA.3 -PORTA4
PORTA.5 -0
PORTA.2
PORTA.7
VCC
vcc
vCC
3
3
4
41
Chip Enable f rom 74LS138
44
CEI
Al
A0
43
42
40
39
38
37
36
.5b
34
1
SS29
28
7
29
25
24
/
10
M
PORTB.7
PORTB.6
PORTB.5
PORTB.4
PORTB.3
PORTB.2
PORT B.1
PORTB.0
PORTC.5
PORTC.4
PORTC.3
PORT C.2
PORTC.1
PORTC.0
TDO 30
TCK
TMS -TDI
GND
GND
GND
XC9536
Figure 7-4: Schematic for XC9536 Parallel Output Port
82
use IEEE.STDLOGICARITH.ALL;
use IEEE.STDLOGICUNSIGNED.ALL;
entity my8255 is
Port ( data-bus : in std.logicvector(7 downto 0);
n_ce : in std-logic;
n-wr : in stdjlogic;
address-bus : in stdjlogic-vector(1 downto 0);
aport : out std-logic.vector(7 downto 0);
bport : out std-logicvector(7 downto 0);
cport : out std-logic-vector(5 downto 0));
end my8255;
architecture top of my8255 is
Purpose: latches data to output ports on the rising
edge of n-wr.
---
--
Here is the mapping of addresses to ports:
--
address-bus = "00" : aport
---
addressbus = "01" : bport
addressbus = "10" : cport
--
address-bus = "11"
: this
address is not mapped
(the state of the device is not affected by
writing to this address)
---
begin
writedata: process(n-wr)
begin
if (rising-edge(n-wr)) and (n-ce = '0') then
-on the rising edge of "n-wr", latch the "data_bus"
-into the appropriate output port, according to the
value of "addressbus"
-case address-bus is
when "00" =>
aport <= data-bus;
when "01" =>
bport <= data-bus;
when "10" =>
cport(5) <= databus(5);
cport(4) <= data-bus(4);
cport(3) <= data-bus(3);
cport(2) <= data-bus(2);
cport(1) <= data-bus(1);
cport(0) <= data_bus(0);
when others =>
end case;
end if;
end process write-data;
end top;
83
See Figure 7-4 for a schematic of the wiring for the three-port output device.
84
Chapter 8
Voice Recorder
8.1
Motivation
Considering all the disciplines and microprocessor applications discussed to this
point, there is still one significant topic which is missing from the 6.115 course
material: digital signal processing (DSP). Adding a DSP project to the 6.115 curriculum would give students a much more complete perspective on microprocessor
applications. There are many interesting applications for DSP, but one that would
have great appeal among students is the area of speech processing.
The 6.115 archives actually contained an outline of a voice recorder project;
it had been a laboratory assignment in previous years of 6.115. The old voice
recording assignment was revived, as a means to give the students some hands-on
experience with DSP. Before assigning the project to a class of students, it was
necessary to first demonstrate the project's feasibility. Since the current 6.115
development system is slightly different from the setup used in previous years of
6.115, there could be unforeseen problems and difficulties in building the voice
recorder.
85
8.2
Hardware
The first step towards building a voice recorder is to build the necessary analog
hardware. A microphone and an analog-to-digital converter (ADC) can be used
for recording; a digital-to-analog converter (DAC) and a speaker can be used for
playback. In addition, analog filters are necessary for reducing noise in the signal.
8.2.1
Microphone Circuitry
A small FET microphone, already available in large supply from the 6.111/6.115
instrument desk, can be combined with an LM386 amplifier. An RC filter should
also be added to this circuit, to filter out high-frequency noise, before the signal
is fed to the ADC. In addition to the RC filter, a bypass capacitor was added between the ADC input and ground, to further eliminate the noise in the prototype.
Figure 8-1 shows the schematic for our prototype of the microphone circuitry.
8.2.2
Speaker Circuitry
For the speaker circuitry, one of the 6.115 speakers was connected to an LM386,
as recommended in the LM386 application notes. This setup is identical to the
speaker circuitry used in other 6.115 projects. See Figure A-4 for the schematic
of this circuit.
8.3
8.3.1
Implementation
Record and Playback
The simplest version of a microprocessor-based voice recorder will just play back
all the data points, without any digital filtering. Even with this simple system,
however, it is crucial to sample the microphone input at precise intervals. Then,
when playing the signal back to the speaker (via the DAC), the data must be
86
microphone. sch-1
Tue May 15 08:55:37 2001
+5V
+5v
RI
2.2K
313
7
|
1
0uF
_I_.
3
-
C2
UF
LM353 powered from +12V
.OuF
R2
1OK
UI
MICROPHONE
C3
2
M386
3
R37
U3-A
LM35
3+
U.3-8
1.1K
2
LM358
C5
- - 015uF
.05uF
+5V
U4
VCC
INTR
P3.4
DO
01
D2
D3
04
05
D6
2
1
DBO
081
082
D83
084
085
D06
47
0D7
RO
WRWf
CSCs
CH2
CH3
CH4
CH5
CH6
CH7
CH8
VREF
AGNO
RD
Chip Select from 74LS135
+5V
10
1
ADC0548
Figure 8-1: Schematic for Microphone and ADC
87
written at the same precise rate, in order to preserve the original signal. Here is a
basic program which records and plays back a recorded signal, prompted by input
from the 6.115 keypad:
;
;
;
;
;
**record2.asm**
This program records input from the ADC at 12.5kHz,
saving the 8 bit data samples in the RAM memory space
from 1000h to 7fO0h. The data can be played back
through the DAC.
; This program interfaces to the keypad, using the MM74C922:
keypress of '1' -> start recording
keypress of '2' -> start playback
AD=address equ
DAC-address equ
inidata-address
maxdata-address
FE14h
FEO4h
equ 0 h
equ
7Fh
10
; MSB of initial data address
; MSB of max data address
8051 hardware vectors
20
org 00h
ljmp start
; on reset, jump to start routine
org 03h
ljmp getkey ; external interrupt 0, triggered by keypad logic
org Obh
ljmp sample
; timer 0 interrupt, generating sample rate
org 13h
ljmp readad ; external interrupt 1, triggered by ADC
30
; Begin main program
start:
; R6 and R7 contain the msb and lsb of the data storage
; address. This address is used for storing data
; during recording, and also for reading data during playback.
mov R6, #init-data-address ; Assign initial memory storage
mov R7, #00h
; address to R6 and R7
icall init
; Execute initialization routine
88
40
loop:
sjmp loop
50
; Initialization routine
init:
; Disable data output for the MM74C922
; Clear status bit-set only when recording.
; Clear status bit-this bit set only
during playback.
TMOD, #02h ; Set timer 0 to 8 bit auto-reload mode
TCON, #15h ; Run timer 0, set external interrupts
; to edge-trigger.
TH, #182
; Interrupt every 74 clock cycles (12.5 kHz)
IE, #87h
; Enable timer 0 interrupt, both ext. interrupts
setb P3.4
clr 00h
clr 01h
mov
mov
mov
mov
ret
60
; Interrupt routine for data sampling and playback
70
; Checks status bits:
; If in record mode, samples ADC, writes to memory,
and increments address.
; If in playback mode, reads memory, writes to DAC,
and increments address.
; If in neither mode, does nothing.
sample:
jb 00h, record
jb 01h, playback
reti
; If 00h set, go to record routine
; If 01h set, go to playback routine
80
record:
; This code is written for use with the ADC0848
; analog-to-digital converter.
mov dptr, #ADC-address
mov A, #08h
; Write configuration byte,
movx @dptr, A
; and trigger new conversion.
reti
90
playback:
mov DPH, R6
mov DPL, R7
movx A, @dptr
; Read stored data from memory.
mov DPTR, #DAC-address
movx UDPTR, a
; Write data to DAC.
lcall inc-address
; Run address incrementing routine
89
reti
100
;
;
;
;
;
;
Increment Address Routine
This routine increments the data storage address.
If address goes beyond the allocated memory space,
the address, along with all status bits, is reset
to their initial values. This will cause recording
and playback to stop.
inc-address:
inc R7
mov A, R7
jnz inc.done
inc R6
; Increment
lsb of address
110
; Check for overflow
; When overflow occurs, increment msb
; Compare address to limit.
cjne R6, #max-data-address, incdone
; If limit has been exceeded, reset state variables.
mov R6, #init-data-address
mov R7, #00h
cdr 00h
Clear record status bit
cdr 01h
; Clear playback status bit
120
inc-done:
ret
; Get Key Routine
This routine retrieves data from the MM74C922 (keypad decoder),
; and is executed each time a key is pressed.
; If the keypress is a '1', the record status bit is set.
; If the keypress is a '2', the playback status bit is set.
; If the keypress is anything else,
no state variables are changed.
getkey:
mov P1, #OFFh
cdr P3.4
mov A, P1
setb P3.4
ani A, #OFh
mov P1, A
;
;
;
;
;
;
Configure Port 1 for input
Enable data output on MM74C922
Read data
Disable data output
Clear the top 4 bits (unimportant data)
check it out on P1 after keypad deactivated
; Check for '1' keypress (A = 00h)
cjne A, #00h, key-notzero
setb 00h
, Set record status bit
cdr 01h
; Clear playback status bit
90
130
140
sjmp getkey-done
150
key-notzero:
; Check for '2' keypress (A = 01h)
cjne A, #01h, getkey-done
; Clear record status bit
cir 00h
setb 01h
; Set playback status bit
getkey-done:
reti
160
; Read ADC Routine
; This routine reads a value from the ADC, writes it
; to memory, then runs the increment address routine.
; This interrupt routine will be run each time the ADC
; signals that a conversion is complete.
readad:
mov DPTR, #ADC-address
movx A, @dptr
; Read ADC
mov DPH, R6
mov DPL, R7
movx @DPTR, A ; Write data to memory
Icall inc-address
reti
8.3.2
Sampling Rate and the Nyquist Frequency
According to the Nyquist criterion, the maximum bandwidth of a sampled signal
is one half of the sampling rate. So, for instance, to accurately record a signal
with a 2kHz bandwidth (one whose highest frequency is 2kHz), the signal must
be sampled at 4kHz or higher.
If the Nyquist criterion is not satisfied, there will be aliasing-high frequency
signals will be converted to lower frequencies. So, for instance, suppose a 2.5kHz
is sampled at 4kHz. When the recorded result is played back, it will not be a
2.5kHz signal. Instead, it will be a 1.5kHz signal, because of aliasing.
91
170
The standard bandwidth for recording and transmitting the human voice is
3.1kHz. (This is the bandwidth for telephone transmissions.) So, in order to create a decent voice recorder, the microphone input should be sampled at 6.2kHz
or higher. However, there is still a potential problem: the signals being recording
will very likely contain frequencies above 3.1kHz. These high frequency signals
could come from ambient audio noise in the room, or just from electrical noise in
the various electrical components. Whatever the source, these higher frequency
signals will be aliased, and pollute the recorded signal with lower-frequency noise.
To solve this problem, the high-frequency components of the signal must be eliminated, using a low-pass filter. There are two ways to do this:
1. Filter the signal before sampling it, using an analog filter
2. Sample the signal at a higher rate, then use a digital filter
An analog filter works well, but it is hard to create one with a sharp cutoff. A
digital filter can be created with a very sharp cutoff, but it is limited by its bandwidth. Even with fast sampling rates, there is still the possibility of aliasing. For
this project, both an analog filter and a digital filter will be used, to combine their
strengths and mask their weaknesses. The analog filter (as shown in Figure 8-1)
should be designed with a cutoff frequency equal to the desired signal bandwidth.
The digital filter will be discussed in the next section.
8.3.3
FIR Filters
The simplest way to perform digital filtering is to use a finite impulse response
(FIR) filter. When implementing an FIR filter, the data points of the filter are
convolved with the data points of the signal. For an n-point FIR filter, this will
involve n multiplications for each sample point of your signal.
FIR filters can be easily computed using Matlab. The following Matlab commands were used to create a 4-point, an 8-point, and a 16-point filter, each with
92
a cutoff frequency equal to one fourth of the sample rate:
4ptfilter = 256 * FIR1(3, 0.5)
8ptfilter = 256 * FIR1(7, 0.5)
16pt.filter = 256 * FIR1(15,
0.5)
The filter coefficients are scaled by 256, in order to make them representable
as bytes.
8.3.4
Filtering Strategy
The ideal recording system will cleanly record over a 3.1kHz bandwidth, filtering
out all frequencies over 3.1kHz. If sampling at 6.2kHz, it will be very hard to
filter out all the higher frequencies, because they will be aliased into the 3.1kHz
bandwidth. So the sampling rate will be set to 12.4kHz instead. At this sampling
rate, it is possible to filter out frequencies between 3.1kHz and 6.2kHz. (It is still
possible for frequencies of 9.3kHz and greater to be aliased into the 3.1kHz range,
but the analog filter should eliminate those frequencies before digital sampling
occurs.)
After sampling at 12.4kHz, the resulting digital signal will have a 6.2kHz bandwidth. An FIR low-pass filter is used to eliminate the frequencies between 3.1kHz
and 6.2kHz. After filtering, every other data point can be thrown away (essentially down-sampling to a 6.25kHz sample rate) since all the useful information is
now contained within a 3.1kHz bandwidth.
However, when playing back the stored signal, it must be restored to the
original 12.4kHz sample rate. This can easily be done by first inserting zeros in
between all the sample points, then filtering the result, using the same 3.1kHz
low-pass filter that was used on the input.
93
8.3.5
Filter Implementation
The simplest way to implement a digital filter is to perform the calculations after
the recording is finished, but before playback begins. When done this way, there
is no definite time constraint on the filtering process (other than user impatience).
In this case, the maximum sampling rate is limited only by the conversion speed
of the ADC. And there are no limitations on the size of the FIR filter. The only
disadvantage to this method is that it requires more memory space. Unlike other
filter implementations, in this case every sampled data point must be stored in
memory. This will limit the amount of data you can record. Here is the assembly
code for a program which implements a voice recorder in this fashion:
;
;
;
;
;
;
;
**record4.asm**
This program records input from the ADC at 12.5kHz,
saving the 8 bit data samples in the RAM memory space
from 1000h to 7fOOh.
Immediately after recording stops, the saved data is
filtered. After filtering completes, the data can
be played back through the DAC.
; This program interfaces to the keypad, using the MM74C922:
keypress of '1'
keypress of '2'
ADC-address equ
DAC-address equ
init-data-address
max-data-address
->
->
10
start recording
start playback
FE14h
FE04h
equ
10h
equ
7Fh
; MSB of initial data address
; MSB of max data address
20
; 8051 hardware vectors
org 00h
ljmp start
; on reset, jump to start routine
org 03h
ljmp getkey ; external interrupt 0, triggered by keypad logic
org Obh
ljmp sample ; timer 0 interrupt, generating sample rate
org 13h
94
30
ljmp readad ; external interrupt 1, triggered by ADC
; Begin main program
start:
40
; R6 and R7 contain the msb and Isb of the data storage
; address. This address is used for storing data
; during recording, and also for reading data during playback.
mov
R6, #init-data-address ; msb of write address
; lsb of write address
mov R7, #00h
MOV SP, #2Fh
; Internal memory locations 60h through 67h contain
; the coefficients for an 8 point FIR filter.
; These coefficients were calculated in Matlab,
50
; using the command "8pt-filter = 256 * FIR1(7, 0.5)".
; The coefficients are scaled by 256 so that, after
; multiplication, the high byte of the 16 bit result
; will be the integer portion of the product.
;
;
;
;
;
;
;
;
For example: given a coefficient c, 0<c<1, and
a data point d, first scale c by 256. The product
of d and the scaled version of c is (c * d * 256).
The high byte of the result is c * d. This byte
is the integer portion of the product of c and d,
not taking into account quantization and round-off error.
Since the object of the multiplication is to find
c * d, this data manipulation makes
60
; the filter calculations relatively simple:
; multiply the scaled coefficient by the data point,
; and save the product high byte as the result, ignoring the
; the product low byte.
70
; Initialize filter coefficients:
; First coefficient = -1
mov 60h, #1
; -6
mov 61h, #6
mov 62h, #25
mov 63h, #110
mov 64h, #110
mov 65h, #25
mov
mov
66h, #6
67h, #1
; 25
; 110
; 110
; 25
; -6
; -1
80
Icall init
loop 1 :
95
jnb
00h, loopi
loop2:
jb 00h, loop2
; Loop until recording begins
; Loop until recording stops
loop3:
; When program flow control reaches this point, a complete set
; of data has just been recorded.
mov IE, #00h
90
; Disable interrupts durign filter calculation
; Internal memory locations 40h through 47h contain a sliding window
; of data points. After each filter calculation, data is shifted
; down along this window, and a new data point is read from memory
; and placed in 47h.
mov 40h, #00h
; Reset data registers
mov 41h, #00h
mov 42h, #00h
mov 43h, #00h
mov 44h, #00h
mov 45h, #00h
mov 46h, #00h
mov 47h, #00h
setb 02h
icall dsp
; Set 02h when DSP filtering is in progress.
; Filter recorded data
mov IE, #87h
ljmp loop1
; Re-enable interrupts
; Repeat sequence
100
110
; DSP Routine
; This routine convolves an 8 point filter with
; a set of data. The filter coefficients are
; located in internal memory, addresses 60h to 67h.
; Data is stored in external memory.
dsp:
mov
mov
mov
mov
mov
mov
mov
40h,
41h,
42h,
43h,
44h,
45h,
46h,
41h
42h
43h
44h
45h
46h
47h
120
; Shift data registers
130
mov
mov
movx
mov
DPH, R6
DPL, R7
A, @dptr
47h, a
; Read new data point from memory
; Move new data into shifting window
96
; The following code performs filter multiplication.
; Multiplications involving positive coefficients
; are performed first. Only the high byte of the product
; is saved; the product high bytes are cumulatively added
; together to produce a result.
mov A, 42h
140
mov B, 62h
mul AB
mov
RO, B
mov
mov
add
mov
A, 43h
B, 63h
AB
A, RO
A, B
RO, A
mov
A, 44h
mov
B, 64h
mul
mov
150
mul AB
mov A, RO
add A, B
mov
RO, A
mov
A, 45h
160
mov B, 65h
mul AB
mov A, RO
add B, B
mov RO, A
; The remaining multiplications all involved negative
; filter coefficients. The calculations will remain
; the same, except that the products will be subtracted
; from the cumulative total, rather than being added.
cr
C
170
; Set up for subtractions
mov
A, 40h
mov B, 60h
mul AB
mov A, RO
subb A, B
mov
RO, A
180
A, 41h
B, 61h
mul AB
mov A, RO
subb A, B
mov
mov
97
mov RO, A
mov
mov
mul
mov
subb
mov
A, 46h
B, 66h
AB
A, RO
A, B
RO, A
mov
mov
mul
mov
subb
A, 47h
B, 67h
AB
A, RO
A, B
190
200
dsp-write:
movx @DPTR, A
icall inc-address
jb 02h, dsp
ret
Write filtered data back to memory
Run address incrementer
; If status bit is set, continue;
; otherwise, return to main loop.
; Initialization routine
210
init:
setb P3.4
clr 00h
clr 01h
clr 02h
;
;
;
;
Disable data output for the MM74C922
Clear status bit-set only when recording.
Clear status bit-set only during playback.
Clear status bit-set only when filtering.
mov TMOD, #02h
mov TCON, #15h
mov THO, #182
mov IE, #87h
ret
; Set timer 0 to 8 bit auto-reload mode
Run timer 0, set external interrupts
to edge-trigger.
; Interrupt every 74 clock cycles (12.5 kHz)
Enable timer 0 interrupt, both ext. interrupts
220
; Interrupt routine for data sampling and playback
; Checks status bits:
;If in record mode, samples ADC, writes to memory,
and increments address.
; If in playback mode, reads memory, writes to DAC,
and increments address.
; If in neither mode, does nothing.
sample:
jb 00h, record
; If 00h set, go to record routine
98
230
jb 01h, playback
reti
; If 01h set, go to playback routine
240
record:
; This code is written for use with the ADC0848
; analog-to-digital converter.
mov dptr, #ADC-address
mov A, #08h
; Write configuration byte,
; and trigger new conversion.
movx @dptr, A
reti
playback:
mov DPH, R6
mov DPL, R7
; Read stored data from memory.
movx A, @dptr
mov DPTR, #DAC-address
; Write data to DAC.
movx @DPTR, a
Icall inc-address
; Run address incrementing routine
reti
; Increment Address Routine
; This routine increments the data storage address.
; If address goes beyond the allocated memory space,
; the address, along with all status bits, is reset
; to their initial values. This will cause recording
; and playback to stop.
inc-address:
inc R7
mov A, R7
jnz inc-done
inc R6
; Increment
250
260
lsb of address
; Check for overflow
; When overflow occurs, increment msb
270
; Compare address to limit.
cjne R6, #maxdata-address, incdone
; If limit has been exceeded, reset state variables.
mov R6, #init-data-address
mov R7, #00h
; Clear record status bit
clr 00h
; Clear playback status bit
clr 01h
280
inc-done:
ret
; Get Key Routine
; This routine retrieves data from the MM74C922 (keypad decoder),
99
;
;
;
;
and is executed each time a key is pressed.
If the keypress is a '1', the record status bit is set.
If the keypress is a '2', the playback status bit is set.
If the keypress is anything else,
no state variables are changed.
getkey:
mov P1, #OFFh
cdr P3.4
mov A, P1
setb P3.4
anI A, #OFh
mov P1, A
;
;
;
;
;
;
Configure Port 1 for input
Enable data output on MM74C922
Read data
Disable data output
Clear the top 4 bits (unimportant data)
check it out on P1 after keypad deactivated
290
300
; Check for '1' keypress (A = 00h)
cjne A, #00h, key-notzero
setb 00h
Set record status bit
cdr 01h
; Clear playback status bit
sjmp getkey-done
key-notzero:
; Check for '2' keypress (A = 01h)
cjne A, #01h, getkey-done
cdr 00h
Clear record status bit
setb 01h
; Set playback status bit
310
getkey-done:
reti
; Read ADC Routine
; This routine reads a value from the ADC, writes it
; to memory, then runs the increment address routine.
; This interrupt routine will be run each time the ADC
; signals that a conversion is complete.
readad:
mov DPTR, #ADC-address
movx A, @dptr
; Read ADC
mov DPH, R6
mov DPL, R7
movx ©DPTR, A
; Write data to memory
Icall inc-address
reti
100
320
330
If the filtering is performed in real-time, processing the data immediately after
being sampled, there are several time constraints. When a data point is sampled,
all the computation for that data point must be completed before the next point
is sampled, otherwise the computation will lag behind. This creates a trade-off
between sampling rate and filter size. A larger filter will produce a better result,
but because of the computation required, it requires a reduction in sampling rate,
reducing the bandwidth. A smaller filter will not be as thorough in eliminating
noise, but it will allow for an increased sampling rate, since less computation
is required. Here is an example of code which implements an 8-point real-time
decimation filter:
; **record9.asm**
;
;
;
;
;
This program records input from the ADC at 12.5kHz,
filters the data, down-samples by 2, then stores the
result in the RAM memory space from 1000h to 7fO0h.
When played back, the data is up-sampled and
filtered again before being played through the DAC.
; This program interfaces to the keypad, using the MM74C922:
keypress of '1' -> start recording
keypress of '2' -> start playback
ADC-address
DAC-address
equ
equ
init-data-address
max-data-address
10
FE14h
FE04h
equ
equ
10h
7Fh
; MSB of initial data address
; MSB of max data address
; 8051 hardware vectors
20
org 00h
ljmp start
; on reset, jump to start routine
org 03h
ljmp getkey ; external interrupt 0, triggered by keypad logic
org Obh
ljmp sample ; timer 0 interrupt, generating sample rate
30
; Begin main program
101
start:
; R6 and R7 contain the msb and lsb of the data storage
; address. This address is used for storing data
during recording, And also for reading data during playback.
mov R6, #init-data-address ; msb of write address
mov R7, #00h
; lsb of write address
Mov SP, #2Fh
; Initialize filter coefficients:
mov 60h, #1
First coefficient = -1
mov 61h, #6
-6
mov 62h, #25
25
mov 63h, #110
; 110
mov 64h, #110
110
mov 65h, #25
; 25
mov 66h, #6
-6
mov 67h, #1
-1
40
50
icall init
loop:
sjmp loop
60
; Initialization routine
init:
setb P3.4
clr 00h
clr 01h
clr 02h
clr 03h
;
;
;
;
;
Disable data output for the MM74C922
Clear status bit-set only when recording.
Clear status bit-set only during playback.
Clear status bit-set only when filtering.
Clear status bit
mov TMOD, #02h
mov TCON, #15h
mov THO, #124
mov IE, #83h
ret
; Set timer 0 to 8 bit auto-reload mode
; Run timer 0, set external interrupts
70
to edge-trigger.
Interrupt every 132 clock cycles (7 kHz)
Enable timer 0 interrupt, ext. interrupt 0
; Interrupt routine for data sampling and playback
80
Checks status bits:
If in record mode, samples ADC, filters and
down-samples data, writes to memory,
and increments address.
102
; If in playback mode, reads memory, up-samples
and filters data, writes to DAC,
and increments address.
; If in neither mode, does nothing.
sample:
jb 00h, record
jb 01h, playback
reti
90
; If
; If
00h set, go to record routine
01h set, go to playback routine
record:
; This code is written for use with the ADC0848
; analog-to-digital converter.
mov DPTR, #ADC-address
mov A, #08h
; Write configuration byte,
movx @DPTR, A ; and trigger new conversion.
lcall filter
; Filter previous data
jnb 03h, readad
; Save every other data point
mov DPH, R6
mov DPL, R7
movx ©DPTR, A
lcall inc-address
100
; Write filtered data back to memory
; Increment address
110
readad:
; In this program, filter calculation takes longer
; than ADC conversion, so there is no need to wait
; for the conversion to complete. The ADC can
; be read immediately after finishing the
; filter calculations.
mov DPTR, #ADC-address
movx A, LDPTR ; Read new data from ADC
cpl 03h
mov
mov
mov
mov
mov
mov
mov
mov
40h, 41h
41h, 42h
42h, 43h
43h, 44h
44h, 45h
45h, 46h
46h, 47h
47h, A
120
; Shift the data window
; Shift in new data
130
reti
playback:
mov R1, #00h
jnb 03h, playback-filter
; Insert zeros between every data point
103
mov DPH, R6
mov DPL, R7
movx A, @DPTR
mov R1, A
Icall inc-address
playback-filter:
mov 40h, 41h
mov 41h, 42h
mov 42h, 43h
mov 43h, 44h
mov
; Read data from external memory
; Increment address
140
; Shift the data window,
; shifting in new data.
44h, 45h
mov 45h, 46h
mov 46h, 47h
mov 47h, R1
Icall filter
rl a
150
; Filter current set of data
; multiply by 2 (to restore original magnitude)
mov DPTR, #DACaddress
movx @DPTR, A ; write filter output to DAC
cpl 03h
reti
160
; Filter Routine
; This routine convolves an 8 point filter with
;a set of data. The filter coefficients are
; located in internal memory, Addresses 60h to 67h.
; The data is also located in internal memory,
addresses 40h to 47h.
;*===========================================
filter:
170
; The following code performs filter multiplication.
; Multiplications involving positive coefficients
; are performed first. Only the high byte of the product
; is saved; the product high bytes are cumulatively added
; together to produce a result.
mov A, 42h
mov B, 62h
mul AB
mov RO, B
180
mov A, 43h
mov B, 63h
mul AB
mov A, RO
add A, B
mov RO, A
104
mov A, 44h
mov B, 64h
mul AB
mov A, RO
add A, B
mov RO, A
190
mov A, 45h
mov B, 65h
mul AB
mov A, RO
add A, B
mov RO, A
200
; The remaining multiplications all involved negative
; filter coefficients. The calculations will remain
; the same, except that the products will be subtracted
; from the cumulative total, rather than being added.
; Set up for subtractions
cdr C
mov A, 40h
mov B, 60h
mul AB
mov A, RO
subb A, B
mov RO, A
mov
mov
mul
mov
subb
mov
A, 41h
B, 61h
AB
A, RO
A, B
RO, A
mov
mov
mul
mov
subb
mov
A, 46h
B, 66h
AB
A, RO
A, B
RO, A
mov
mov
mul
mov
subb
ret
A, 47h
B, 67h
AB
A, RO
A, B
210
220
230
105
; Increment Address Routine
; This routine increments the data storage address.
; If address goes beyond the allocated memory space,
; the address, along with all status bits, is reset
; to their initial values. This will cause recording
; and playback to stop.
inc-address:
inc R7
mov A, R7
jnz inc-done
inc R6
; Increment
240
Isb of address
; Check for overflow
; When overflow occurs, increment msb
250
Compare address to limit.
cjne R6, #max-data-address, incdone
; If limit has been exceeded, reset state variables.
mov R6, #init-data-address
mov R7, #00h
cdr 00h
Clear record status bit
cdr 01h
; Clear playback status bit
cdr 02h
; Clear filter status bit
cdr 03h
inc-done:
ret
Get Key Routine
This routine retrieves data from the MM74C922 (keypad decoder),
and is executed each time a key is pressed.
If the keypress is a '1', state variables are
reset for recording mode.
; If the keypress is a '2', state variables are
reset for playback mode.
If the keypress is anything else,
no state variables are changed.
260
;
;
;
;
getkey:
mov P1, #OFFh
cdr P3.4
mov A, P1
setb P3.4
anI A, #OFh
mov P1, A
; Configure Port 1 for input
; Enable data output on MM74C922
; Read data
; Disable data output
; Clear the top 4 bits (unimportant data)
; check it out on P1 after keypad deactivated
; Check for '1' keypress (A =
djne A, #00h, key-notzero
00h)
Icall setup-record
sjmp getkey-done
106
270
280
key-notzero:
; Check for '2' keypress (A = 01h)
cjne A, #01h, getkey-done
icall setup-playback
290
getkey-done:
reti
setup-record:
setb 00h
; Set record status bit
clr 01h
; Clear all other status bits
clr 02h
clr 03h
mov R6, #init-data-address ; Reset address
mov R7, #00h
mov
mov
mov
mov
mov
mov
mov
mov
ret
40h,
41h,
42h,
43h,
44h,
45h,
46h,
47h,
#00h
#00h
#00h
#00h
#00h
#00h
#00h
#00h
300
; Clear data window
310
setup-playback:
setb 01h
clr
; Set playback status bit
00h
; Clear all other status bits
clr 02h
clr 03h
mov
mov
R6, #initdata-address ; Reset address
R7, #00h
mov
mov
mov
mov
mov
mov
mov
mov
ret
40h,
41h,
42h,
43h,
44h,
45h,
46h,
47h,
#00h
#00h
#00h
#00h
#00h
#00h
#00h
#00h
320
; Clear data window
330
107
There is a method for making the filtering computation more efficient: recall that, after filtering, every other point is discarded. If a data point will be
discarded, there is no need to perform the calculation which produces that data
point. It is only necessary to perform the filter calculations for data points which
will be saved. Since only half of the output points of the digital filter are being saved, it is possible to reduce the computation by half, if only the necessary
calculations are performed.
Similarly, for the output filter, since every other input point is zero, the zero
points can be excluded from the filter calculations. Multiplying by zero is a waste
of time, since the result is always zero. If the filter omits those calculations, the
result will be the same, but the calculations will be twice as fast.
Here a complete code listing for a program which uses these tricks to achieve
to a fast sampling rate with real-time data filtering:
; **reclO.asm**
; This program records input from the ADC at 12.5kHz,
; filters the data, down-samples by 2, then stores the
; result in the RAM memory space from 1000h to 7fOOh.
When played back, the data is up-sampled and
; filtered again before being played through the DAC.
; In this implementation of the recorder, the
; filtering is made more efficient by eliminating
; un-needed calculations.
10
; This program interfaces to the keypad, using the MM74C922:
keypress of '1' -> start recording
keypress of '2'
ADC-address equ
DAC-address equ
init-data-address
max-data-address
->
start playback
FE14h
FE04h
equ
10h
equ
7Fh
; MSB of initial data address
; MSB of max data address
; 8051 hardware vectors
org 00h
ljmp start
; on reset, jump to start routine
108
20
org 03h
ljmp getkey ; external interrupt 0, triggered by keypad logic
30
org Obh
ljmp sample ; timer 0 interrupt, generating sample rate
; Begin main program
start:
40
; R6 and R7 contain the msb and lsb of the data storage
; address. This address is used for storing data
; during recording, And also for reading data during playback.
mov R6, #initdata-address ; msb of write address
; lsb of write address
mov R7, #00h
mov SP, #2Fh
; Initialize filter coefficients:
; First coefficient
mov 60h, #1
mov 61h, #6
; -6
mov 62h, #25
; 25
; 110
mov 63h, #110
; 110
mov 64h, #110
mov 65h, #25
; 25
mov 66h, #6
; -6
; -1
mov 67h, #1
=
-1
50
icall init
loop:
60
sjmp loop
; Initialization routine
init:
setb P3.4
clr 00h
clr 01h
clr 02h
clr 03h
;
;
;
;
;
Disable data output for the MM74C922
Clear status bit-set only when recording.
Clear status bit-set only during playback.
Clear status bit-set only when filtering.
Clear status bit
mov TMOD, #02h
mov TCON, #15h
mov TbH, #171
mov IE, #83h
; Set timer 0 to 8 bit auto-reload mode
; Run timer 0, set external interrupts
; to edge-trigger.
; Interrupt every 85 clock cycles (10.8 kHz)
; Enable timer 0 interrupt, ext. interrupt 0
109
70
ret
80
; Interrupt routine for data sampling and playback
; Checks status bits:
; If in record mode, samples ADC, filters and
down-samples data, writes to memory,
and increments address.
; If in playback mode, reads memory, up-samples
and filters data, writes to DAC,
and increments address.
; If in neither mode, does nothing.
90
sample:
cpl P1.4
jb 00h, record
jb 01h, playback
reti
record:
100
; This code is written for use with the ADC0848
; analog-to-digital converter.
;
;
;
;
;
;
;
;
;
;
This efficient implementation divides the filter
calculation into two stages. Previously, a new
data point was calculated once every sampling
period. However, since every other data point
was being thrown away, it is also possible to neglect every
other filter calculation. Each of the remaining
calculations can be spread over two sampling periods,
allowing for a faster sample rate.
record-flterl and record-filter2 are the two
pieces of the decimation filter.
110
mov DPTR, #ADCaddress
mov A, #08h
; Write configuration byte,
movx @DPTR, A
; and trigger new conversion.
; 03h is a toggling status bit, used to switch back
; and forth between stagel and stage2.
jb 03h, record-stage2
record-stagel:
Icall record-filterl
stagel-read:
mov DPTR, #ADCaddress
movx A,@DPTR
; Read data from ADC
mov 48h, A
; Shift data into data window
110
120
cpl 03h
reti
130
record..stage2:
icall record-filter2
stage2_write:
mov DPH, R6
mov DPL, R7
movx @DPTR, A
Icall inc-address
; Write filtered data back to memory
; Increment address
140
stage2-read:
mov DPTR, #ADC-address
; Read data from ADC
movx A,@DPTR
mov 40h,
mov 41h,
mov 42h,
mov 43h,
mov 44h,
mov 45h,
mov 46h,
mov 47h,
cpl 03h
reti
42h
43h
44h
45h
46h
47h
48h
A
; Shift data window
150
playback:
; This playback routine up-samples the stored data
; by inserting zeros between every two points.
; Because of the zeros, only a smaller data window
; is required for filter calculations. Furthermore,
; since half the input points for the filter are zero,
; only half the number of multiplications are required.
; Taking advantage of this details makes this routine
; run much faster, and allows for a faster sampling rate.
jb 03h, playback-stage2
playback-stagel:
Icall play-filterl
mov DPTR, #DAC-address
movx @DPTR, A ; Write the up-sampled, filtered data to DAC
mov 40h, 42h
mov 42h, 44h
mov 44h, 46h
mov DPH, R6
mov DPL, R7
movx A,©DPTR
160
170
; Shift data
; Read new data from memory
111
180
mov 46h, A
cpl 03h
reti
playback-stage2:
Icall play-filter2
mov DPTR, #DACaddress
movx @DPTR, A
; Write to DAC
190
Icall inc-address
; Increment address
cpl 03h
reti
record-filterl:
mov A, 42h
mov B, 62h
mul AB
mov RO, B
200
mov A, 43h
mov B, 63h
mul AB
mov A, RO
add A, B
mov RO, A
mov A, 44h
mov B, 64h
mul AB
mov A, RO
add A, B
mov RO, A
210
mov A, 45h
mov B, 65h
mul AB
mov A, RO
add A, B
mov RO, A
clr C
mov
mov
mul
mov
subb
mov
220
; Set up for subtractions
A, 40h
B, 60h
AB
A, RO
A, B
RO, A
230
112
ret
record-filter2:
cdr C
mov A, 41h
mov B, 61h
mul AB
mov A, RO
subb A, B
mov RO, A
mov
mov
mul
mov
subb
mov
A, 46h
B, 66h
AB
A, RO
A, B
RO, A
mov
A, 47h
mov
mul
mov
subb
ret
B, 67h
AB
A, RO
A, B
240
250
play-filterl:
; This filter is the regular FIR filter, with half of
; the product terms omitted. As explained above,
; half of the input data points are zero, so the corresponding
; products need not be calculated.
mov A, 42h
mov B, 62h
mul AB
mov RO, B
260
mov A, 44h
mov B, 64h
mul AB
mov
270
A, RO
add A, B
mov RO, A
cdr C
mov A, 40h
mov B, 60h
mul AB
mov A, RO
subb A, B
mov RO, A
mov
280
A, 46h
113
mov B, 66h
mul AB
mov
A, RO
subb A, B
rl A
ret
play-filter2:
; This filter is similar to play-filter2. The only
; difference is that the data has been shifted
; relative to the filter coefficients.
mov
mov
mul
mov
A, 42h
B, 63h
AB
RO, B
mov
mov
mul
mov
add
mov
A, 44h
B, 65h
AB
A, RO
A, B
RO, A
cdr C
mov A, 40h
mov B, 61h
mul AB
mov A, RO
subb A, B
mov RO, A
mov
mov
mul
mov
subb
rl
ret
300
; Set up for subtractions
310
A, 46h
B, 67h
AB
A, RO
A, B
A
320
; Increment Address Routine
; This routine increments the data storage address.
; If address goes beyond the allocated memory space,
; the address, along with all status bits, is reset
; to their initial values. This will cause recording
; and playback to stop.
inc-address:
inc R7
290
; Increment Isb of address
114
330
mov A, R7
jnz inc-done
inc R6
; Check for overflow
; When overflow occurs, increment msb
; Compare address to limit.
cjne R6, #maxdata-address, incdone
340
; If limit has been exceeded, reset state variables.
mov R6, #init-data-address
mov R7, #00h
clr 00h
; Clear record status bit
clr 01h
; Clear playback status bit
; Clear filter status bit
clr 02h
clr 03h
inc-done:
ret
350
;
;
;
;
Get Key Routine
This routine retrieves data from the MM74C922 (keypad decoder),
and is executed each time a key is pressed.
If the keypress is a '1', state variables are
reset for recording mode.
; If the keypress is a '2', state variables are
reset for playback mode.
; If the keypress is anything else,
no state variables are changed.
getkey:
mov P1, #OFFh
clr P3.4
mov A, P1
setb P3.4
anl A, #OFh
mov P1, A
360
; Configure Port 1 for input
; Enable data output on MM74C922
; Read data
; Disable data output
; Clear the top 4 bits (unimportant data)
; check it out on P1 after keypad deactivated
; Check for '1' keypress (A = 00h)
370
djne A, #00h, key-notzero
Icall setup-record
sjmp getkey-done
key-notzero:
; Check for '2' keypress (A = 01h)
djne A, #01h, getkey-done
icall setup-playback
getkey-done:
reti
setup-record:
setb 00h
380
; Set record status bit
115
clr 01h
; Clear all other status bits
clr 02h
clr 03h
mov R6, #init-data-address ; Reset address
mov R7, #00h
390
mov
mov
mov
mov
mov
mov
mov
mov
ret
40h,
41h,
42h,
43h,
44h,
45h,
46h,
47h,
#00h
#00h
#00h
#00h
#00h
#00h
#00h
#00h
; Clear data window
400
setup-playback:
setb 01h
; Set playback status bit
clr 00h
; Clear all other status bits
clr 02h
clr 03h
mov R6, #init-data-address ; Reset address
mov R7, #00h
mov
mov
mov
mov
mov
mov
mov
mov
ret
40h,
41h,
42h,
43h,
44h,
45h,
46h,
47h,
#00h
#00h
#00h
#00h
#00h
#00h
#00h
#00h
; Clear data window
410
420
There are a few more strategies for increasing the speed and efficency of the
digital filter, which will be briefly be discussed here. The first is to exploit the
symmetry of the filter-oftentimes, different coefficients in the filter will be equal.
In that case, rather than performing the same multiplication twice, the result
of the first calculation can be saved and reused. This technique can be used to
dramatically increase the filter speed.
Another strategy for increasing speed is to make use of a circular buffer. Instead of constantly shifting data in the data buffer, it is possible to keep the data
116
114
1________
Point Filter
7 Point Filter
7 kHz
11.4 kHz
12 kHz
15 kHz
No Optimizations
Eliminating Unecessary Calculations
8 Point Filter
15 kHz
Exploiting Symmetry
Table 8.1: Maximum Sampling Rates for Various Filter Implementations
in the same place, and shift the reference pointer instead. This method would
be hard to implement on the 8051, because the 8051 and the MCS-51 assembly
language doe not have any good mechanisms for implementing circular buffers. A
read-only circular buffer can easily be implemented, using the MOVC command.
But a read-write circular buffer is slightly more complicated. As it turns out, the
extra instructions required for maintaining the data pointers would eliminate the
time saved by not shifting the entire data buffer.
8.3.6
Timing Constraints
Table 8.1 shows a comparison of the various techniques for implementing the
various digital filters, along with the maximum sampling rate than can be attained.
It appears that a voice recorder project is feasible, using the 8051 and an 11.0592
MHz clock, but in order to perform the sampling and filtering at a reasonable
quality level, it is necessary to use the optimizations.
117
118
Chapter 9
Conclusions
Four of the lab exercises discussed in this paper (described in Chapters 3-6) were
fully implemented as the 6.115 course curriculum in the Spring of 2001. These
exercises were well received. There were complaints about the volume of work required, but students were generally excited about the topics and projects included
in the class.
All of the hardware systems designed for the course were reliable and dependable, even with misuse, and the pressure exerted by a class of more than 75
students. There were some cases where the equipment broke or failed, for various
reasons. But the number of failures was relatively few. There was never a shortage
of hardware, due to system failures.
One student, after the class was completed, remarked that "6.115 was the best
laboratory class I've taken at MIT. It was so well organized!"
119
120
Appendix A
Schematics
A.1
R31JP Daughter Card
Figure A-1 contains the schematic for the R31JP daughter card. This circuit was
used to connect between the R31JP development system and the 6.115 NUBUS
lab kit.
A.2
Fluorescent Lamp Ballast
Figure A-2 contains the schematic for a fluorescent lamp ballast. This circuit was
implemented (using ExpressPCB) and built as a lab station for 6.115
A.3
Keypad
Figure A-3 contains a schematic for interfacing a keypad to the R31JP, using the
MM74C922 keypad decoder chip.
121
R31JPdaughter.sch-1 - Wed May 23 13:49:08 2001
XSELA
IN
+5V
+5v
+12V
A
U3
+12V
vc
K1
2
1CC 4
_ 33
_RESEETIN
D2
RESET
AL4F
91
0
11
19
9
Al
AZ
Ul
GN
12 34
A4
IN.II.
1
AQ&
+5V
17 A05.,
1
:SJ
A[0
CO7
2
GND
12
-- ^4L
19+20
A15+
F
-S
+5v
7805
PWR
22uF
T
U2DIR
+2V
+5v
21 A
K2
J2
1
RESET
S P17~~-
6
_ P17FT
6f 11
P1
P
P
2
4
1
IN
P35
12
Pil
PLO
-P34
13 -P33
P3?
14
T)
20
21
22
23
P35
1 GND
15
16
05
-
-
-6
12 Pi
1 PL
42
4
44
i
15
LEDBANK
P[10:171
24
26
D 4345
0049
CON23
P'a
2
P34 Z7/
07P33
D6P37 293331
Q
no
B5
B7
74LS245
16
28
20
25
BO
ai
-
2I 1CC 11
9
560ohms
5
11
120
21
23
[1:31
P
ENA BLE -19
A2
A3
-f22
14
11
0
41
46
CON50
Figure A-1: R31JP Daughter Card
122
RESISTOR-PACKIO
- Thu May 24 09:12:58 2001
lamp.sch-1
+12V
+12V
D4
C1IIu
U4
05
IN
POWER
OUT
1A
A~
RI
1K
LM7R12CK
C2
C3
INN
-25V
VCC
LED
D6
-
DI
r[
IR2104
I
J1
, ...
JUMPER
SD
R5
C5
2.4K
68uF
35V
I
Ca
SF
LED
R2
yS
MOSFET
C7
INDUCTOR
R7VOUT+
luF
300K
R6
R3
10
LO
CAP
M2I
LAMP
Figure A-2: Interactive Ballast for a Fluroescent Lamp
123
30K
keypad.sch-1 - Wed May 23 15:42:01 2001
Keypad Connector
J2
Ul
1 ROW
I
2~
~
COL1
~
CL
1
7 ROW3
8 ROW2
ROW1
10
8
COL
COL2
COO3
COL4
CON16
VCC
18
2 ROW2
ROW3 DATA_A
ROW4 DATA_B
DATA-C
9
GND
T--
DATAD
1.0
P1
1.1
P1
Pi
4
Pi 5.4
OE
5.2
DA
Osc 6
KBM
MM74C922
Cl
.06E uF
C2
-
Figure A-3: Schematic for Keypad and MM74C922
124
.2
.3
0068uF
speaker.sch-1 - Tue May 15 08:56:13
2001
U1+5V
DO
1 060
+VCC
D4
084 VOUT
06
D3f M
07
066
SEL
DB
067 AGND
CSO ED 10
1
Chip Select from 74LS138
ETSg
is
0 125u
C
3M8
DGND 12U2
+
1C1
AD558
.05uF
--
SPEAKER
--
0
R2
10
Figure A-4: Schematic for DAC and Speaker
A.4
Speaker
Figure A-4 contains a schematic for connecting a speaker to the R31JP, using an
LM386 amplifier and the AD558 digital-to-analog converter.
A.5
Memory-mapped I/O Devices
Figure A-5 contains a schematic for connecting the 74LS138 decoder logic chip.
This logic chip was used to decode memory addresses for the memory-mapped
I/O devices.
Figure A-6 contains a schematic for connecting the 8254 counter/timer peripheral chip.
Figure A-7 contains a schematic for connecting the 8255 parallel port periph125
74LS138.sch-1
-
Wed May 23 15:40:55 2001
+5V
+5V
U'
Al
A2
XI0SEL#J
A
B
C
M2
E
5
8
VCC
16
YO(
Y1
G2A Y2
13
G2B Y3 ( 12
GND
y5
Y6 (
Y7 ( 7
11
_10
CS2
CS3
CS4
CS5
CS6
CS7
74LS138
Figure A-5: Address Decoding For Memory-Mapped I/O
126
8254.sch-1
Wed May 23 14:57:09 2001
-
U1
Chip
Select
+5V
from 74LS138
CSI?
D2
+5V
F
Y1
OE VCC
GND
OUT
D
DO
WR~
CL
D2
05
GTED D7 R
InGA TE1OUTO
D5
N
ATEUT2D
35
I CLOCK
Figure A-6: 8254 Counter/Timer
127
7
SUAE
W
AE
8255.sch-1 - Wed May 23 14:56:11 2001
U1
RD$
-D
WR
Chip Select from 74LS138
, k: eWRESLET
RESET
CS,
CS
AD
Al
AD
Al
DOLD
DlED
at DO
L D1
D2
D3
D4
D5
PCO
PCi
PC2 ~15
PC3
PC4 IL
PC5 AL
PC6
PC7 IL
D2
D3
D4
[-)
29
PBO AIL
PB1 19PB2
PB3
PB4 -zU
P85
PB6
PB7
D5
D6
D6
07
07
PAO
PA
PA2 -2PA3
PA4
PA5
PA6 1I
PA7
8255A
Figure A-7: 8255 Parallel Port
eral chip.
Figure A-8 contains a schematic for connecting the AD558 digital-to-analog
converter.
Figure A-9 contains a schematic for connecting the 8255 counter/timer peripheral chip.
128
AD558.sch-1 - Wed May 23 13:59:19 2001
+5V
B +VCC
DB2Ul
DO
D2
D3
D4
D6
D7
-
3
DB4 VOUT
6
SEL
AGND
14
-
__
WRJ E::
Cs# ED
Chip Select from 74LS138
1
DB7
VOUT
OV to 2.56V output range
rcE
10a65~
1GN
AD555
Figure A-8: AD558 digital-to-analog converter
129
ADC0848.sch-1
-
Wed May 23 14:09:03 2001
+5V
U4
RD
VCC
P3.4
Do
D1
D2
D3
D4
D5
D6
D7
RD
WR
23
INTR CS
CHi
CH1 3
20
20 DB0
CH2 -3DB1
CH3
DB2
CH4
CH5
1
DB3
DB4
CHS
1
DB5
CH7
1
0-3-D6
CH8
DB7
VREF 11
AGND
DGND
CS
Chip Select from 74LS138
-
INPUT
-5-
Li
+5V
C6
--
015uF
ADCOB48
Figure A-9: ADC0848 Analog-to-Digital Converter
130
Bibliography
[1] Carl's Electronics. http://www.electronickits.com/robot/robot.htm.
[2] Datasheet
for
Lattice
Semiconductor
GAL22V10.
http://www.latticesemi.com/products/devices/low5v.cfm.
[3] Datasheetfor Xilinx XC9536. http://www.xilinx.com/partinfo/9536.pdf.
[4] Lynxmotion Robot Kits. http://www.lynxmotion.com.
[5] MIT
Course
6.111:
Beginner's
A
Guide
to
WARP.
http://sunpal2.mit.edu/6.111/s2001/bguidewarp/bguidewarp.html.
[6] MIT Course 6.111 (Spring 2001). http://sunpal2.mit.edu/6.111/s2001/6111.html.
[7] Rigel Corporation. http://www.rigelcorp.com.
[8] Warp CPLD Development Software. http://www.cypress.com/pld/warp.html.
[9] Xantz Innovations. http://www.xantz.com.
[10] Xilinx CPLD WebPA CK ISE. http://www.xilinx.com/sxpresso/webpack.htm.
[11] Warit Wichakool. Dc-dc power converter lab stations for 6.002. Technical
report, MIT, 2000.
131
Download