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