ECE 3724/CS 3124 Microprocessors I Lab Manual © R. B. Reese Preface The goals of these lab experiments are simple; to expose you to a range of topics in microprocessor assembly language programming and hardware interfacing. The PIC18F242 is used as it is supported by freely available development tools from Microchip (MPLAB IDE, assembler and simulator) and high quality C compilers (Hi-Tech Software, the PIC18 C Compiler). The availability of PICs in small pin count DIP packages with on-chip USART, I2C, and A/D modules make it easy to build a small protoboard system that is used to support a wide variety of relevant exercises. Experiments 1 and 2 relate basic digital design to the microprocessor world. The next three experiments introduce PIC assembly language programming and the connection between assembly language and C programming. Experiments 6 through 13 build a PIC18F242 system from scratch to explore topics such as RS232 interfacing, the I2C bus, A/D and D/A conversion, interrupt driven IO, IR pulse width decoding, and audio record/playback. The experience of building a microprocessor system from the ground up provides skills that prove useful in later design experiences, such as the capstone senior design course. These labs assume a basic digital design course prerequisite (ECE 3714), exposure to C or C++ programming, and familiarity with the Altera Maxplus toolset (used in the first two lab exercises). A physics-level circuits theory exposure is all that is needed to succeed in the hardware labs. An oscilloscope and multimeter are used in the hardware experiments. The parts kit cost is approximately $50 and can be purchased through the department; the lab web site has the complete parts list posted. The protoboard purchased previously for ECE 3714 is used throughout the semester to build the PIC-based system. The board must stay wired between lab exercises, so if you have another lab that requires a protoboard then a second protoboard must be purchased. You may also find it necessary to purchase an extra wiring kit. All of the C and assembly language programs referenced in this document are available from the lab web site (http://www.ece.msstate.edu/~reese/ece3724/lab). The material in this document is intended to supplement material in the textbook and datasheets. Refer to the lab web site for a detailed lab schedule and lab report guidelines. If errata is found in this lab manual, please send email to reese@ece.msstate.edu. Feel free to send comments about clarity, difficulty or any other topic concerning the exercises to the same email address! Send any comments about the Knuts & Boltz strips at the start of each exercise to my evil twin whose email address is bots@insightbb.com (FYI: yes, he is my twin but is really not evil; he is an ex-F15 fighter pilot with an MSEE degree who after 20 years in the Air Force currently flies boxes for UPS in-between drawing Knuts & Boltz strips, see http://www.b0ts.com -- that is a zero in b0ts). Many thanks goes to J. Harden, J.W. Bruce, and J. Moorhead for discussions and suggestions. Good luck, and I hope your lab experience is a good one. R. B. Reese 5/2004 Summer 2004/V0.2 i Contents Experiment 1: A Stored Program Machine- - - - - - - - - - - - - - - - - - - - - 1-1 Prelab Requirements - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1-2 Finite State Machine versus Stored Program - - - - - - - - - - - - - - - - 1-2 The Problem - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1-3 A Stored Program Computer - - - - - - - - - - - - - - - - - - - - - - - - - - - 1-4 What instructions are needed? - - - - - - - - - - - - - - - - - - - - - - - - - - 1-5 Instruction Encoding - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1-6 The Hardware - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1-8 Lab Activity - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1-11 Background - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1-11 Report - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1-11 Maxplus LPMs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1-12 Changing a Parameter Value - - - - - - - - - - - - - - - - - - - - - - - - - - 1-12 LPM_DFF - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1-12 LPM_COUNTER - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1-13 LPM_ROM - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1-13 MIF format - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1-13 Bus Labeling - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1-14 Experiment 2: The PIC 18Fxx2 Architecture - - - - - - - - - - - - - - - - - - - 2-1 PreLab Requirements - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 2-2 A quick introduction to MPLAB - - - - - - - - - - - - - - - - - - - - - - - - 2-2 Simulating your program - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 2-3 Single Stepping - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 2-4 Reset, Clearing Memory - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 2-5 QuickBuild Mode instead of Projects - - - - - - - - - - - - - - - - - - - - - 2-5 Watch Window - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 2-5 Animate Command - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 2-5 Lab Activity - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 2-6 Exploring PIC18 Data memory organization - - - - - - - - - - - - - - - - 2-6 Data Memory Banks in the PIC18 - - - - - - - - - - - - - - - - - - - - - - - 2-6 Moving data between banks - - - - - - - - - - - - - - - - - - - - - - - - - - - 2-9 showid.asm - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 2-10 bit test and skip - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 2-10 Controlling the value of odd - - - - - - - - - - - - - - - - - - - - - - - - - - 2-10 The Stopwatch - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 2-10 A poor emulation? - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 2-11 Report - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 2-12 Experiment 3: PIC18Fxx2: Instruction Set- - - - - - - - - - - - - - - - - - - - - 3-1 Summer 2004/V0.2 ii Prelab Requirements - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 3-2 A Quick C Review - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 3-3 Loops and Conditions - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 3-4 Lab Activity - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 3-6 STATUS Register: Carry, Zero Flags - - - - - - - - - - - - - - - - - - - - - 3-6 Converting the C operations to PIC Assembly - - - - - - - - - - - - - - - 3-7 arithmetic operations - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 3-8 logical operations - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 3-8 Shift operations - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 3-8 Condition Tests - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 3-10 Test for bit set or clear - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 3-10 Zero/Nonzero Test with branch instruction - - - - - - - - - - - - - - - - 3-11 Zero/Nonzero Test with branch instructions - - - - - - - - - - - - - - - - 3-12 <, > tests - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 3-13 Compare instructions - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 3-15 Equality, Inequality tests - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 3-16 Report - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 3-17 Experiment 4: Data: Wider is Better - - - - - - - - - - - - - - - - - - - - - - - - - 4-1 Prelab Requirements - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 4-2 Data Sizes in C - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 4-3 Lab Activity - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 4-5 Storing 16-Bit values in memory - - - - - - - - - - - - - - - - - - - - - - - - 4-5 Addition/Subtraction of 16-bit values - - - - - - - - - - - - - - - - - - - - - 4-7 increment, decrement - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 4-7 left, right shift - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 4-8 Unsigned 16-bit comparisons - - - - - - - - - - - - - - - - - - - - - - - - - - 4-10 16-bit Equality tests - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 4-11 16-bit Zero/Nonzero tests - - - - - - - - - - - - - - - - - - - - - - - - - - - - 4-11 Signed Comparisons - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 4-12 Integer Signed Comparison: N, V flags - - - - - - - - - - - - - - - - - - - 4-13 Equality, zero, nonzero tests for 16-bit signed data - - - - - - - - - - - 4-15 PC Relative Addressing - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 4-15 Report - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 4-17 Experiment 5: Beyond Assembly Language- - - - - - - - - - - - - - - - - - - - 5-1 Prelab Activity - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 5-2 Pointers in C - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 5-2 Pointers in PIC assembly language - - - - - - - - - - - - - - - - - - - - - - - 5-3 Subroutine Parameters - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 5-4 main code - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 5-5 strcnt subroutine - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 5-5 POSTINC0 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 5-6 Lab Activity - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 5-9 Compiling C programs to PIC18 machine code - - - - - - - - - - - - - 5-10 Simulating cstrcnt.c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 5-12 Compiling, Simulating your C program - - - - - - - - - - - - - - - - - - - 5-13 Report - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 5-14 Summer 2004/V0.2 iii Formal Report Questions - - - - - - - - - - - - - - - - - - - - - - - - - - - - 5-14 Experiment 6: Bringing the PIC to Life - - - - - - - - - - - - - - - - - - - - - - - 6-1 Prelab Requirements - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 6-2 Lab Activity - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 6-4 Which pins are Tx and Rx? - - - - - - - - - - - - - - - - - - - - - - - - - - - - 6-6 Detailed RS232 Serial Port Debugging - - - - - - - - - - - - - - - - - - - - 6-7 What is next? - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 6-9 Optional In-Circuit Programming Connection - - - - - - - - - - - - - - 6-14 Report - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 6-15 Experiment 7: Serial versus Parallel - - - - - - - - - - - - - - - - - - - - - - - - - 7-1 Prelab Requirements - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 7-2 Lab Activity - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 7-3 Formatted IO via printf - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 7-5 Report - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 7-7 Experiment 8: Interrupt-Driven IO - - - - - - - - - - - - - - - - - - - - - - - - - - 8-1 Prelab Requirements - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 8-2 Lab Activity - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 8-3 The Overrun Problem - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 8-7 Fixing the Problem - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 8-7 Storing/Retrieving values from a circular buffer - - - - - - - - - - - - - - 8-7 Empty, Not-empty, Full - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 8-8 Report - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 8-9 Experiment 9: Memory and the I2C Bus - - - - - - - - - - - - - - - - - - - - - - 9-1 Prelab Requirements - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 9-2 Lab Activity - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 9-3 Streaming writes - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 9-4 Use two buffers - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 9-4 Checking for Overrun - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 9-6 Program Operation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 9-7 Report - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 9-8 Experiment 10: Talking to the Real World- - - - - - - - - - - - - - - - - - - - -10-1 Prelab Requirements - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 10-2 Lab Activity - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 10-3 Report - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 10-6 Formal Report Questions - - - - - - - - - - - - - - - - - - - - - - - - - - - - 10-6 Experiment 11: Controlling Time- - - - - - - - - - - - - - - - - - - - - - - - - - -11-1 Prelab Requirements - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 11-2 Lab Activity - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 11-4 sqwave.c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 11-4 ledpwm.c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 11-5 sinegen.c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 11-7 Comments on sinegen.c measurements - - - - - - - - - - - - - - - - - - - 11-8 Arbitrary Waveform Generation - - - - - - - - - - - - - - - - - - - - - - - - 11-9 Report - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 11-12 Experiment 12: Time Measurement - - - - - - - - - - - - - - - - - - - - - - - - -12-1 Summer 2004/V0.2 iv Prelab Requirements - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 12-2 Lab Activity - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 12-3 swdet.c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 12-3 Multiple Timer1 Overflows - - - - - - - - - - - - - - - - - - - - - - - - - - - 12-4 IR Pulse Decoding - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 12-5 ‘1’,’0’, Start periods - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 12-6 Hints for IR Decoding - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 12-7 Report - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 12-10 Experiment 13: The PIC Listens and Speaks - - - - - - - - - - - - - - - - - - -13-1 PreLab Requirements - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 13-2 Audio Sampling - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 13-3 Lab Activity - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 13-5 Implementing Playback - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 13-5 Report - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 13-7 Appendix A: Prototyping Hints - - - - - - - - - - - - - - - - - - - - - - - - - - - - A-1 Protoboard and Parts - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - A-2 Protoboard Layout - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - A-2 Power Connector - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - A-3 Voltage Regulator (7805) - - - - - - - - - - - - - - - - - - - - - - - - - - - - A-3 PCB Fuse - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - A-4 Resistor SIP Packages - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - A-4 Capacitors (1.0 µF/0.1 µF) - - - - - - - - - - - - - - - - - - - - - - - - - - - A-4 Light Emitting Diodes (LEDs) - - - - - - - - - - - - - - - - - - - - - - - - - A-5 Power LED - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - A-5 Power Switch - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - A-6 Momentary Pushbutton Switches - - - - - - - - - - - - - - - - - - - - - - - A-6 7.3828 MHz Crystal - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - A-6 Potentiometers - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - A-7 Audio Connector - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - A-8 Wire Wrapping - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - A-8 Get a decent protoboard! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - A-9 Get a multimeter! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - A-10 Debugging - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - A-11 My board used to work and now it doesn’t! - - - - - - - - - - - - - - - A-11 My fuse keeps blowing, my board used to work, help! - - - - - - - - A-11 My RS232 interface does not work and/or serial bootloader does not work. A12 My I2C interface does not work. - - - - - - - - - - - - - - - - - - - - - - A-13 My PIC seems to be spontaneously resetting?! - - - - - - - - - - - - - A-13 My A/D input does not work? - - - - - - - - - - - - - - - - - - - - - - - - A-14 Appendix B: Instrumentation- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - B-1 TDS 210 Oscilloscope - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Displaying a continuous waveform - - - - - - - - - - - - - - - - - - - - - Voltage/Time Scaling - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Measure Function - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - B-1 B-1 B-2 B-2 Summer 2004/V0.2 : Cursor Function, measuring voltage difference, pulse width - - - - Trigger Function, continuous or single shot capture - - - - - - - - - - AC vs. DC Coupling - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Multimeter - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Measuring Voltage - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Measuring Resistance - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Measuring Current - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - B-3 B-3 B-4 B-5 B-5 B-5 B-6 —v : — vi Summer 2004/V0.2 Summer 2004/V0.2 E x p e r i m e n t Experiment 1: A Stored Program Machine 1 A Stored Program Machine There was this guy named Von Neuman who hated wiring a new circuit every time he had a new problem to solve (kinda like students in the logic gates class). So, because of this hatred of wires, the stored program machine was born. It lives to fetch and execute all day long, and sometimes, if we are lucky, we can make it do useful work for us. The best thing is that we don’t have to change any wiring when we want it to do something different! Summary Use a stored program machine approach to implement a state machine that displays a number sequence. 1—1 Experiment 1: A Stored Program Machine Summer 2004/V0.2 A. Prelab Requirements Table 1–1: Prelab Checkoff Do This 1. Review the notes below on the Student-ID CPU machine. 2. Have Altera Maxplus 10.1+ Baseline edition installed on your PC and review how to compile/simulate designs within Maxplus. Perform the Maxplus tutorial found in the digital devices (ECE 3714) textbook if a review of Maxplus operation is needed. 3. Download the file archive containing the Student-ID CPU. Compile the design in Altera Maxplus, and verify that you can simulate it. The scpu.gdf Altera Maxplus schematic in the ZIP archive attached to this lab is the student ID CPU implementation 4. Become familiar with the LPM modules used within the Student-ID CPU design (lpm_counter, lpm_rom, lpm_dff). Read the material at the end of this lab on LPM usage within Maxplus. Finite State Machine versus Stored Program 1—2 Comments More notes on this subject are linked to the lab web site. The rom.mif file specifies the memory contents (i.e, the program); if this file is changed the schematic must be recompiled. The rom.mif file can be edited with a text editor such as notepad or wordpad. In the digital devices course, a logic network was designed to implement a student ID sequencer. The logic design used flip-flops and combinational logic to implement a specific number sequence. A different student ID required a different logic design. An alternate approach to solve this problem uses a general purpose logic network called a stored program machine. The operation of a stored program machine is determined by instructions stored in a memory. Changing the instruction sequence (changing the contents of memory), changes the actions of the machine. A new problem is solved by simply reprogramming memory; no hardware modifications are required. This general purpose logic network might not be as fast as a special Summer 2004/V0.2 Experiment 1: A Stored Program Machine purpose logic network, but the flexibility of being able to solve multiple problems by changing memory contents is often worth this trade-off. The Algorithmic State Machine (ASM) chart below illustrates the problem to be solved. The machine displays either the odd or even digits of a student ID. A single input called odd determines if the odd or even sequence is displayed. 0 odd? 1 Dout = 4 The Problem S0 Dout = 5 Dout = 8 Dout = 0 Dout = 2 Dout = 8 S1 S4 Dout = 7 S5 Dout = 1 S2 S6 Dout = 9 S3 S7 Figure 1.1 ASM Chart for Student ID 458 70 2198 The finite state machine implementation shown below m n Combinational Logic Circuit Inputs k-bit Present State Value k Memory Element Outputs Figure 1.2 FSM Block Diagram k-bit Next State Value k 1—3 Experiment 1: A Stored Program Machine Summer 2004/V0.2 requires three D flip-flops (k=3) to implement the eight states of the ASM, one input signal (n=1) to implement odd, and four output signals (m = 4) to display the current student ID digit (the values 0-9 are encoded in 4 bits). A new digit is displayed every clock cycle. A different student ID requires redesign of the combinational logic network that produces the output value and next state value. A Stored Program Computer Figure 1.3 A Stored program machine A more general approach solves the problem via a stored program approach. The block diagram of a stored program machine (a computer) is shown below. Address bus C o n t r o l Databus bus Memory Input/Output devices A stored program machine has three principle blocks: • Memory: stores data and instructions. The memory contents determines the machine’s actions. The address bus specifies a particular location in memory, and the data bus contains the data fetched from or stored to that location. • Control: logic that controls the fetch and execution of instructions stored in memory. • Input/Output: used for interaction with the external world. The input/output signals for our stored program machine are the same as for the finite state machine; 1—4 Summer 2004/V0.2 Experiment 1: A Stored Program Machine one input for odd and a four bit output bus for displaying the current digit of the student ID. A stored program machine executes a program that is stored in memory. A program consists of a sequence of instructions. The key design question is “What instructions are needed to solve this problem?”. To answer this, transform the ASM chart to a pseudo high-level language description as shown below (translation: something that looks like C or Pascal or any other programming language you know). What instructions are needed? start: if (odd == 1) then goto odd_start even_start: output even digit #1 output even digit #2 .... output last even digit goto start odd_start: output odd digit #1 output odd digit #2 .... output last odd digit goto start In the above ‘program’, there are three different operations: • out data: output a 4-bit value representing the current digit (i.e, ‘output odd digit #2’) • jmp location: unconditionally jump to a location (i.e, ‘goto odd_start’). To ‘jump’ to a location means to fetch the next instruction from that loca- 1—5 Experiment 1: A Stored Program Machine Summer 2004/V0.2 tion instead of the location immediately following the current instruction. • jc location: conditionally jump to location (i.e. ‘if odd == 1 then goto odd_start’). Instruction Encoding The three instruction types above must be encoded in a binary form for efficient implementation in digital logic. Typically an instruction is divided into at least two parts: • opcode: specifies the instruction type. In this case, there are three instruction types, so two bits are sufficient for opcode specification. • data: every instruction operates on data. The data for the out instruction is the four bits that specifies the current ID value. The data for the jc and jmp instructions is the address of the memory location being jumped to. The number of bits required depends on the maximum number of locations in memory. If memory is limited to 16 locations, then four bits are sufficient to specify a memory location. The instruction format requires two bits for opcode, and four bits for data as shown below. The term mne- Figure 1.4 Instruction mnemonics vs. encoding mnemonic encoding JMP location 00 | 4-bit location JC location 01 | 4-bit location 10 | 4-bit data OUT data b5 b4 b3 b2 b1 b0 monic refers to the human-readable form of the instruction; the encoding is the binary form of the instruction that is stored in memory. Each instruction 1—6 Summer 2004/V0.2 Experiment 1: A Stored Program Machine requires 6 bits. The encoding choice for the opcode affects the boolean logic required to decode the instruction. This encoding allows bit b5 to differentiate an out instruction from the two jump instructions. The pseudo code written previously for the ASM is written using these instructions in Table 1–2. Note that Table 1–2: Program for Student ID 458 70 2198 Memory Location Memory Contents mnemonic 00 01 0111 start: jc odd_start (loc 7) 01 10 0100 out 4 02 10 1000 out 8 03 10 0000 out 0 04 10 0010 out 2 05 10 1000 out 8 06 00 0000 jmp start (loc 0) 07 10 0101 odd_start: out 5 08 10 0111 out 7 09 10 0001 out 1 0A 10 1001 out 9 0B 00 0000 jmp start (loc 0) this program almost fills available memory as the four bit data field for the jc and jmp instructions limit memory to 16 locations. The process of converting the instruction mnemonic to its binary form (machine code) is called assembly; typically a computer program called an assembler is used to perform this process automatically. A program written using the instruction mnemonics of a stored program machine is called an assembly language program. 1—7 Experiment 1: A Stored Program Machine The Hardware Summer 2004/V0.2 The stored program machine is implemented using the following components: • Memory: a 16 x 6 memory. The K x N notation for memory indicates the memory has K locations, with each location containing N bits. • Registers: recall from your digital devices course that a register is used to store a N-bit binary value, where N is the number of bits in the value. This machine needs two registers: out and program counter (PC). The out register is 4-bits wide and contains the current digit being displayed. The program counter contains the address of the current location accessed from memory. The PC is implemented as a counter that is either incremented to point to the next location, or loaded from the data field of the current instruction to implement the jump instructions. • Decode logic: this logic controls the loading of the out register, and the loading or incrementing of the program counter. The inputs to the control logic are the odd input, and the opcode of the current instruction. 1—8 Summer 2004/V0.2 Experiment 1: A Stored Program Machine Figure 1.5 shows a block diagram of the stored program machine implementation. Data[3:0] odd D E C O D E ld R E G aclr out 4 clk r_ld Data[3:0] clk c_ld c_en Op[1:0] ld en aclr 4 c n t r Addr[3:0] 4 PC out[3:0] 4 Data[5:0] M E M 6 16 x 6 Data[5:4] 2 Figure 1.5 Stored program machine implementation The r_ld output of the decode logic controls the loading of the out register, which needs a new value when an out instruction is executed. The Boolean equation for r_ld is: r_ld = op1 as the op1 bit is a logical 1 for an out instruction. The PC register (the counter) is loaded when a jmp instruction is executed, or if a jc instruction is executed and the odd input is true. Written as a VHDL statement, this equation is: c_ld <= ‘1’ when ((op = ‘00’) or (op = ‘01’ and odd = ‘1’)) else ‘0’; Written as a Boolean equation, this becomes: c_ld = op1’op0’ + op1’ op0 odd 1—9 Experiment 1: A Stored Program Machine Summer 2004/V0.2 The PC register is incremented if a parallel load is not done, so: c_en <= not(c_ld); c_en = c_ld’; (VHDL) (boolean equation) The aclr control line is an asynchronous reset input; at power up this input is asserted to clear the PC register so that the first instruction is fetched from location 0. 1 — 10 Summer 2004/V0.2 Experiment 1: A Stored Program Machine B. Lab Activity Background Table 1–3: Student ID machine Checkoff Checkpoint 1. 2. Comments/Debugging Write a program for the student ID CPU that outputs the digits of your student ID. You must have the program represented both as instruction mnemonics and machine code. Modify the rom.mif file to contain your assembled program. Step through the operation of the student ID CPU with the original rom.mif file and verify that you understand what is happening on each clock cycle. Create a new schematic called my_scpu.gdf and make the necessary modifications to it so that it can support a program that contains up to 32 lines of code. Test the changes by placing your original program starting at location 16 in memory. At location 0, place a 'goto 16' instruction. Review the material at the end of this lab on LPM modules. You will need to change the width parameters to one or more LPM modules and also change the size of the data busses that connect to them. Include the instruction mnemonic as a comment on each line of machine code in the rom.mif file. Discuss your proposed changes with the TA before proceeding too far into the implementation. DEMONSTRATE THAT THE CHANGES MADE TO THE ROM.MIF FILE DISPLAYS YOUR STUDENT ID. DEMONSTRATE THE MODIFIED VERSION OF THE STUDENT ID MACHINE THAT SUPPORTS 32 INSTRUCTIONS. C. Report 1. Include the assembly code and machine code of the programs for checkpoints 1 & 2 of Table 1–3. 1 — 11 Experiment 1: A Stored Program Machine Summer 2004/V0.2 2. Include a screenshot of your schematic for checkpoint 2 of Table 1–3. 3. Briefly discuss the changes made for the student ID CPU design for checkpoint 2 of Table 1–3 and the reasoning behind the changes. 4. Assume a new instruction is needed called 'NOT' that performs a one's complement (invert the bits) on the current value in the OUTPUT register. What changes are required to the decode logic and overall design to implement this? Show a sketch or rough schematic of the necessary modifications (there is more than correct solution). D. Maxplus LPMs The student ID CPU uses three elements from the Maxplus Library of Parameterized Modules (LPM). Each LPM implements a common digital system building block such as a counter, register, memory, etc. with parameters used to control key attributes. For example, each LPM has a parameter called LPM_WIDTH that determines the component’s data width (i.e, for a counter, if LPM_WIDTH = 4, then it is a 4 bit counter). Converting a 4-bit counter to a 16-bit counter is as easy as changing the value of the LPM_WIDTH parameter and the labels on the data busses that connect to the counter. Changing a Parameter Value To change an LPM parameter value, double-click on the LPM within the schematic to open the Edit Ports/ Parameters window. The lower half of the window has a scroll list containing all of the parameters. Select a parameter and edit its value in the Parameter Value type-in field. Click OK to close the window. LPM_DFF The LPM_DFF module is used to implement the out register. The enable input functions as the load line for 1 — 12 Summer 2004/V0.2 Experiment 1: A Stored Program Machine the register. The LPM_WIDTH parameter is currently set equal to 4. The LPM_COUNTER module is used to implement the PC register. The sload input is the load signal for the counter; when asserted the counter is loaded from the data inputs on the next rising clock edge. The counter increments its current value on the next rising clock edge when the cnt_en signal is asserted. The LPM_WIDTH parameter is currently set to 4. LPM_COUNTER The LPM_ROM module is used to implement the program memory (ROM = Read Only Memory). At compilation time, the memory contents are initialized from the file specified by the LPM_FILE parameter, currently set equal to rom.mif. The LPM_WIDTHAD parameter specifies the width of the address bus; the number of locations in the ROM is equal to 2**LPM_WIDTHAD. The current value of LPM_WIDTHAD is 4, so the number of locations is 2**4 = 16. The LPM_WIDTH parameter controls the number of bits per location and sets the width of the output data bus (q[]); it’s value is currently equal to 5. LPM_ROM The MIF file, which can be edited with a text editor, specifies the contents of the ROM. The format is fairly self-explanatory, but a few words of caution are needed. The number of locations in the LPM_ROM is controlled by the LPM_WIDTHAD parameter. A change to this parameter requires a corresponding change to the MIF file Depth value that specifies the number of locations in the ROM. Similarly, a change to the LPM_WIDTH parameter of the LPM_ROM requires a corresponding change to the MIF file Width value. The MIF file does not need a value specified for every location in the ROM. MIF format A comment is bracketed by two ‘%’ symbols; there MUST BE two ‘%’ symbols! Formatting errors are 1 — 13 Experiment 1: A Stored Program Machine Summer 2004/V0.2 generated during compilation if an ending ‘%’ symbol is missing. Bus Labeling 1 — 14 After changing the LPM_WIDTH parameter on an LPM, the size of the data busses connected to the LPM must also be changed by editing the bus label. For example, assume the LPM_WIDTH parameter of the LPM_COUNTER is changed from 4 to 5. This requires modifying the sizes of the busses connecting to the data[] and q[] pins by changing the bus names from instr[3..0] to instr[4..0], and pc[3..0] to pc[4..0]. Note these changes affect other busses/components in the schematic requiring modifications to related LPM_WIDTH values and bus names as well. Double click on a bus label to edit it. During compilation, a “width mismatch” error indicates that the width of the data bus connecting to an LPM does not match the internal width of the LPM. Summer 2004/V0.2 E x p e r i m e n t Experiment 2: The PIC 18Fxx2 Architecture 2 The PIC 18Fxx2 Architecture It is suspected that the favorite bible story of microprocessor (µP) architects is “The Tower of Babel” given the gazillion varieties of microcontrollers available, each with its unique set of instructions, registers, and features. But don’t worry, we will only concentrate on one in this lab. Unfortunately, it is generally agreed the first µP instruction set you learn is the toughest.... Summary Use MPLAB to assemble and execute a small assembly language program. Execute the same program on a PIC18Fxx2 model in Maxplus-II, and trace data movement on internal data busses. 2—1 Experiment 2: The PIC 18Fxx2 Architecture Summer 2004/V0.2 A. PreLab Requirements Table 2–1: Prelab Checkoff Do This 1. 2. Comments Attached to this lab is a program called mptst.asm. Assemble and execute this program in MPLAB using the 18F242 as the target device. Follow the instructions below on how to do this. Trace the program until address 0x0212 in program memory is reached. Change the value of the myid symbol to be the decimal equivalent of the last two digits of your student id. If the last two digits of your student ID are ‘00’, then use the first two digits. Verify that the value of the ‘k’ variable stored at location ‘0x02’ has the expected value in it given the new value of myid. Verify that the value of the k variable stored at location 0x02 has the value 0xC9 at this point. Trace the program until address 0x0212 in program memory is reached. Capture a screen shot that shows the ‘Program memory’ and ‘File Register’ contents at this point. A quick introduction to MPLAB If you have not already done so, install the latest version of MPLAB on your PC by visiting to http:// www.microchip.com, selecting ‘Engineer’s Toolbox →Development Tools →Software →MPLAB IDE’, and downloading the MPLAB IDE executable. Copy the file mptst.asm to a local directory. Caution: MPLAB 6.0+ does not allow pathnames to exceed 62 characters so be careful where you place this file. Execute MPLAB and create a new project for it. Call the new project mptst and browse to the directory that contains mptst.asm. Use ‘View →Project’ to view the project file hierarchy. Right click on ‘Source Files’ 2—2 Summer 2004/V0.2 Experiment 2: The PIC 18Fxx2 Architecture and use the ‘Add Files...’ command to add mptst.asm to the project. At this point the project window should appear as shown on the right. Use ‘Project Set Language Toolsuite’ and choose ‘Microchip MPASM Toolsuite’. This selects the tools used to assemble or compile files in the project. Next, use ‘Configure →Select Device’ and select the PIC18F242 as the target device. Before doing any editing of the program, use ‘Project →Build All’ to assemble the program, which should produce a “Build Succeeded” message in the output window. Use ‘Debugger →Select Tool →MPLAB Sim’ to set the MPLAB simulator as the debugging tool. Use ‘View Program Memory’ to view the machine code of your program (use the Symbolic button the program memory window to see the most readable representation of the code). Use ‘View File Registers’ to view the internal memory of the PIC. Use ‘View Special Registers’ to view the special registers (W, TRISA, Simulating your program 2—3 Experiment 2: The PIC 18Fxx2 Architecture Summer 2004/V0.2 PORTA, etc.) of the PIC. Double click on the mptst.asm file in the project window to open a source file window. Use either F6 or ‘Debugger →Reset →Processor Reset’ to reset the processor’s program counter to point at the instruction in location 0. The figure below is approximately what should be displayed: Single Stepping 2—4 Use F7 or ‘Debugger Step Into’ to single step through the program. The Special Function Registers window is useful for observing changes to often-used registers such as W and STATUS. The File Registers window is useful for observing changes to all of the other internal memory locations of the PIC. Summer 2004/V0.2 Experiment 2: The PIC 18Fxx2 Architecture In this program, using the original value of 100 for the myid definition causes the k variable to finish with the value 201 (0xC9). Single step the program until location 9 is reached and verify that location 0x02 (corresponds to variable k) has the value 0xC9. To start the program back at location “0x0”, use “Debugger →Reset Processor →Reset” (bound to the F6 key). To clear data memory contents back to their original values, select “Debugger →Clear Memory →GPRs”. The command “Debugger →Clear Memory →All Memory” clears all memory including program memory requiring the file to be re-assembled before execution. Reset, Clearing Memory A project does not have to be created each time you want to assembly and simulate a file. Close MPLAB, then re-open it, and open the mptst.asm file. Next, use ‘Configure →Select Device’ and select the PIC18F242 as the target device. Now use ‘Project→Quickbuild mptest.asm’ to assemble the program without creating a project. If you only have one file to assemble, use QuickBuild instead of building a project. QuickBuild Mode instead of Projects The command “View →Watch” opens a watch window which is useful for monitoring select memory locations. After the watch window is opened, use the pull down list next to the Add Symbol button to list all variables in the program. Find the i symbol, then click Add Symbol to add it to the watch window. Do the same for the j, k variables. You are now able to monitor these values during program execution. Watch Window Use the command “Debugger →Animate” to watch the program execute in slow speed. Use the F5 key (halt) to stop execution. Animate Command 2—5 Experiment 2: The PIC 18Fxx2 Architecture Summer 2004/V0.2 B. Lab Activity Exploring PIC18 Data memory organization This part of the lab explores how the data memory of the PIC18 is organized. Table 2–2: Data Memory variations checkoff Activity Questions to be answered 1. Modify the mptst.asm file so that the CBLOCK starting location is now 0x80. Re-assemble and re-execute the program. Verify that the i, j, k variables are updated at locations 0x80-0x82. When the program memory is viewed, the instruction at program location 0x202 is now different from the original mptst.asm file. Record this difference, and determine the reason for this behavior. 2. Modify the mptst.asm file so that the CBLOCK starting location is now 0x100. Re-assemble and re-execute the program. Use the File Registers window to determine what locations are changed when the i, j, k variables are modified. Record these locations and determine the reason for this behavior. Hint: look at the definition of the BSR (Bank Select Register). 3. To the program in step 2, add the statement “MOVLB 0x1” just after the ‘main’ label and before the statement ‘movlw myid’. Re-assemble and re-execute the program. The “MOVLB” instruction is “Move Literal to Bank Select Register”; “MOVLB 0x1” moves the value 0x1 to the BSR (BSR= Bank Select Register). Use the File Registers window to determine what locations are changed when the i, j, k variables are modified. Record these locations and determine the reason for this behavior. 4. Based on the knowledge gained from steps 2 and 3, modify the mptst.asm program so that the i,,j,k variables are located at locations 0x200-0x202. Reassemble, re-execute, and verify that these locations are modified. Data Memory Banks in the PIC18 2—6 The data memory banks in the PIC18 is split into multiple banks. The PIC18F242 has three banks - bank0 (0x00-0xFF), bank1 (0x100-0x1FF), and bank2 (0x200-0x2FF). A 8-bit memory address within a PIC18 instruction word specifies the location within a bank; the value in the Bank Select Register (BSR) selects the bank that is accessed. The default value for the BSR is 0, which means that Bank 0 is selected by Summer 2004/V0.2 Experiment 2: The PIC 18Fxx2 Architecture default. To select Bank 1, the value 0x1 must be placed in the BSR. This can be done by executing the instruction: MOVLB 0x1 which moves the value 0x1 into the BSR, selecting bank 1. To select Bank 2, one can do: MOVLB 0x2 which moves the value 0x2 into BSR, selecting Bank 2. To reselect Bank 0, do: MOVLB 0x0 When specifying an address in a PIC18 instruction, if the ‘access’ bit is set, then the BSR register is ignored, and addresses 0x00-0x7F are mapped to locations 0x00-0x7F in bank 0 (access bank low), and addresses 0x80-FF are mapped to locations 0xF80-0xFFF (access bank high) which are the special function registers (WREG, STATUS, etc.). The ‘movf’ instruction below forces the address for j to be in the access bank. movf j,w,A ;ignore BSR register The ‘movf’ instruction below uses the BSR with the address of j: movf j,w,BANKED ; use BSR register With MPLAB, you should not have to use either the ‘A’ (use access bank) or ‘BANKED’ (use BSR) qualifiers on instructions as long as the CBLOCK statements have the full bank address for a variable (i.e, address 0x100 for ‘j’ places j in bank 1) as the default rules for variable access in the absence of ‘A’ or ‘BANKED’ make sense. If you do not explicitly specify the ‘A’ or ‘BANKED’ qualifier on an instruction, the following rules are used by MPLAB assembler: 2—7 Experiment 2: The PIC 18Fxx2 Architecture Summer 2004/V0.2 a. If the address for the variable is between 0x0 - 0x7F, or between 0xF80-0xFF (special function registers), then qualifier ‘A’ is assumed, which causes the BSR to be ignored, forcing it into bank 0. b. If the address is between 0x80 and 0xF7F, then qualifier ‘BANKED’ is assumed, which causes the BSR to be used for data access. SHOW THE TA THE RESULTS FOR STEPS 1-4 AND EXPLAIN THE REASONS BEHIND THE OBSERVED RESULTS. BE SURE TO INCLUDE THIS REASONING IN THE LAB REPORT. 2—8 Summer 2004/V0.2 Experiment 2: The PIC 18Fxx2 Architecture This portion of the lab explores moving data between memory banks. Moving data between banks . Table 2–3: Data Movement Checkoff Activity Questions to be answered 1. In MPLAB, open a “File Registers” window that shows locations 0x0000 through 0x0120. Click on the first line of ‘...’ under the ASCII column and type the first 5 letters of your first name, and seven digits of your phone number. Then type enough spaces so that the entire type in column has been filled. Record what appears in the hex locations 0x0 through 0x0F. Justify to yourself the reason for these values (and explain in the lab report). 2. Using the mptst.asm file as a starting point, create a new program with a series of data movement instructions that will move the contents of locations 0x0-0x7 to locations 0x100 -0x107. Verify the operation of this program by typing data of your choice into locations 0x0-0x7, executing your program, and verifying that the data is moved to locations 0x100-0x107. You may NOT use the ‘movff’ instruction in this program. You do not need a CBLOCK statement for this program, you can specify addresses for memory locations within instructions as: Create a new version of the program done in step 2 (keep the old version!) that uses the ‘movff’ instruction to accomplish the data movement (i.e., ‘movff 0x0, 0x100’ moves the contents of location 0x0 to 0x100). Re-assemble, and verify that your program exhibits the same behavior as the program in step 2. Starting at location 0x200 in Program Memory, determine the number of BYTES needed for this program (most PIC18 instructions need 2 bytes, some need 4 bytes). Report this number IN DECIMAL. 3. movf 0x0, w You may find the instructions “BSF BSR, 0” (bit set) and “BCF BSR, 0” (bit clear) useful. Starting at location 0x200 in Program Memory, determine the number of BYTES needed for this program (most PIC18 instructions need 2 bytes, some need 4 bytes). Report this number IN DECIMAL. Which program took fewer program bytes? DEMO THE PROGRAMS YOU WROTE IN STEPS 2 AND 3 TO THE TA. 2—9 Experiment 2: The PIC 18Fxx2 Architecture Summer 2004/V0.2 showid.asm The showid.asm program attached to this lab duplicates the action of the Student ID CPU of the previous lab by copying the even or odd digit sequence of a student ID to the out variable. The odd input is simulated through a variable called odd; if the least significant bit (LSB) of variable odd is 0 then the even sequence is chosen, else the odd sequence is chosen. Variable odd is located at location 0x0 in data memory; this value can be changed by opening a File Registers window and directly typing a new value in location 0x0. bit test and skip The LSB of variable odd is tested via the instruction sequence: btfsc odd, 0 goto odd_seq The btfsc instruction tests if a particular bit of the specified file register is clear (a logic 0 value). If the specified bit is clear, then the next instruction is skipped. In this case, the next instruction is a jump to the sequence of instructions the copies the odd sequence to the out variable. Controlling the value of odd Note that the variable odd is cleared to 0x00 by the instruction ‘clrf odd’. This causes the even sequence to always be chosen. To cause the odd sequence to be chosen after reset, replace the instruction ‘clrf odd’ with ‘bsf odd, 0’. This sets the LSB of file register odd to a logic 1. During program execution, you can type a new value for odd into the location 0x0 in the file registers window to change the number sequence that is displayed. The Stopwatch The command “Debugger →Stopwatch” can be used to display how many instruction cycles and how much time an instruction requires when executed. This is useful in determining the amount of execution time required for a particular section of code. The com- 2 — 10 Summer 2004/V0.2 Experiment 2: The PIC 18Fxx2 Architecture mand “Debugger →Settings” can be used to changed the simulated clock frequency of the processor. Table 2–4: showid Checkoff Checkpoint Comments 1. Single step through showid.asm in MPLAB for both odd and even sequences. Note that location 0x0 corresponds to out, and 0x01 to odd. To force the odd sequence, either do as above and modify the instruction that initializes odd, or directly change variable odd (location 0x20) by typing into the file register window. 2. Modify showid.asm to display the digits of your student id. Assemble and verify the operation. 3. Use the ‘Stopwatch’ command in the simulator and record the instruction cycles and time for displaying all of the odd digits of your student ID. This instruction count and time is for one complete pass through the loop. Use a time of 20 MHz and record this time. Then change the clock speed to 8 MHz and record this time. 4. Use the ‘Stopwatch’ command in the simulator and record the instruction cycles and time for displaying all of the even digits of your student ID. This instruction count and time is for one complete pass through the loop. Use a time of 20 MHz and record this time. Then change the clock speed to 8 MHz and record this time. DEMO THE SHOWID PROGRAM THAT DISPLAYS THE DIGITS OF YOUR STUDENT ID TO THE TA. The showid.asm program does a poor job of emulating the student ID CPU as the variables odd and out are internal memory locations and do not correspond to external pins on the PIC18Fxx2. However, you will soon discover that setting and testing external pin values is done in the same way as internal memory locations. A poor emulation? 2 — 11 Experiment 2: The PIC 18Fxx2 Architecture Summer 2004/V0.2 C. Report 1. Include the ‘.lst’ files of any assembly language programs written for this lab. 2. Include the MPLAB screenshot required in the prelab checkoff. 3. Include the results from Table 2–2 and your reasons for the observed behavior. 4. Include the results from Table 2–3 and your reasons for the observed behavior. 5. Include the results from Table 2–4 and verify via manual calculations that the recorded time for both even and odd sequences is correct, for both clock frequencies. Explain the execution time required for the ‘btfsc odd,0’ under both conditions (odd = 0 and odd = 1). 6. For the following instruction, assume j is location 0x64 and has an initial value of 0x40. Give the values of w and j after the instruction is executed as well as the machine code for the instruction: decf j, w 7. For the following instruction, assume j is location 0x7C and has an initial value of 0xDA. Give the values of w and j after the instruction is executed as well as the machine code for the instruction: incf j, f 2 — 12 Summer 2004/V0.2 E x p e r i m e n t Experiment 3: PIC18Fxx2: Instruction Set 3 PIC18Fxx2: Instruction Set Surely you’ve seen the TV commercial of the two female engineers mud-wrestling while arguing about the PIC instruction set1. “Less Filling!” “Tastes Great!”. Well, I’m not sure about tastes great, but less filling is right on. So much so, you often find yourself saying ‘Why in the #$!*& doesn’t it have instruction X?!?’ But, fewer instructions means less to know! Woot! Summary Experiment with different PIC instruction sequences in the context of C code examples. 1. At least, I think that’s what the argument is about. They never really say..... 3—1 Experiment 3: PIC18Fxx2: Instruction Set Summer 2004/V0.2 A. Prelab Requirements Table 3–1: Prelab Checkoff Do This 1. Comments The C programs ops_var{1-5}.c and loops_var{1-5}.c attached to this lab perform operations on three unsigned byte variables: i, j, k. Verify that you can compile and execute these programs on any machine/operating system of your choice. The programs variants 1 through 5 rearrange C statements in different orders. For the ‘ops’ programs, the files ‘ops_{al}.c’ define 12 different C operations that are included in different orders within ops_var{1-5}.c. For the ‘loops’ programs, the files ‘loops_{a-e}.c’ define 5 different C code segments that are included in different orders within loops_var{1-5}.c. These programs are used to illustrate how common C operations are implemented in PIC18F242 assembly language. These programs can be compiled and executed on the ECE Unix machine (leto.ece) once the ZIP archives have been unpacked into a common directory. An example compilation/execution is shown below: To compile: gcc -o ops_var1 ops_var1.c This produces the executable ops_var1 To execute: ./ops_var1 Print statements are included after each block of code to track variable modifications. 2. Compile and execute your assigned op and loop program variation as given by the tables below. Have a printout the values of i, j, k ready for checkoff. Understand the functionality of your assigned op/loop program as you are required to implement these in PIC 18F242 assembly language. Table 3–2: Program Variations for ‘ops’ If the last digit of your student ID is... 3—2 Use the program... 0 or 2 ops_var1.c 1 or 3 ops_var2.c 4 or 6 ops_var3.c 5 or 7 ops_var4.c 8 or 9 ops_var5.c Summer 2004/V0.2 Experiment 3: PIC18Fxx2: Instruction Set Table 3–3: Program Variations for ‘loops’ If the last digit of your student ID is... Use the program... 0 or 9 loops_var1.c 1 or 8 loops_var2.c 2 or 7 loops_var3.c 3 or 6 loops_var4.c 4 or 5 loops_var5.c In case you are a bit rusty on C (or have never had it!), here is a quick review. The use of C in this course is very simplistic; please refer to any C reference manual for deeper coverage of the topics presented here. A Quick C Review Variables declared as: unsigned char i, j, k; are 8-bit (byte) variables. The unsigned modifier is important as this affects how comparisons such as ‘>’ or ‘<‘ are performed; these variables are compared as unsigned values. Furthermore, the unsigned modifier causes a ‘0’ to be shifted into the most significant bit for a right shift (i >> 1); the MSB stays the same for a right shift of a signed data type. The table below explains the operators used in ops_var{1-5}.c. Table 3–4: Some C operators Operator Comment ++, -- increment (i++) or decrement (i--) the variable by one. +, - addition, subtraction 3—3 Experiment 3: PIC18Fxx2: Instruction Set Summer 2004/V0.2 Table 3–4: Some C operators Operator Comment >>, << right shift (i >> 1) or left shift (i << 1) a variable by the specified amount. For unsigned types, a right shift away shifts in a ‘0’ into the MSB. For signed types, a right shift leaves the MSB bit (sign bit) unchanged. For left shifts, a ‘0’ is always shifted into the LSB regardless of whether it is a signed or unsigned type. |, &, ^ bitwise OR (|), bitwise AND (&), bitwise XOR (^). A bitwise operation does the specified logic operation with each bit of the two operands. ~ Bitwise negation or complement operation ! Logical negation (i.e,!j); returns a ‘1’ if the operand is zero; returns a ‘0’ if the operand is non-zero. ==,!= Test for equality (i.e, i == j) returns a ‘1’ if i is equal to j, else returns ‘0’. The test for inequality (i.e, i != j) returns a ‘1’ if i is not equal to j, returns a ‘0’ otherwise. >, <, >=, <= Inequality tests of less than (<), greater than (>), greater than or equal (>=), less than or equal (<=). The bitset and bitclr macros in ops_var{1-5}.c use logical and shift operations to do a set or clear on the specified bit of the operation. The bittst macro returns the value of the specified bit in the operand; either ‘0’ or ‘1’. Loops and Conditions A condition test in C is considered false if the condition test returns a ‘0’ value; true if it returns a non-zero value. Thus an if statement written as: if (bittst(i,0)){ /* true block */ } else { /* false block */ } will execute the true block if the LSB of variable i is a ‘1’, else it will execute the false block. The for loop has three parts; initialization, condition test, and end-of-loop statements: 3—4 Summer 2004/V0.2 Experiment 3: PIC18Fxx2: Instruction Set for (init; ctest; end-of-loop) { /* loop body */ } A for statement is equivalent to a while statement written as: init; while (ctest) { /* loop body */ end-of-loop statements } The most common use of a for loop is to execute some block of code a fixed number of times: for (i=0; i < 10; i++) { /* loop body */ } The above code executes the loop body 10 times. The equivalent while statement is: i = 0; while (i < 10) { /* loop body */ i++; } The difference between a while loop and a do-while loop is that the loop body in a do-while loop is guaranteed to execute at least once because the condition test is done after the loop body. The above for loop can also be written as: for (i=0; i!= 10; i++) { /* loop body */ } Note that the bodies of both for loops execute 10 times. 3—5 Experiment 3: PIC18Fxx2: Instruction Set Summer 2004/V0.2 B. Lab Activity Table 3–5: ops in PIC18F242 Assembly Checkpoint 1. Comments/Debugging Convert your assigned ops_var{1-5}.c program to PIC18F242 assembly and verify that the i, j, k variables have the same values at each step as with the original C program. Use the table below to determine what file register locations to use for i, j, k. The print statements in the original C file cannot be converted; you must track the progress of the i, j, k variables by observing memory contents. Test your code for different i, ,j, k initial values. Use the STOPWATCH and record the amount of time it takes for this program to execute with a processor frequency of 20 MHz. Look at the hints below on implementing these C operations. Develop your program one operation at a time. There is no need to advance to the next operation until the current one produces the correct value. Do not worry about any code optimization; do it in the easiest, most straight forward manner. Modify the C code to have print statements after each operation if you do not trust your hand computation of the variable values. Table 3–6: Register file assignment for ops If the last digit of your student ID is... 0 or 1 i: 0x48 (bank 0), j: 0x49 (bank 1), k: 0xC8 (bank 2) 2 or 3 i: 0x51 (bank 2), j: 0x31 (bank 0), k: 0x52 (bank 1) 4 or 5 i: 0xE1 (bank 1), j: 0x60 (bank 2), k: 0x61 (bank 0) 6 or 7 i: 0x70 (bank 0), j:0xB1 (bank 2), k: 0x30 (bank 1) 8 or 9 i: 0xC4 (bank 1), j:0x44 (bank 0), k: 0xC5 (bank 2) STATUS Register: Carry, Zero Flags 3—6 Use the following locations... That STATUS register is a special function register whose individual bit values are called referred to as Summer 2004/V0.2 Experiment 3: PIC18Fxx2: Instruction Set flags, and which are set or cleared as a side-effect of instruction execution. There are two other bits in the STATUS register that are useful in this exercise. They are the carry flag (bit 0), and zero flag (bit 2). The carry (C) flag is affected in multiple ways, but the most common methods are through addition and subtraction. In an addition, the carry bit is set when there is a carry out of the MSB. In a subtraction, the carry bit is cleared if there is a borrow into the MSB during the subtraction. The carry flag will prove useful in unsigned comparisons operations. The zero (Z) flag is set whenever the result of an operation is zero. The zero flag is useful in equality tests. The C and Z flags are set as side-effects of PIC operations. Look at the instruction descriptions to determine when these flags are affected; not all instructions affect these flags. Convert each C operation separately from the other, and use the simulator to check the result as you go. Remember that the w register is involved in every twooperand PIC instruction. If it is a two-operand calculation such as k = i op j, use the approach: Converting the C operations to PIC Assembly 1. load the w register with i 2. perform op j; store the result in w 3. store the w register to k. For example, if the calculation is k = i + j, then: movf i,w ; w ← i addwf j,w ; w ← w + j movwf k,w ; k ← w This code assumes that i, j, k are all in bank0. If k is in bank1, the code is written as: movf i,w addwf j,w ; w ← i ; w ← w + j 3—7 Experiment 3: PIC18Fxx2: Instruction Set Summer 2004/V0.2 movlb 0x1 ; select bank1 movwf k,w ; k ← w movlb 0x0 ; re-select bank 0 If the operation k=k+i, then the code is written as: movf i,w ; w ← i movlb 0x1 ; select bank1 addwf k,f ; k ← w + k movlb 0x0 ; re-select bank 0 Note that in this case the addwf command is written to modify the k file register location. This is because k is both a source operand of the operation, and the destination. arithmetic operations The arithmetic operations (addition, subtraction, increment, decrement), are straightforward as there are PIC instructions that do all of these. Remember that with the subtraction operation, it is f - w, where f is the file register value, and not vice-versa. The increment and decrement operations are convenient in that a separate instruction does not have to be used to load the w register with the operand value; the instruction does this automatically. logical operations The PIC has instructions for AND, OR, XOR, and complement (negation) that do the equivalent of the bitwise operations in C, so conversion is again straight forward. Shift operations The PIC has two rotate instructions (left and right) that are used to implement shift operations. A rotate right performs a shift right, with the MSB filled by the value of the carry bit, and the LSB becoming the new carry bit. A single shift right (i >> 1, i is an unsigned char) using a rotate instruction is written as: bcf STATUS,C rrcf i,f 3—8 ; clear carry Summer 2004/V0.2 Experiment 3: PIC18Fxx2: Instruction Set Repeat this sequence as many times as needed to accomplish the specified C shift operation. Do not put the code in a loop; simply duplicate the two-instruction sequence. In the above code, STATUS and C are symbols that are defined in the “pic18f242.inc’ file as: STATUS EQU H'0FD8' C EQU H'0000 The previous BCF instruction could have been written as: bcf 0xFD8,0 ; clear carry but this is much less readable. Symbols for special function registers and bits/bit fields within special function registers are declared in “pic18f242.inc”. Use these symbols to improve code readability. These symbols are all declared as uppercase, and MPLAB is case sensitive, so you will get an ‘undeclared symbol error’ for the following code: bcf status,c ; clear carry because ‘status’ and ‘c’ are lowercase. A shift left (i << 1) is done in the same way; clear the carry flag before executing the rotate instruction: bcf STATUS,C ; clear carry rlcf i,f DEMONSTRATE YOUR OPS.ASM PROGRAM AND SHOW THAT THE I, J, K RESULT VALUES ARE THE SAME AS PRODUCED BY THE C CODE. BE PREPARED TO CHANGE THE INITIAL VALUES OF I, J, K. 3—9 Experiment 3: PIC18Fxx2: Instruction Set Summer 2004/V0.2 Table 3–7: loops in PIC18F242 Assembly Checkpoint 1. Comments/Debugging Convert your assigned loops_var{15} program to PIC18F242 assembly and verify that the i, j, k variables end up with the same values as your original C program. Use the same variable location assignments as used for the ops program. Look at the hints below on implementing loops and condition checks in PIC assembly language. Again, convert one block at a time and verify the result before proceeding to the next block. Test your code for different i, ,j, k initial values. Condition Tests A condition test is part of all loops and if statements. The four types of condition tests used in this lab are: 1. 2. 3. 4. Test for bit set or clear test for a particular bit being zero or non-zero test if an entire byte is zero or non-zero test if a byte is less than or greater than a value test if a byte is equal to another value An condition check for a particular bit set or clear is easy because the PIC has direct instructions for this. The C code: if (bittst(i,5)) { /* true block */ } else { /* false block */ } can be directly translated as: btfss i, 5 goto false_block true_block 3 — 10 Summer 2004/V0.2 Experiment 3: PIC18Fxx2: Instruction Set ...true blk goto false_block_end false_block ...false blk false_block_end ... remaining statements Note that the ‘bit test and skip if set’ (btfss) instruction is used because the condition is checking for the bit being equal to a ‘1’. The condition below: if (i) { /* if_body */ } executes the if body if i is nonzero. This can be implemented as: movf i,f ;move i onto itself! btsfc STATUS, Z goto skip ; Z=1, so i == 0 ...if body... skip ... rest of code Note that the movf i,f instruction moves i onto itself; the only useful thing this accomplishes is setting the Z flag if i is zero. The if body true is executed if i is nonzero. The condition below: if (!i) { Zero/Nonzero Test with branch instruction /* if_body */ } executes the if body if i zero. This could be implemented using the ‘movf/btsfsc’ approach above, or can be done by PIC18 code: 3 — 11 Experiment 3: PIC18Fxx2: Instruction Set Summer 2004/V0.2 tstfsz i ; is i == 0? goto skip ; i != 0, skip ...if body... i is zero skip ... rest of code The tstfsz instruction is ‘test F, skip if zero’; it skips the next instruction if the file register contents is zero. There is usually more than one way to accomplish a task, use the approach that you understand the best. Zero/Nonzero Test with branch instructions The condition below: if (i) { /* if_body */ } can be implemented using the branch instructions, which are conditional goto instructions based upon the setting of a single flag bit in the status register: movf i,f bz skip ;move i onto itself! ; skip if Z=1 ...if body... skip ... rest of code The ‘bz skip’ (branch on zero) instruction jumps to skip (branches to skip) if Z = 1. The condition below: if (!i) { /* if_body */ } can be written as: 3 — 12 movf i,f ;move i onto itself! bnz skip ; skip if Z=0 Summer 2004/V0.2 Experiment 3: PIC18Fxx2: Instruction Set ...if body... skip ... rest of code Using branches typically improves code clarity and reduces instruction count. The remaining code examples use branches to implement condition tests. To perform a test such as A > B, note that this is the same as A - B > 0. This test is true if the result is nonzero (Z = 0) and if no borrow occurred during the subtraction (C = 1). Written in a boolean fashion: <, > tests (A-B > 0) is true if (!Z) & C (A-B > 0) is false if Z |!C The false test is derived by using DeMorgan’s law on the true test. The statement below: if (i > j) { /* if body */ } can be to translated to PIC assembly as: movf j,w ;w ← j subwf ; w ← i - w i,w bz skip ; skip if Z=1 bnc skip ; skip if C=0 ; Z=0 & C=1, do if body ..if body.... skip ... rest of code... The subtraction operation is written to leave the operands unchanged; its only purpose is to affect the flags. Note that the if body is executed if the two successive bit operations are both true (the AND condition, as in ‘!Z & C’). The if body is not executed if either bit test fails (the OR condition, as in ‘Z | !C’). 3 — 13 Experiment 3: PIC18Fxx2: Instruction Set Summer 2004/V0.2 The test for i > j is accomplished in fewer statements if the subtraction j - i is performed instead of i - j. If i is greater than j, then j - i will produce a borrow (C = 0). Thus, the PIC assembly is written as: movf i,w ;w ← i subwf ; w ← j - i j,w bc skip ;skip if C=1 ; C=0, do if body ...if body.... skip ... rest of code... To implement if (i >= j) { /* if body */ } the subtraction i-j will not produce a borrow (C=1) if the comparison i >= j is true. This is implemented as: movf j,w ;w ← j subwf ; w ← i - j i,w bnc skip ;skip if C=0 ; C=1, do if body ...if body.... skip ... rest of code.. The table below shows the subtraction operation and C flag test required for the comparison i > j and i >= j which is sufficient for all comparisons (i < j can be written as j > i, and i <= j is j >= i). 3 — 14 Summer 2004/V0.2 Experiment 3: PIC18Fxx2: Instruction Set Unsigned Comparison Operation Flag setting if true Flag setting if false i>j j-i C = 0 (borrow occurred) C=1 (no borrow) i >= j i-j C = 1 (no borrow) C=0 (borrow occurred) An alternate method of accomplishing: Compare instructions if (i > j) { /* if body */ } is to use the cpfsgt instruction (Compare F with W, skip if >). This instruction combines the ‘subwf’ and ‘btfsc’ of the previous example into one instruction. Thus, the PIC18 assembly is written as: movf j,w ;w ← j cpfsgt ; i > j? i goto skip ;skip if i =< j ; i > j, do if body ...true block.... skip ..rest of code... The instruction cpfslt instruction (Compare F with W, skip if <) can be used for the i < j compare operation. The >= (greater than or equal) test: if (i >= j) { /* if body */ } can be written as: 3 — 15 Experiment 3: PIC18Fxx2: Instruction Set Summer 2004/V0.2 if (! (j > i)) { /* if body */ } which reads “if NOT ( j > i) ”. One way to implement the above test in PIC18 assembly is: movf i,w cpfsgt j ;w ← i ; j > i? goto if_body ;i >= j goto skip ;j > i if_body .... if body code.... skip ..rest of code... WARNING: While the compare instructions can result in fewer instructions, they cannot be used for 16-bit inequality comparisons. The subtraction/flag test approach is the more general approach and you need to understand it as we will be using that approach for other types of comparisons in future labs. Equality, Inequality tests Equality (i == j) and inequality (i != j) are done in a similar manner using the subtraction operation. Equality is true if Z=1 after the i-j operation; inequality is true if Z=0 after the i-j operation. The cpfseq instruction (compare F, skip if equal) can also be used if desired. DEMONSTRATE YOUR LOOPS.ASM PROGRAM AND SHOW THAT THE I, J, K RESULT VALUES ARE THE SAME AS PRODUCED BY THE C CODE. BE PREPARED TO CHANGE THE INITIAL VALUES OF I, J, K. 3 — 16 Summer 2004/V0.2 Experiment 3: PIC18Fxx2: Instruction Set C. Report 1. Include the lst files for all assembly language programs and any C source code. Comment your assembly language program very well; at least one comment every other line (points will be deducted if your assembly program is not well commented). 2. For the ops program, calculate the total number of 8-bit operations performed (each 8-bit assignment counts as 1, each logical/add/sub/inc/dec counts as 1, each shift operation counts as 1). For shift operations, count each required shift as 1 (a >> 3 counts as 3 shift operations). Make this calculation based on the C code, not the assembly code. Take the execution time value recorded for the ops program, and divide by the total number of 8-bit operations to get an average execution time per 8-bit operation. Take the inverse of this value to get the number 8-bit operations per second that can be expected from the PIC18 running at 20 MHz. Compare this to what is obtained by taking the ADDWF instruction and computing the same values based on its execution time. Why are the values different? Discuss this in your report. What could be done differently in the ops program to give it higher performance? 3 — 17 Experiment 3: PIC18Fxx2: Instruction Set 3 — 18 Summer 2004/V0.2 Summer 2004/V0.2 E x p e r i m e n t Experiment 4: Data: Wider is Better 4 Data: Wider is Better µP life crawled out upon the silicon beach in 1972 as a 4-bit critter, then began expanding faster than a Japanese rubber-suit monster eating nuclear waste -- first 8 bits, then 16, 32...64...128....Mommie!!! Will the madness ever stop?! ...Hopefully not, because then us hardware types would be out of a job. Can the lil’ ol PIC handle wide data? Sure! ... Fast?.... Nope! But many times, getting the job done slowly is perfectly alright. But don’t try that with your lab report! Summary Experiment with manipulating 16-bit arithmetic operations, and comparisons on 16-bit unsigned and signed data. 4—1 Experiment 4: Data: Wider is Better Summer 2004/V0.2 A. Prelab Requirements Table 4–1: Prelab Checkoff Do This 1. Comments The C programs intops_var{1-5}.c attached to this lab performs operations on two unsigned 16-bit integer variables: i, j. The C programs unsigned_var{1-5}.c performs operations on two unsigned 16bit variables. The C programs signed_var{1-5}.c performs operations on two signed 16-bit variables. Verify that you can compile and execute your assigned program versions on any machine/operating system of your choice. When viewing the printed i, j values from within signed_var{1-5}.c, ignore the most significant four ‘F’ digits if 8 hex characters (32-bits) are displayed for a value. This is the extension of the sign bit to 32bits. Have a printout of the i, j values for both programs ready for checkoff. 2. The following HEX values are 2’s complement, 8-bit integers. Convert to decimal. a) 0xFD, b)0x70 c) 0x82 3. Convert the following signed decimal values to 8-bit two’s complement values. Write the values in Hex. a) -20 b) -78 4. c) + 39 Perform the following operations, give the result in hex. Also give the values for the N, V, C flags based on the 16-bit computation. a) 0xA8AF + 0x9C23 b) 0x49B0 - 0x82F3 5. The machine code for a branch instruction is 0xE4E6 and is located at address 0x0232. What branch instruction is this and what is the target address? 6. What is the machine code for instruction sequence below. Does this machine depend on where it is located in memory? here bra here 4—2 Summer 2004/V0.2 Experiment 4: Data: Wider is Better Table 4–2: Program variations for ‘intop’ If the last digit of your student ID is... Use the program... 0 or 3 intop_var1.c 1 or 4 intop_var2.c 2 or 5 intop_var3.c 6 or 9 intop_var4.c 7 or 8 intop_var5.c Table 4–3: Program variations for ‘unsigned’, ‘signed’ If the last digit of your student ID is... Use the programs... 0 or 1 unsigned_var1.c, signed_var1.c 2 or 3 unsigned_var2.c, signed_var2.c 4 or 5 unsigned_var3.c, signed_var3.c 6 or 7 unsigned_var4.c, signed_var4.c 8 or 9 unsigned_var5.c, signed_var5.c The char data type is always 8 bits regardless of the processor type. The size of the int data type is dependent upon the processor and is typically 32 bits. A short int is 16 bits. A long data type on high performance CPUs is 64 bits; on most other CPUs it is 32 bits. The following program can be used to determine the data sizes of a particular C implementation: Data Sizes in C main() { printf (" A char is %d bits.\n", sizeof(char)*8); printf (" A short int is %d bits.\n", sizeof(short int)*8); printf (" A int is %d bits.\n", sizeof(int)*8); printf (" A long is %d bits.\n", sizeof(long)*8); 4—3 Experiment 4: Data: Wider is Better Summer 2004/V0.2 } By default, a char, int, or long type is assumed signed unless specified otherwise via the unsigned modifier. 4—4 Summer 2004/V0.2 Experiment 4: Data: Wider is Better B. Lab Activity Table 4–4: intops.c in PIC16F873 Assembly Checkpoint 1. Comments/Debugging Convert your assigned intops_var{1-5}.c program to PIC18F242 assembly and verify that the i, j variables finish with the same values as your original C program. Use the table below to determine what file register locations to use for i, j. Test your code for different i and j initial values. Use the STOPWATCH and record the amount of time it takes for this program to execute with a processor frequency of 20 MHz. Look at the hints below on implementing these C operations. Develop your program one operation at a time. There is no need to proceed to the next operation until the current one produces the correct value. Do not worry about any code optimization; do it in the easiest, most straight forward manner. Modify the C code to have print statements after each operation if you do not trust your hand computation of the variable results. Table 4–5: Register file assignment for intops.c If the last digit of your student ID is... Use these locations... 0 or 9 i: 0x53 (bank 0), j: 0x55 (bank 0) 1 or 8 i: 0x5A (bank 0), j: 0x5E (bank 0) 2 or 7 i: 0x63 (bank 0), j: 0x68 (bank 0) 3 or 6 i: 0x71 (bank 0), j: 0x77 (bank 0) 4 or 5 i: 0x4A (bank 0), j: 0x4C (bank 0) When storing an integer that is more than one byte in memory, the bytes can arranged either least significant to most significant (little endian) or most significant to least significant (big endian). On an 8-bit processor like the PIC, the choice is up to the programmer. There is no inherent advantage to either ordering. As an example, the code below uses little endian format for Storing 16-Bit values in memory 4—5 Experiment 4: Data: Wider is Better Summer 2004/V0.2 the 16-bit variable i that is initialized to the value 0xC428: CBLOCK 0x040 i_low, i_high ENDC org 0 movlw 0x28 movwf i_low ; LSB = 0x28 movlw 0xc4 movwf i_high ;MSB = 0xC4 The low and high bytes are explicitly named i_low and i_high for clarity, with i_low at location 0x40 and i_high at location 0x41. Another way to accomplish the same thing is shown below: CBLOCK 0x040 i:2 ENDC org 0 movlw 0x28 movwf i ; LSB = 0x28 movlw 0xc4 movwf i+1 ;MSB = 0xC4 In this example, the statement i:2 reserves two bytes of storage for i. The Least Significant Byte (LSB) is referenced as i, while the Most Significant Byte (MSB) is referenced as i+1 as it resides in the byte location following the LSB. In these examples, little endian byte ordering will always be used. 4—6 Summer 2004/V0.2 Experiment 4: Data: Wider is Better Assume that the 16-bit variables i, j are declared as shown below: Addition/Subtraction of 16-bit values CBLOCK 0x040 i:2, j:2 ENDC The operation i= i+j can be accomplished via: movf j,w addwf i,f movf ; w ← j (LSB) ;i LSB ← i LSB + w j+1,w ; w ← j (MSB) addwfc i+1,f ;i MSB← i MSB + w +C The addwfc instruction adds the C (Carry) flag to the sum of the two MSBs; if a carry is produced by the addition of the two LSBs then C=1 and this adds a +1 to the MSB sum. Similarly, in an i=i-j operation, the MSB subtraction is performed by the subwfb instruction the subtracts from W with a borrow. This subtracts a 1 from the MSB subtraction if the subtraction of the two LSBs produces a borrow. movf j,w subwf i,f movf ; w ← j (LSB) ;i LSB ← i LSB - w j+1,w ; w ← j (MSB) subwfb i+1,f ;i MSB← i MSB - w -(~C) Increment and decrement also can also use the addwfc/ subwfb instructions. One way to do an integer increment (i++) is: movlw 0x00 incf i,f increment, decrement ; w ← 0 ;i LSB ← i LSB + 1 addwfc i+1,f ;i MSB← i MSB + 0 +C 4—7 Experiment 4: Data: Wider is Better Summer 2004/V0.2 The ‘movlw 0x00’ instruction is needed to ensure that W is zero for the addwfc instruction used on the MSB. The following is a more efficient 16-bit increment: infsnz i,f ;i LSB ← i LSB + 1 incf ;i MSB← i MSB + 1 i+1,f The infsnz instruction is “increment, skip if nonzero”. If the result of incrementing the LSB is a zero, then this means a carry is produced, and the MSB must be incremented. However, it cannot be generally applied to values greater than 16-bits. A 16-bit decrement (i--) can be performed as: ; w ← 0 movlw 0x00 ;i LSB ← i LSB - 1 decf i,f subwfb i+1,f ;i MSB← i MSB -0 - (~C) or as: tstfsz i ; is LSB 0? ;i MSB ← i MSB - 1 decf i+1,f decf i,f ;i LSB← i LSB -1 The second version tests to see if the LSB is zero; if yes, then MSB is also. left, right shift For an unsigned right shift operation, the MSB is shifted first followed by the LSB, with the carry flag propagating the carry bit from the MSB to the LSB. The operation i = i>>1 is written as: bcf STATUS,C ; clear carry rrcf i+1, f ; i MSB >> 1 rrcf i, f ; i LSB >> 1 For a left shift operation, the reverse is done; the LSB is shifted first followed by the MSB. 4—8 Summer 2004/V0.2 Experiment 4: Data: Wider is Better DEMONSTRATE YOUR INTOPS.ASM PROGRAM AND SHOW THAT THE I, J RESULTS ARE THE SAME AS PRODUCED BY THE C CODE. BE PREPARED TO CHANGE THE INITIAL VALUES OF I, J. 4—9 Experiment 4: Data: Wider is Better Summer 2004/V0.2 Table 4–6: unsigned 16-bit comparisons in PIC18F242 Assembly Checkpoint 1. Comments/Debugging Convert your assigned unsigned_ver{15}.c program to PIC18F242 assembly and verify that the i, j variables finish with the same values as the C program. Use the same file register locations for i, j as used for the previous section. Use any address you want for variable k. Look at the hints below on implementing signed comparisons in PIC assembly language. Again, convert one block at a time and verify the result before proceeding to the next block. Test your code for different i and j initial values. Unsigned 16-bit comparisons Unsigned 16-bit comparisons are performed using the subtraction/C flag test as was done for 8-bit numbers. The comparison: unsigned int i, j; if (i > j) { /* if body */ } is accomplished by performing j-i and checking if C=0. In PIC18 assembly this is: movf i,w subwf j,w movf ; w ← i (LSB) ; w ← j LSB - i i+1,w ; w ← i (MSB) subwfb j+1,w ; w← j MSB -i MSB-(~C) bc skip ; C = 1, j >= i, so skip ... if _body.... skip .... rest of code The cpfsgt or cpfslt instructions cannot be used for 16bit unsigned compares. 4 — 10 Summer 2004/V0.2 Experiment 4: Data: Wider is Better The equality test below: 16-bit Equality tests unsigned int i, j; if (i == j) { /* if body */ } is done by performing i-j (or j-i) and checking if both byte results are zero: movf j,w ; w ← j (LSB) subwf i,w ; w ← i LSB - j bnz skip ;skip if LSB != 0 j+1,w ; w ← j (MSB) movf subwfb i+1,w ; w← i MSB -j MSB-(~C) bnz skip ;skip if MSB !=0 ... if _body.... skip .... rest of code The nonzero test below: 16-bit Zero/Nonzero tests unsigned int i, j; if (i) { /* if body */ } is done by determining if i is non-zero: ; w ← i (LSB) movf i,w bnz if_body movf i+1,w ; w ← 1 (MSB) bz skip ; ; if Z=0, i nonzero if Z=1, then i==0 if_body ... if body code... skip 4 — 11 Experiment 4: Data: Wider is Better Summer 2004/V0.2 The above code checks each byte of i to see if it is zero or non zero. The if body is executed if either byte is non-zero. DEMONSTRATE YOUR UNSIGNED PROGRAM AND SHOW THAT THE I, J RESULTS ARE THE SAME AS PRODUCED BY THE C CODE. BE PREPARED TO CHANGE THE INITIAL VALUES OF I, J. Table 4–7: signed 16-bit comparisons in PIC18F242 Assembly Checkpoint 1. Comments/Debugging Convert your assigned signed_ver{1-5}.c program to PIC18F242 assembly and verify that the i, j variables finish with the same values as the C program. Use the same file register locations for i, j as used for the previous section. Use any address you want for variable k. Look at the hints below on implementing signed comparisons in PIC assembly language. Again, convert one block at a time and verify the result before proceeding to the next block. Test your code for different i and j initial values. Signed Comparisons 4 — 12 Using the same subtraction/C flag test for signed values (2’s complement values) does not work. Table 4– 8 shows the result if unsigned comparisons are used Summer 2004/V0.2 Experiment 4: Data: Wider is Better for signed numbers. Note that if both numbers are posTable 4–8: Signed Comparisons for ‘>’ Numbers As unsigned i > j? As signed i >j? i = 0x7f, j = 0x01 i = 127, j = 01 True i = +127, j = +01 True i = 0x80, j = 0xFF i = 128, j = 256 False i = -128, j = -1 False i = 0x80, j = 0x7F i = 128, j = 127 True i = -128, j = +127 False i = 0x01 j = 0xFF i = 1, j = 255 False i = 1, j = -1 True itive or both negative, comparing the numbers as unsigned numbers gives the same results as signed comparison. However, if the numbers are different signs, the wrong answer is produced. A subtraction approach is used for signed comparisons, but instead of using the C flag, the N and V flags are tested. The N flag is called the negative flag and is set when the MSB for a result is ‘1’, indicating the result is negative for a two’s complement number. The V flag is called the overflow flag and is set when the result produces two’s complement overflow. For addition, overflow occurs when the sum of two positive numbers is negative, or the sum of two negative numbers is positive. For subtraction, overflow occurs when a negative number subtracted from a positive number results in a negative number, or when a positive number subtracted from a negative number results in a positive number. Integer Signed Comparison: N, V flags 4 — 13 Experiment 4: Data: Wider is Better Summer 2004/V0.2 Assume we want to do the following signed integer comparison: signed int i, j; if (i > j) { /* if body */ } If i > j is true, the subtraction j - i should produce a negative result (N=1, and V = 0). However, if overflow occurs, the result is incorrect, or positive (N = 0, V = 1). PIC18 assembly code to accomplish this is: ; for i>j, do j-i movf i,w ;w= i LSB subwf j,w ;w= j LSB - i LSB movf i+1,w ;w= i MSB subwfb j+1,w ;w= j MSB - i MSB -~C bn chk_v bnov skip ; skip if N=0,V=0 bra if_body ; true if N=0,v=1 chk_v bov skip ; skip if N=1,V=1 if_body ...if_body.... skip ... rest of code The above code uses the branch instructions which cause a jump to the specified label based on the status of a single bit in the STATUS register. The branch instructions used above are bn (branch if negative), bnov (branch if no overflow), bov (branch if overflow). The table below shows the operation required and flag settings for the comparisons i > j and i >= j. 4 — 14 Summer 2004/V0.2 Experiment 4: Data: Wider is Better Signed Comparison Operation Flag settings if true Flag settings if false i >j j-i N=1 & V=0 or N= 0 & V = 1 N=1 & V=1 or N=0 & V=0 i >= j i-j N=0&V=0 or N=1&V=1 N=0 & V=1 or N =1 & V = 0 Note that the previous approach for signed int data can also be used in a simpler form for signed char data by performing an 8-bit subtraction instead of a 16-bit subtraction. Equality, zero, and non-zero tests for signed 16-bit data is performed in the same way as for unsigned data. Equality, zero, nonzero tests for 16-bit signed data DEMONSTRATE YOUR UNSIGNED PROGRAM AND SHOW THAT THE I, J RESULTS ARE THE SAME AS PRODUCED BY THE C CODE. BE PREPARED TO CHANGE THE INITIAL VALUES OF I, J. The branch instructions use PC Relative Addressing to compute the target address for the branch. The machine code for a branch instruction specifies a word displacement (1 word = 2 bytes). Let PC be the address of the branch instruction, and disp be the displacement within the machine code for a branch instruction. The target address of the branch is computed as: PC Relative Addressing Target Address = PC + 2 + disp * 2 The value ‘2’ is added to the PC because the PC will have been incremented to the next instruction (two byte locations), and the displacement is multiplied by two because it is a word displacement (1 word = 2 4 — 15 Experiment 4: Data: Wider is Better Summer 2004/V0.2 bytes). The Target and PC addresses are byte addresses. The displacement can be calculated as: disp = [Target Address - (PC+1)]/2 The displacement is a 2’s complement number; a negative displacement means the target address is at or before the branch instruction, while a positive displacement indicates the target address is ahead of the branch instruction. 4 — 16 Summer 2004/V0.2 Experiment 4: Data: Wider is Better C. Report 1. Include the lst files for all assembly language programs and any C source code. Comment your assembly language program very well; at least one comment every other line (points will be deducted if your assembly program is not well commented). 2. For the intops program, calculate the total number of 16-bit operations performed (each 16-bit assignment counts as 1, each logical/add/sub/inc/dec counts as 1, each shift operation counts as 1). For shift operations, count each required shift as 1 (a >> 3 counts as 3 shift operations). Make this calculation based on the C code, not the assembly code. Take the execution time value recorded for the intops program, and divide by the total number of 16-bit operations to get an average execution time per 16-bit operation. Take the inverse of this value to get the number 16-bit operations per second that can be expected from the PIC18 running at 20 MHz. Compare this to what is obtained by taking the ADDWF instruction, computing the same values based on its execution time, and multiplying by 2. Compare these two values, discuss reasons for any differences. 3. Pick the machine code for either a BOV or BNOV in your signed program, and show that the displacement value in the machine code is correct given the PC and target address values. 4. What is missing from the cmpsgt that does prevents it from being used for 16-bit compares? (HINT, think about what is needed for a multi-byte compare). What could be changed about its operation to make it useful for extended compares? 5. Suggest two new branch instructions that could be added to the PIC18 instruction set that would improve execution time of signed compares. Describe the operation of these branches. 4 — 17 Experiment 4: Data: Wider is Better 4 — 18 Summer 2004/V0.2 Summer 2004/V0.2 E x p e r i m e n t Experiment 5: Beyond Assembly Language 5 Beyond Assembly Language By now you have figured out that programming in assembly language is just great....if you are a control freak. You get to specify how each and every instruction cycle of the PIC’s existence is spent. However, this can become.....tedious. So why learn assembly language? That answer is easy -- to learn how to write an efficient C compiler so that we don’t have to write assembly language any more! Yippee! Summary Experiment with indirect addressing and subroutines in PIC assembly language. Then investigate the PICC18 compiler for compiling C programs to PIC18Fxx2 machine code. 5—1 Experiment 5: Beyond Assembly Language Summer 2004/V0.2 A. Prelab Activity Table 5–1: Prelab Checkoff Do This Comments 1. Read the sections below on pointers in C and PIC assembly language. Pointers in PIC assembly language are also covered in your textbook; these notes are meant to supplement that material, not replace it. 2. Read the Lab Activity section and find the C program that you are assigned to convert to assembly language. Make a good faith effort at beginning to implement this in PIC assembly language and have a listing to show the TA for checkoff. A ‘good faith effort’ means that the program is mostly complete and partially debugged. Having one or two lines of assembly language is not ‘good faith’. Pointers in C Pointers in C are convenient as they allow a single reference to a block of data to be passed to a subroutine, instead of having to copy the block of data itself to the subroutine. The C code below includes a subroutine that counts the number of characters in a string. Recall that strings in C are terminated by a 0x00 (null) value. char s1[] = "Upper/LOWER."; unsigned char strcnt (ptr) unsigned char *ptr; { unsigned char i; i = 0; while (*ptr != 0) { ptr++; i++; } return(i); } 5—2 Summer 2004/V0.2 Experiment 5: Beyond Assembly Language main() { unsigned char i; i = strcnt(s1); } A pointer contains the memory address of the variable that the pointer is referencing. In the above code, the subroutine call strcnt(s1) passes the address of the first character of s1 to the strcnt subroutine; this address is stored in the variable ptr, which is a pointer to a char data type. To read the data that a pointer variable is referencing, the ‘*’ is placed in front of the pointer variable. The statement *ptr returns the data value that ptr is referencing, which in this case is the ASCII value of the first character of string s1 (a ‘U’ = 0x55). The statement ptr++ increments the pointer to the address of the next character in the string. To replace the value that a pointer is referencing, a statement such as *ptr = new_value is used. Accessing variables through pointers is also called indirect addressing. Two special sets of registers, INDF{0-2} and FSR{02} are used to implement indirect addressing in the PIC. An FSRn register holds the value of the pointer itself. An INDFn register is used to access the data that the pointer is referencing. An implementation of the strcnt function in PIC assembly language is shown below. Pointers in PIC assembly language ;space for strings in data memory CBLOCK 0x280 ;put in bank2 for grins s1:0x10,s2:0x10 ;16 bytes max ENDC org 0 goto main ;; org 0x0200 main 5—3 Experiment 5: Beyond Assembly Language Summer 2004/V0.2 ;; copy strings from program memory to data memory call init_s1 call init_s2 ;; set up call for strcnt movlw low s1 movwf ptr movlw high s1 movwf ptr+1 ;; ptr = s1 value call strcnt ;; do strcnt ;; cnt value is stored in 'i', returned in 'w' here goto here ;parameter, local storage block for strcnt subroutine CBLOCK 0x0 i,ptr:2; ENDC strcnt clrf i ;; clear i movff ptr,FSR0L ;; set FSR low byte movff ptr+1,FSR0H ;; set FSR high byte strcnt_loop movf INDF0,w ;; get current char bz strcnt_exit ;; exit if zero movwf 0 ;;clear w infsnz FSR0L,f ;; inc FSR0, or ptr++ incf FSR0H,f incf i,f ;; increment char count bra strcnt_loop strcnt_exit return Subroutine Parameters 5—4 The strcnt subroutine has one parameter (ptr) and one local variable (i). In more powerful CPUs that have more registers and a stack that can be modified under Summer 2004/V0.2 Experiment 5: Beyond Assembly Language program control, the parameters are passed in registers or on the stack. However, in the PIC18Fxx2, the lack of these features means that allocating static space for parameters is a good solution from a performance and memory usage point of view. Limitations with this method are: 1. The subroutine cannot be called recursively (the subroutine cannot call itself). 2. The subroutine cannot be interrupted, and then called from the interrupt service routine (interrupts will be covered in a later lab exercise). In the example above, the i local variable and the ptr parameter are allocated in a CBLOCK. In main, the ptr value is initialized with the address of s1 before the strcnt subroutine is called. The address of s1 can be anywhere in the 4K byte data address space, so two bytes are required for ptr. The assembler directive ‘high s1’ returns the 2nd byte (bits 15-8) of the s1 address; while ‘low s1’ returns the LSB (bits 7-0) of the s1 address. main code In the strcnt subroutine, the FSR0 register is initialized with the value of ptr, which points to the first character in the s1 string. The FSR0 register is a 12 bit register because it points to data memory space, which can be up 4K bytes. strcnt subroutine The instruction movf INDF0,w reads the byte referenced by the FSR0 register, places it in the W register, and affects the Z flag in the process of loading w. This is important, as the end of a string is marked by a 0x00 value (a null byte). If the Z flag is set, the subroutine is exited via a return statement, with i containing the number of characters in the string. If the Z flag is clear, the i variable is incre- 5—5 Experiment 5: Beyond Assembly Language Summer 2004/V0.2 mented to keep track of the number of characters in the string, and the FSR0 pointer is incremented to point at the next character in the string via: infsnz FSR0L,f incf FSR0H,f ;; inc FSR0,or ptr++ The FSR0L and FSR0H registers refer to the low and high byte of the FSR0 register, which is 12-bits wide. You may be tempted to do something like: incf FSR0,f This does NOT WORK, as FSR0 is a 12 bit register; the incf instruction only works on an 8-bit register. POSTINC0 Incrementing or decrementing FSRn registers are a common operation. The strcnt assembly code can be written in a more efficient manner as: strcnt clrf i ;; clear i movff ptr,FSR0L ;; set FSR low byte movff ptr+1,FSR0H ;; set FSR high byte strcnt_loop movf INDF0,w ;; get current char bz strcnt_exit ;; check if zero movf POSTINC0,w ;; inc FSR0 incf i,f ;; increment char count bra strcnt_loop strcnt_exit return In the above code, the FSR0 register is incremented by the instruction: movf POSTINC0,w The above instruction does two operations: it reads the byte referenced by FSR0 and places it in w, then incre- 5—6 Summer 2004/V0.2 Experiment 5: Beyond Assembly Language ments the FSR0 register. In this case, we do not care about the character moved into w; incrementing FSR0 is the desired result. Think of POSTINC0 as another name for INDF0, in which the side effect of using POSTINC0 is to increment the FSR0 register. The POSTINC0 register combines ‘*ptr; ptr++’ into one operation. Another version of the assembly code for strcnt is shown below: strcnt clrf i ;; clear i movff ptr,FSR0L ;; set FSR low byte movff ptr+1,FSR0H ;; set FSR high byte strcnt_loop: movf POSTINC0,w ;; get current char ;; and increment FSR0 bz strcnt_exit ;; exit if zero incf i,f ;; increment char count bra strcnt_loop strcnt_exit return Here, the instruction ‘movf INDF0,w’ is replaced by ‘movf POSTINC0,w’; this reads the character and also increments FSR0 as the same time. This removes the need to increment FSR0 later in the loop. Remember that FSRn contains the value of a pointer (i.e., ptr), and INDFn is used to access what the pointer is referencing (i.e., *ptr). To increment a pointer (ptr++), either use the high and low bytes of the FSRn register (FSRnL, FSRnH) or use the POSTINCn register. The POSTINCn register references what the pointer is referencing, and increments the pointer after the reference, so it combines the two operations ‘*ptr; ptr++’ into one operation. 5—7 Experiment 5: Beyond Assembly Language Summer 2004/V0.2 Other registers similar to POSTINCn are: PREINCn - does ptr++; *ptr POSTDECn - does *ptr; ptr--; PLUSWn - does *(ptr+wreg) The POSTINCn, PREINCn, POSTDECn are useful for implementing software stacks or stepping linearly through data. The last form, PLUSWn, is useful for implementing C arrays, where ptr[4] is the same as *(ptr+4). 5—8 Summer 2004/V0.2 Experiment 5: Beyond Assembly Language B. Lab Activity Table 5–2: Indirect Addressing Task Checkpoint 1. Comments/Debugging Look at the table below, and find the C program attached to this lab that you are to implement in PIC assembly language. Use the strcnt.asm program attached to the lab as a template for implementing this code. Use the init_s1, init_s2 subroutines to copy the s1, s2 strings from program memory to data memory. Each program has a printf statement in it to illustrate how the s1, s2 strings are affected during execution. Do not implement this statement; use the File Registers window to determine how the strings are altered when testing the assembly code. In all of these programs, assume that s1, s2 are the same length and 16 characters or less. Table 5–3: C Program Assignments If the last digit of your student ID is... C program, parameter block location 0 or 1 strdcase.c; copies s2 to s1, down cases all letters. Use 0x54 for the location of the dostr parameter block (ptr1, ptr2). 2 or 3 strflip.c; copies s1 to s2, reversing the case of all letters. Use 0x58 for the location of the dostr parameter block (ptr1, ptr2). 4,5, or 6 strup.c; exchange s1 and s2, up casing all chars in the new s2. Use 0x5C for the location of the dostr parameter block (ptr1, ptr2). 7, 8 or 9 strxchg.c; exchange s1 and s2, reversing the case of all chars in the new s1. Use 0x60 for the location of the dostr parameter block (ptr1, ptr2). ASCII data manipulation is used to illustrate indirect addressing because it is easy to observe the effect of program execution on the resulting strings. The amount of ASCII data manipulation a microcontroller 5—9 Experiment 5: Beyond Assembly Language Summer 2004/V0.2 performs is very dependent on the application and can vary from none to a substantial amount (typically in the form of a debug monitor that communicates with an external terminal via a serial link). Indirect addressing is useful for any PIC microcontroller application, regardless of the amount of ASCII data manipulation required. DEMONSTRATE YOUR PIC ASSEMBLY PROGRAM OF THE ASSIGNED C TASK. BE PREPARED TO CHANGE THE VALUES OF STRINGS S1, S2. Table 5–4: C compilation checkoff Checkpoint Comments/Debugging 1. Compile the file cstrcnt.c to PIC18 assembly language following the instructions below. Simulate the program and single step it through it to understand the structure of the resulting assembly language. The file cstrcnt.c must be saved on your ‘unixhome’ drive that is accessible from the yavin.ece.msstate.edu machine. 2. Modify the C program assigned in Table 5–3 so that it can be compiled to PIC assembly language. Be sure to remove the printf statement. Complete Table 5–5 based on the assembly code produced by C compilation. The include, define, and __config statements at the top of cstrcnt.c must be included in a C program for the compilation procedure to succeed. Simulate the compiled code and verify that it performs the correct function. Compiling C programs to PIC18 machine code The file cstrcnt.c is a version of strcnt.c that is compatible with the PICC18 C-compiler. The differences between the two files are: 1. The cstrcnt.c has some includes, defines, and __config statements before the C code begins. The defines and __config statements defines PIC startup 5 — 10 Summer 2004/V0.2 Experiment 5: Beyond Assembly Language options needed when the code is programmed into the PIC. 2. The main program ends in an infinite loop. This is because there is no place for the main program to exit to when the code is finished. 3. To compile cstrcnt.c, save this file to a directory under your unixhome mounted drive (if you are using your portable PC, see the class web site for instructions on how to mount this directory on your PC, which must be connected to the network via a wireless card or hard connection). Use either putty or SSH (secure shell) to open a terminal window to yavin.ece.msstate.edu. This machine runs Linux, see the class website for a quick UNIX primer. Once you have logged into yavin, execute the command: “swsetup hitech”. This places the PIC18 compiler on your executable search path. Change to the directory (use the ‘cd’ command) that contains cstrcnt.c - verify that you are in the correct directory by listing the files in the directory (use the ‘ls’ command). To compile cstrcnt.c do: picc18 -O -18F242 cstrcnt.c The ‘-O’ (capital letter O) is the optimization option; it instructs the C compiler to optimize the assembly code. The resulting code will contain fewer bytes and execute faster than code compiled without this option. The ‘-18F242’ option designates the target processor; the 18F242 is the flavor of PIC18 that is used in the hardware labs. The output file produced is cstrcnt.hex which is an ASCII hex representation of the machine code. Execute the command: 5 — 11 Experiment 5: Beyond Assembly Language Summer 2004/V0.2 unix2dos cstrcnt.hex to convert this file into a format readable by MPLAB. Import the hex file into MPLAB by doing “‘File →Import”. If the error “end of file has been reached unexpectedly” is displayed, then you forgot to execute the ‘unix2dos’ command. Another useful compile option is: picc18 -O -18F242 -Mmap.txt cstrcnt.c The ‘-Mmap.txt’ option creates a map file called map.txt. The map file contains a listing of all symbols in the program and their mapping to memory locations. For example, the symbol _main in the map.txt file is the location of the entry point for main() in program memory. The symbol _s1 in the map.txt file is the location of the string s1 in data memory. The ‘-s’ compile option shown below: picc18 -O -18F242 -s cstrcnt.c produces an assembly language source file named ‘cstrcnt.s’ instead of a hex file. This is useful for determining how C language statements are translated to PIC18 assembly. Simulating cstrcnt.c 5 — 12 Compile the cstrcnt.c program; produce a map file and hex file. Use the map file to determine the locations for the s1, s2 strings in data memory, and the location of main in program memory. Within MPLAB, import the cstrcnt.hex file into memory. Use the “Opcode Hex” button in the program window to see a hex version of the program window; from this you can determine where the s1 and s2 strings are stored in program memory. Use the “Symbolic” button in the Program Memory window to see the most readable version of the disassembled code. Use the simulator and single step through the first few instructions. Have both the Summer 2004/V0.2 Experiment 5: Beyond Assembly Language File Registers and Special Function Registers windows open. Use the F8 key to skip over the first two call instructions (this code is still executed, but the F8 key will cause you to skip over these instructions instead of single stepping through them). These two call instructions execute initialization code; the second call executes code that copies the s1, s2 strings from program memory to data memory. After executing the second call, use the File Registers window and determine what memory was modified. Verify that these data locations match what is specified for the s1, s2 strings in the map file. At this point, follow the program execution through the C code source window and the assembly code in the Program Memory window. Modify your assigned C program so that it is compatible with the picc18 compiler. Compile the program and produce both hex and map files. Use the simulator to single step through the program and complete the table below. Compiling, Simulating your C program Table 5–5: Variable, Code Locations Variable or Code Label Location (in HEX) s1 string (in program memory) s1 string (in data memory) s2 string (in program memory) s2 string (in data memory) main entry point dostr entry point ptr1 ptr2 5 — 13 Experiment 5: Beyond Assembly Language Summer 2004/V0.2 DEMONSTRATE YOUR COMPILED C PROGRAM AND BE READY TO DISCUSS YOUR VARIABLE AND CODE LOCATIONS WITH THE TA. C. Report This is a formal lab report; be sure to follow the formatting guidelines posted on the lab web site. 1. Include the lst files for all assembly language programs and any C source code. Comment your assembly language programs very well; at least one comment every other line (points will be deducted if your assembly programs are not well commented). 2. Include the results of Table 5–5 in your report Formal Report Questions The following questions refer to the non-PIC microcontroller you are assigned via the lab web site. 3. What is the width of the instruction word? 4. What is the width of the internal data registers? 5. What is the width of the program counter or instruction pointer? 6. How much on-chip RAM does the processor have? (RAM = Random Access Memory, memory that the processor can modify, equivalent to the register file on the PIC). 7. Can the µP access external memory (memory that does not reside on the same chip). If ‘yes’, what is the maximum amount? 8. Does the µP have special instructions for signed comparisons? If ‘yes’, give an example. 9. Does the µP have any special instructions for multiply/divide? If ‘yes’, give an example. 5 — 14 Summer 2004/V0.2 Experiment 5: Beyond Assembly Language 10.Does the µP have a fixed sized stack? If ‘yes’, what is the size? 11. Can the µP write to the stack under program control? If ‘yes’, give an example on an instruction that does this. 12. How many clock cycles does it take for an add operation to execute? 13. How does the µP accomplish indirect addressing? Give an example. 14. Give the machine code format for an add of two register values (you pick the registers). 15. What flags are affected in the status register of the µP by the add instruction? Give the definition of each flag. 16. For the shift/rotate instructions, can multiple positions be shifted via one instruction? If yes, how many clocks does it take for a multiple position shift? 5 — 15 Experiment 5: Beyond Assembly Language 5 — 16 Summer 2004/V0.2 Summer 2004/V0.2 E x p e r i m e n t Experiment 6: Bringing the PIC to Life 6 Bringing the PIC to Life This lab makes your PIC 18F242 come alive. You will feel what Dr. Frankenstein felt when his creation took its first breath. OK...maybe not. But you will breath a sigh of relief when an LED turns on under PIC control. Summary: Hook up power, reset, and the RS232 serial port for your PIC. Verify functionality via the ledflash program. Verify that you can program your PIC using a serial bootloader. Measure the current consumption the PIC while in normal mode and sleep mode. 6—1 Experiment 6: Bringing the PIC to Life Summer 2004/V0.2 A. Prelab Requirements Table 6–1: Prelab Checkoff Do This 1. Comments Wire all connections shown in the schematic. You will not receive prelab credit unless your protoboard is fully wired before lab (the headerto-modular connector will be wire wrapped during the lab period). Do not have your PIC plugged into your board until you have verified that the output of the voltage regulator is 5V. Use the PIC 18F242 datasheet and the Prototyping Hints appendix for more information on the parts. WARNING: Only the wiring necessary to complete this lab may be on your protoboard. This is to prevent you from using a completed protoboard from a previous semester, which would give you an unfair advantage over your fellow students. It would also bypass one of the principle educational tenets of this lab - how to bring a microcontroller system to life from scratch. Figure 6.1 Wall Xfmr If there are multiple VDD/VSS pins on your PIC, hook them all up!!! Fuse Pic Startup Schematic Note polarity of LED!! Should turn on when reset button is pressed. 10K ohm 7805 Pwr Conn 18F242 5V 9V 1.0µ + Vdd Vss 470 ohm Power on LED 15 pf Osc1 Crystal Osc2 15 pf RB1 470 ohm 6—2 Vpp/ Mclr Reset Switch Summer 2004/V0.2 Experiment 6: Bringing the PIC to Life Table 6–2: Parts List Part Comments 1. PIC18F242 28-pin Dual Inline Package (DIP) 2. 7.3728 MHz Crystal 2-pin Metal package 3. Power connector (plug) 3-pin connector, has circular jack in middle 4. 7805 Power regulator three pin package, has metal heat sink 5. push button switch 4-pin package, small square push button 6. 3 LEDs Choose a color, any color 7. 1.0 µf Capacitor or 0.1µf capacitors (at least 6) Will be 1.0 µf if your part kit has a MAXIM 232 transceiver; will be 0.1 µf if your part kit has a MAXIM 202 transceiver. Note that the capacitors you have in the parts kit are polarized, the + terminal is the longer lead, the ‘-’ terminal is the shorter lead. 8. 15 pF Capacitors (2) To be used with the crystal to create the clock for the PIC; these capacitors are non-polarized so it does not matter how you plug them in. 9. 5 pin header Will use wire wrap to connect this to pins of the external modular connector for the RS232 serial port connection 10. DC Wall Transformer Be sure to use the one supplied in your parts kit. If you use a different one, verify the polarity and voltage value. 11. 470 ohm resistor pack 10-pin Single Inline Package (SIP), contains 5 resistors 12. 10K ohm resistor pack 10-pin SIP, contains 5 resistors. 13. MAX232 or MAX202 RS232 transceiver 16-pin DIP 14. DB9 connector 15. In-line PCB Fuse Two-lead printed circuit board slow-blow fuse 6—3 Experiment 6: Bringing the PIC to Life Summer 2004/V0.2 B. Lab Activity Table 6–3: Initial Hookup Checkoff Checkpoint 1. Debugging Before hooking up the PIC, plug the wall transformer into the power connector and use the multimeter to verify that the output of the 7805 voltage regulator is 5V. Use the scope to check the voltage level, and also verify that power supply ripple is within acceptable limits (+/300 mV or so). Use the picture in the ‘Prototyping Tips’ appendix to discover the proper orientation of the parts. Verify that the back pin of the power connector has +9 Volts (V). Verify that the pin from the power switch to the 7805 switches from +9 V to floating when switched. The ‘input’ pin of the 7805 is on the left side when viewed from the front (the writing on the 7085 is visible). The output is on the right hand side, and the middle pin is connected to ground. You will need to solder wires on to the power connecter, then use these wires to connect to the protoboard. 2. Verify that the power LED turns on when power is switched on. The short pin of an LED is the cathode and is connected to ground. 3. Use the scope and verify that a sinusoidal waveform is present on the OSC1 pin of the PIC. Verify the capacitor and crystal connections as shown in Figure 6.1 . 4. Verify that the reset LED turns on when the reset button is pushed. Use the multimeter to determine which two pins of the push button switch are connected when the button is pushed. The resistance across these two pins is zero when the button is pushed. 5. Give your PIC to the TA, and have the TA program the PIC with the ledflash program. Plug the PIC back in the protoboard, and the LED attached to port RB1 should flash. If the LED does not flash, disconnect the LED from RB1, and use the oscilloscope to check the output waveform on the RB1 pin. The waveform should be a square wave with a frequency of less than 1 Hz. If there is no waveform, ask the TA for assistance. If there is a waveform, then the LED incorrectly connected. DEMONSTRATE THAT THE LEDFLASH PROGRAM IS WORKING CORRECTLY. HAVE THE OSCILLOSCOPE DISPLAYING THE OSCILLATOR OUTPUT WAVEFORM THAT IS PROVIDING THE CLOCK FOR THE 6—4 PIC. Summer 2004/V0.2 Experiment 6: Bringing the PIC to Life Table 6–4: RS232 Serial Port Hookup Checkpoint 1. Make the connections for the RS232 serial port as shown in Figure 6.2 . You will need to use wirewrap for the connections between the 5-pin header and the DB9 connector. See Appendix A for tips on wire-wrapping; a wirewrap tool is available from the TA. 2. Have the TA program your PIC with the sercomm program. Open a Hyperterminal window (found under Programs → Accessories → Communications). After typing in a name for the session, select port COM1 with baud rate = 19200, 8 data bits, 1 stop bit, and flow control = NONE. Type a character, the PIC should echo back the next ASCII character in the sequence (‘a’ echoed as ‘b’, ‘P’ as ‘Q’, etc.). Debugging The MAX232/MAX202 provides 5 V conversion to the +/- 10 V voltage levels required by RS-232 via external capacitors (not shown in the schematic below). Use the MAX232/MAX202 datasheet and connect all capacitors shown (your parts kit will have 1.0 µF capacitors if using a MAX232, else the capacitors will be 0.1 µF if using the MAX202). Be careful of the polarity of the capacitors. The MAX232/ MAX202 provides two sets of drivers/ receivers; it does not matter which set is used. However, you must be careful to use the RIN/ROUT pins that are connected to the same buffer (ditto for the TIN/Tout pins). The pinouts of the MAX232 vs. the MAX202 are the same; the only difference is the value of the external capacitors and the total current consumption of the part. This program waits for a value to be ready from the RXREG (typed from keyboard), increments this value, then echoes this character back to the TXREG of the serial port (character will be displayed in Hyperterm). For detailed debugging steps, see the next section. 6—5 Experiment 6: Bringing the PIC to Life Summer 2004/V0.2 Figure 6.2 18F242 RS232 Serial Port Schematic MAX232/MAX202 Rout RC7/RX/DT 5 pin header TX Rin DB9 Female Pin 3 Gnd Pin 5 Tin RC6/TX/CK Tout RX Pin 2 Header to DB9 connections are wire-wrapped Figure 6.3 DB9 Connector Pinout Front view: (looking into connector, pins facing up) 6 7 8 9 DB9 Female 1 2 3 4 5 4 5 Top view: (looking down on pins) 1 2 3 DB9 Female 6 Which pins are Tx and Rx? 6—6 7 8 9 To determine if pin 2 (RX) and pin 3 (TX) are identified correctly, plug the DB-9 female connector into a Summer 2004/V0.2 Experiment 6: Bringing the PIC to Life cable connected to the serial port on the laboratory PC. Measuring the voltage between ground (pin 5) and TX (pin 3, DB9) should produce a value of at least -8 V. The RX (pin 2, DB9) is an input and will either be floating (multimeter display fluctuating) or close to ground. The following debugging steps require use of the single trigger mode of the scope that allows a waveform to be captured once a falling or rising edge is seen. See Appendix B, steps 19-25 for information on how to place the scope in this mode. If the sercomm program does not work (no characters appear or garbled characters appear), try the following debugging steps in order: Detailed RS232 Serial Port Debugging • Verify that there is approximately +/- 10V on the pins indicated in the MAX232/MAX202 datasheet. This indicates that the capacitors are placed correctly. • Verify the correct hyperterm settings of 19200 baud, no flow control. If garbled characters appear, this means that the baud rate is set wrong. • Determine if the typed character is reaching the DB9 by placing the scope input on the TX pin of the 5-pin header, and use Single trigger mode, rising edge triggered. The voltage level on the TX pin of the DB9 should be approximately -8V when the line is idle. Type a key on the keyboard, this should cause the scope to trigger and capture the serial waveform of the received character. If this does not happen, then either the scope is configured wrong, or the header pin is not connected to the TX pin of the DB9. Move the scope input to the RIN pin of the MAX202/232 and verify that the same character is being received at that point (if it is not, then you have a wiring error between the header and MAX232/202). 6—7 Experiment 6: Bringing the PIC to Life Summer 2004/V0.2 • Determine if the typed character is reaching the PIC by placing the scope input on the ROUT pin of the MAX232/202, and use Single trigger mode, falling edge triggered (note that this triggering is the reverse of the previous step). This voltage level should be at +5V when the line is idle. Type a key on the keyboard; this should cause the scope to trigger and capture the serial waveform of the received character. If this does not happen, then either power is incorrectly applied to the MAX232/202 part, or you have used a ROUT pin that is not associated with the RIN pin that you verified in the previous step. If you capture a character at this point, then place the scope input on the RX pin of the PIC and verify that the same character can be captured at the PIC (if no character is seen, then check your wiring). • Determine if the received character is being transmitted by the PIC by placing the scope input on the PIC TX pin, and use Single trigger mode, falling edge triggered. This voltage level should be at +5V when the line is idle. Type a key on the keyboard, this should cause the scope to trigger and capture the serial waveform of the transmitted character. If this does not happen, then the PIC is either not receiving the character in the first place (check the previous step), the PIC was programed with the incorrect program (not sercomm), or the PIC is inoperative (check the clock waveform on the OSC1 pin, voltage level of the board). If you capture a serial character on the TX pin of the PIC, then move the scope trace to the Tin pin of the MAX 232/202, and verify that the same character is being received at that pin. • Determine if the transmitted character is flowing through the MAX202/232 by placing the scope input on the Tout pin of the MAX202/232, and use 6—8 Summer 2004/V0.2 Experiment 6: Bringing the PIC to Life Single trigger mode, rising edge triggered. This voltage level should be at approximately -8V when the line is idle. Type a key on the keyboard, this should cause the scope to trigger and capture the serial waveform of the transmitted character. If this does not happen, then the Tout pin being used is not associated with the Tin pin used in the previous step. After verifying that a character is being transmitted, move the scope input to the RX pin on the 5-pin header and verify that the transmitted character is present at that point. If you have done all of the above debugging steps and the sercomm program is still not executing correctly, then seek TA assistance. After you have verified the sercomm program, proceed to the next step of using the PIC18 bootloader program. What is next? 6—9 Experiment 6: Bringing the PIC to Life Summer 2004/V0.2 Table 6–5: PIC18 Bootloader Checkpoint Debugging 1. Use the PIC18 C compiler, and produce a hex file for the sercomm.c program listed on the files link for this lab. Follow the procedure given in the previous lab for using the PIC18 C compiler. 2. Go to the ECE 3724 lab page, and follow the Bootloader Instruction Link for information on using the PIC18 bootloader. The PIC18 bootloader is installed on the micro lab PCs; you may want to test your board with this bootloader before attempting to install the bootloader on your portable PC. Program your PIC18 with the sercomm.hex file using the PIC18 serial bootloader. However, you do eventually want to verify that you can operate the PIC bootloader via your portable PC as this will allow you to work on lab exercises at home. When using the bootloader, there is a 2 second delay after power up or reset before the bootloader begins executing the resident program - wait for this time period before entering any input to the PIC. WARNING: The best way to use the bootloader is to turn off power to the PIC, press ‘PROGRAM’ in the bootloader interface, then restore power to the PIC. This ENSURES that the bootloader firmware in the PIC has a chance to connect to the PC. DEMONSTRATE TO THE TA THE PROGRAMMING OF THE SERCOMM.HEX FILE USING THE PIC18 BOOTLOADER, AND THE OPERATION OF THE SERCOMM PROGRAM. HAVE THE SCOPE INPUT ON THE TX PIN OF THE PIC, AND THE SCOPE SET IN SINGLE CAPTURE MODE, FALLING EDGE TRIGGER. DEMONSTRATE THAT YOU CAN CAPTURE AND DISPLAY THE SERIAL 6 — 10 Summer 2004/V0.2 Experiment 6: Bringing the PIC to Life WAVEFORM OF THE CHARACTER BEING TRANSMITTED BY THE PIC. Table 6–6: Current Measurement of the PIC18 Checkpoint Debug 1. Compile the pertest.c program and program it into the PIC18. Verify its operation by opening a hyperterm window with 19200 baud rate, no flow control. You will be presented with a menu choice of three items after reset is pressed. 2. Hook a multimeter in series with your power supply to monitor the TOTAL current being drawn by your board. To monitor the total current, place the multimeter in series between the 7805 voltage regulator and the power connector. Be sure to use the mA and common terminals of the multimeter, and choose the Dc/mA function. 3. Fill in the current measurements in the table below. To measure the current draw of the power LED, determine the different in current draw when the power LED is inserted in the circuit, and when it is removed. To calculate the expected current draw, use the equation I = V/R; where V= (VDD - 0.7V) and R = 470 ohms To measure the current draw of the MAX232/202, determine the difference in current draw when power is connected to the MAX232/202 and when it is disconnected. Determine the expected value from the datasheet value for VCC power supply current. To determine the current draw of the PIC in normal operation, place the PIC in sleep mode via the menu choice and record the difference in total current draw. Determine the expected value for PIC normal mode operation using the Typical IDD vs. FOSC over VDD (HS/PLL mode) in the PIC18 datasheet. The expected total current draw of your board is the sum of the expected current draw of the individual components. 6 — 11 Experiment 6: Bringing the PIC to Life Summer 2004/V0.2 Table 6–6: Current Measurement of the PIC18 Checkpoint 4. In the PIC bootloader, reload the pertest.hex file, but change the PIC configuration bits by selecting EDIT Config, and change the bits to match below (ensure HS option is chosen, LVP option is unchecked, BODEN is unchecked). Turn the PIC off, choose Program Config, then turn power back on to the PIC to allow the programing to finish. Then cycle power on the PIC for the new configuration bits to take effect. Re-measure the total power consumption of your board, and the power consumption of the PIC18. 6 — 12 Debug The HS option disables the PLL circuit, so the PIC will run 4 times SLOWER than previously (the HSPLL option causes the crystal frequency to be multiplied by 4X internally to the PIC via a phase-lockedloop circuit). The Hyperterminal baud rate must now be set at 4800 baud. Measure the total board current draw and the PIC current draw as previously. The expected PIC18 current draw can be found in the typical IDD vs. Fosc over VDD (HS mode) graph in the PIC18 datasheet. Summer 2004/V0.2 Experiment 6: Bringing the PIC to Life Record your measurements in the following table. Table 6–7: Current Measurements Measurement 1. MAX202/232 2. Power LED 3. PIC18 (normal, HS/PLL) 4. Total Power (HS/PLL) 5. PIC18 (normal,HS) 6. Total Power (HS) Expected Actual %diff (ActualExpected)/ Expected*100 After the last measurements have been taken, re-program the configuration bits so that the HSPLL option is chosen. Failure to do this will result in your PIC running 4X slower than it should (you can also get the TA to reprogram your PIC with the original bootloader hex file to turn the HSPLL option back on). When configuration bits are changed, the PIC must be powered on and off for the changes to take effect. HAVE THE TA INSPECT YOUR CURRENT MEASUREMENTS. DEMONSTRATE TO THE TA HOW YOU OBTAINED THE MEASUREMENT FOR THE PIC18 IN NORMAL MODE, USING THE HS CRYSTAL OPTION. 6 — 13 Experiment 6: Bringing the PIC to Life Summer 2004/V0.2 C. Optional In-Circuit Programming Connection Figure 6.4 below shows an optional in-circuit programming connection that can be connected; this is an alternative to using the serial port and the bootloader and requires the use of the ICD2 programmer (blue hockey puck). This schematic is provided for reference purposes only; you DO NOT have to implement this interface. Figure 6.4 In-Circuit Programming Schematic Note polarity of LED!! Should turn on when reset button is pressed. 10K ohm 16F873 1.0µ + Vdd OPTIONAL In-circuit programming connection Vpp/Mclr Vpp/ Mclr Vss Vdd Reset Switch Vss 1 2 3 4 5 RB7/ PGD RB6/ PGC RB7/ PGD RB6/ PGC Use 5-pin header for ISP connector. The ordering of the pins is up to you, but the picture in the prototyping appendix has 1-to-5, right to left. The 6-pin modular jack is available from Digikey, part number A9084-ND. 6 — 14 Summer 2004/V0.2 Experiment 6: Bringing the PIC to Life D. Report 1. In the pertest.c program, explain why the value for ‘reset cnt’ increments steadily each time the reset button is pushed. What happens to the ‘reset cnt’ value when power is turned off/on? Why? What bit/register of the PIC18 is being checked by the pertest.c code to change this ‘reset cnt’ value? 2. For the pertest.c program, when option #3 is chosen (enable watchdog timer and sleep), the following sequence of events occur: a) user types ‘3’, b) after a pause, the menu is re-displayed, c) after another pause, the message ‘Watchdog timer reset has occurred’ is displayed, followed by the menu being displayed again. Clearly explain why this sequence of events occurs from your reading of the pertest.c code, and your knowledge of the watchdog timer and sleep mode operations. 6 — 15 Experiment 6: Bringing the PIC to Life 6 — 16 Summer 2004/V0.2 Summer 2004/V0.2 E x p e r i m e n t Experiment 7: Serial versus Parallel 7 Serial versus Parallel The nights of laying awake at night wondering about that 9-pin connector on the back of your PC are over! Rejoice! ....WhaTha? No sleepless nights? Curious or not, prepare to be initiated into the mysteries of the 3-wire serial interface known as RS-232. Summary: Write programs that: a) that reads an external switch and controls an LED, b) uses the PIC parallel port to test a 74XX device, c) queries the serial port for status information. 7—1 Experiment 7: Serial versus Parallel A. Summer 2004/V0.2 Prelab Requirements Table 7–1: Prelab Checkoff Do This Comments 1. Make a good faith effort at writing the ledswitch.c program specified in Table 7–2 , and demo to the TA that it compiles without syntax errors. To save time in lab, you should make an attempt to write all programs required by the lab before entering the lab so that lab time can be spent debugging the programs. 2. Draw the RS232 waveform for an 8-bit data value, 1 start, 1 stop bit, LSB sent first. The 8-bit data value is based on the last digit of your Student ID as follows: 0) ‘e’, 1) ‘F’, 2) ‘n’, 3) ‘S’, 4) ‘3’, 5) ‘Z’, 6) ‘z’, 7) ‘#’, 8) ‘u’, 9) ‘p’. Use an ASCII table to determine the 7-bit value of your character (the 8th bit is zero). 3. Demo to the TA an Excel spreadsheet that calculates the bit time in microseconds for any baud rate from 2400 to 115200. Recall that a bit time is equal to one over the baud rate, and that a microsecond is 10-6 seconds. 4. Demo to the TA an Excel spreadsheet that calculates the value to be written to the SPBRG register given an oscillator frequency value, a target baud rate, and either high speed or low speed baud rate mode. The PIC18 datasheet section titled USART Baud Rate Generator should prove helpful. 7—2 Summer 2004/V0.2 Experiment 7: Serial versus Parallel B. Lab Activity Table 7–2: ledswitch Program If the last digit of your Student ID is... Write a program called ledswitch.c to do: 0 or 5 Input push button is on RB2; LED flashes three times while the push button is held down, then freezes off. When the pushbutton is released, the LED freezes ON. LED is on port RB1. 1 or 6 Input push button is on RB2; LED flashes twice while the push button is held down, and freezes off. LED flashes once when the pushbutton is released, and freezes off. LED is on port RB1. 2 or 7 Input push button is on RB4, LED is initially ON. A press AND release of the button starts the LED flashing SLOWLY; a subsequent press AND release changes the blink speed of the LED to a noticeably faster rate. Each subsequent pushbutton press and release changes the LED blink speed between slow and fast. The LED is on port RB1. 3 or 8 Input push button is on RB4; LED flashes rapidly while the push button held down, LED flashes three times slowly when the push button is released, then freezes off. LED is on port RB1. 4 or 9 Input push button is on RB5; a press and release of the pushbutton causes the LED to blink twice fast, then once slowly, and freeze off. A subsequent press and release starts the LED flashing rapidly. Each press and release changes between these two sequences. LED is on port RB1. The input pushbutton switch MUST BE configured as a low true switch (i.,e produce a low voltage when the button is pressed). Use a 10K pullup resistor to provide the high voltage. DEMONSTRATE THE LEDSWITCH.C PROGRAM. 7—3 Experiment 7: Serial versus Parallel Summer 2004/V0.2 Table 7–3: USART Error Checking Checkpoint 1. 2. Debugging In the sercomm program from the previous lab, the getch subroutine waits for a character to be ready in the TXREG. Modify this subroutine to detect a framing error by checking the FERR bit in the USART status register (RCSTA register). Turn on an LED when an error is detected. The LED should be off after reset. Use the following output port for your error status LED based on the last digit of your student id: RB1 (0 or 1), RB2 (2 or 3), RB3 (4 or 5), RB4 (6 or 7), RB5 (8 or 9). Change the baud rate from 19200 baud in Hyperterminal and verify that a framing error condition is produced. Verify that you are checking the correct bit in the RCSTA register. Framing errors occur when the stop bit is detected as clear, which occurs when the actual baud rate is lower than the expected baud rate. IMPORTANT!!! You must check the RCSTA register for the framing error BEFORE reading the RCREG. Reading the RCREG changes the value of the framing error bit to the next character in the input FIFO. USE THE SCOPE IN SINGLE TRIGGER CAPTURE MODE TO CAPTURE THE CHARACTER APPEARING ON THE RX PIN OF THE PIC. DEMONSTRATE THAT THE CHARACTER WAVEFORM YOU CAPTURE MATCHES THE WAVEFORM FOR THE CHARACTER YOU WERE ASSIGNED IN PRELAB. DEMONSTRATE THAT YOUR PROGRAM DETECTS A FRAMING ERROR CONDITION. 7—4 Summer 2004/V0.2 Experiment 7: Serial versus Parallel Table 7–4: Checkpoint 1. 2. Connect a 74XX gate as shown in the schematic below. Use the one provided in your part kit. You can use any pins on port RB from 1 to 5 except the pin used for your framing error LED. Each 74XX package has four gates, it does not matter which gate is used. Write a program called gatetest.c that applies all four combinations of gate inputs to the 74XX gate and checks if the output value is correct. Print a message indicating success or fail of the test. Be sure that you understand how your 74XX gate function works. Test it independently before testing it with your program. Your serial port must be configured with the baud rate given on the right. 3. Debugging DO NOT USE PIN RB0. This requires some extra configuration for correct operation. Based on the last digit of your Student ID, use the following baud rate for your RS232 interface: 0,1 or 2: 38400; 3, 4 or 5: 57600; 6 or 7: 9600; 8 or 9: 115,200. Try disconnecting an input or the output and verifying that the test fails. 18F242 74xx RB? RB? RB? 7400 NAND 7402 NOR 7408 AND 7432 OR 7486 XOR Figure 7.1 74XX gate connection to 18F242 Use the C function printf to send strings to the serial port. The following: Formatted IO via printf 7—5 Experiment 7: Serial versus Parallel Summer 2004/V0.2 printf (“Hello World”); will send the string “Hello World” to the Hyperterminal window. The following should print the same string followed by a new line (carriage return, line feed): printf (“Hello World\n”); For some reason, the new line (‘\n’) is not recognized by Hyperterminal, so use: putch(0x0a);putch(0x0d); This sends the ASCII codes for a newline followed by a carriage return. Put this in a subroutine called pcrlf as it is a common operation. gatetest Program Operation Output from the gatetest program should appear something like the following: Hit any key to begin test... Gate Passed! Hit any key to begin test... Gate Failed! Hit any key to begin test... Use the getch subroutine to wait for the user to type a key to begin a test; test the gate; indicate pass or fail; then loop to start. DEMONSTRATE YOUR GATETEST PROGRAM. SHOW BOTH SUCCESS AND FAIL CASES. 7—6 Summer 2004/V0.2 Experiment 7: Serial versus Parallel C. Report 1. Include source code listings of any C programs. 2. Include all pre-lab material; include a screen shot of your Excel spreadsheet operation. 3. Discuss what problems can occur if a pushbutton switch is connected as shown below. 4. The error tolerance for bit time mismatch between receiver and transmitter in RS232 over 10 bits is 5%. For a crystal frequency of 7.3728 MHz, and a PIC oscillator option of HSPLL, what is the MAXIMUM value that can be written to the SPBRG for a baud rate of 19200 that will still be within this error tolerance? 18F242 Pic Input Push button, momentary closure when pushed. 7—7 Experiment 7: Serial versus Parallel 7—8 Summer 2004/V0.2 Summer 2004/V0.2 E x p e r i m e n t Experiment 8: Interrupt-Driven IO 8 Interrupt-Driven IO Ahhh...how sweet life would be without interruptions; no need for alarm clock bashing, cussing at telephone solicitors, withering glares at students knocking on the door....<cough>. However, life in the microprocessor world would be tough without interrupts. How so? Read on, young grasshopper, and find enlightenment - or at least your next assignment. Summary: Given a program that uses interrupt-driven serial input, modify it to use a circular buffer for data storage. Also add error checking for buffer overrun and framing error, and a choice of multiple baud rates. 8—1 Experiment 8: Interrupt-Driven IO A. Summer 2004/V0.2 Prelab Requirements Table 8–1: Prelab Checkoff Do This Comments 1. Wire all connections shown in the schematic. You will not receive prelab credit unless your protoboard is fully wired before lab. Based on the last digit of your student ID, use the following two pins for the DIP switch: a) 0, 1, or 2 use RB5/RB4; b) 3 or 4 use RB4/RB3; c) 5 or 6 use RB3/RB2; d) 7, 8, or 9 use RB2/RB1. You may use any other ports from RB1 to RB5 for the framing and overrun error LEDs. 2. Give the expected bit time in microseconds for each baud rate selected by the DIP switch. Table 8–3 contains your assigned baud rates. DIP Switch 18F242 Baud Rate selection RB? RB? RB? 470 ohm RB? Framing error overrun 470 ohm Figure 8.1 Baud Rate Selection and Error Indication 8—2 Summer 2004/V0.2 Experiment 8: Interrupt-Driven IO B. Lab Activity The doroot program linked to this lab inputs a decimal number in ASCII format, computes the integer square root, and displays the result. The serial port is used for all I/O (115,200 baud is the default baud rate). This program uses an interrupt approach for serial input. When the USART receives a character, an interrupt is generated that causes the subroutine pic_isr to be called. This subroutine stores the received character in a memory location, and sets a flag (got_char) indicating an available character. The getch subroutine checks this flag instead of the RCIF bit to determine character availability. Note that the getch subroutine clears the got_char flag when it is called. Read this program and understand how the serial IO is performed (do not worry about understanding the operation of the sqroot subroutine). The doroot program is the starting point for your modifications. Create different versions of this program as you advance through the lab, so that a previous version can be used if an approach yields unsatisfactory results. Table 8–2: Baud Rate Selection/Error Detection Checkoff Checkpoint 1. Program your PIC with the doroot program and familiarize yourself with its operation. Type in one number at a time and verify that the integer square root is computed. Comments/Debugging Remember to set all of the correct options to the Hyperterminal program. When compiling doroot.c, use the ‘-lf’ compile option so that the floating point numbers print correctly. 8—3 Experiment 8: Interrupt-Driven IO Summer 2004/V0.2 Table 8–2: Baud Rate Selection/Error Detection Checkoff Checkpoint 2. Open the file test1.txt in Notepad, and select/copy a range of input values, and use the Hyperterminal ‘Edit → Paste-to-Host’ command to copy this selection into the terminal window. What happens when a large number of entries is pasted at a time? Comments/Debugging You should observe that the doroot program will operate correctly for a small number of entries pasted into the window, but not for a large number. The failure is due to simultaneously receiving characters during transmission of the result string. While characters are being transmitted, the receive port is not checked. At some point, the RCREG input FIFO buffer fills to capacity, and characters are lost. NOTE: When the Paste-to-Host command in Hyperterminal is used, each character is sent at the specified baud rate. However, there is considerable dead time between each character that is sent (why? Unknown, poor programming in Hyperterminal or other tasks in windows taking time). This explains why it takes more than the expected number of input characters to cause a buffer overrun problem. If you cannot get overrun to occur using your portable PC, try using the lab PC to communicate with your PIC. 3. 4. 8—4 Modify the doroot.c program to use the DIP switch to select between 4 different baud rates after reset. Enable the weak-pullup on the Port B pins. External pullups are not required for these inputs. Table 8–3 contains your assigned baud rates. Examine the serial_init() subroutine in the serial.c include file to understand how to pass in values for the SPBRG register and how to select between low and high speed mode. Use a multimeter to verify the close/open positions of the DIP switch. Test all four baud rates. Use an oscilloscope, and capture a character waveform. Be prepared to show the TA that the bit time of the captured waveform matches the expected bit time. Modify the pic_isr subroutine to turn on an LED when a framing error is detected. The RCSTA register that contains the FERR bit must be read BEFORE the RCREG. Once the error LED is turned on, leave it on. Test the program with mismatched baud rates to determine if a framing error can be detected (HINT: Hyperterminal must use a SLOWER baud rate than the PIC expects to generate a framing error). You may need to use the low speed mode to reach some of your assigned baud rates. Summer 2004/V0.2 Experiment 8: Interrupt-Driven IO Table 8–2: Baud Rate Selection/Error Detection Checkoff Checkpoint Comments/Debugging 5. Modify the pic_isr subroutine to turn on an LED if an overrun error occurs. This is not the same as the USART overrun error. This overrun error occurs if the pic_isr subroutine is called, and the got_char flag is already set, indicating that the previous character has not been read. If the got_char flag is already set when the pic_isr subroutine is called, then reading and storing the current transmitted character will overwrite the old character, causing it to be lost. Once the error LED is turned on, leave it on. After an overrun error, do not read RCREG. Test the program by pasting several numbers into the Hyperterminal window, causing buffer overrun. 6. Determine the relationship between baud rate and the number of pasted selections required to cause overrun. Record the minimum number of entries (within 3 or 4) needed to cause buffer overrun for 4800 and 115200 baud. Be prepared to discuss the ‘whys’ of the relationship between baud rate and the number of entries required for overrun with the TA. Table 8–3: Baud Rate Assignment If the last digit of your Student ID is... Use the following baud rates for your DIP switch (switch assignment is up to you) 0 or 1 4800, 19200, 57600, 115200 2 or 3 4800, 38400, 57600, 115200 4 or 5 4800, 9600, 38400, 115200 6 or 7 4800, 9600, 57600, 115200 8 or 9 4800, 19200, 38400, 115200 DEMONSTRATE YOUR BAUD RATE SELECTION AND ERROR DETECTION. CAPTURE A CHARACTER WAVEFORM AND USE THE OSCILLOSCOPE CURSORS TO MEASURE THE BIT TIME. COMPARE THIS BIT TIME TO THE EXPECTED BIT TIME. 8—5 Experiment 8: Interrupt-Driven IO 8—6 Summer 2004/V0.2 Summer 2004/V0.2 Experiment 8: Interrupt-Driven IO The doroot program is attempting two things at once: print a result while also receiving new input. The interrupt-driven input allows the PIC to interrupt the printing of the result to read an input character. However, the current implementation only has a single character location to store the incoming character. If the interrupt subroutine is called again before the current result is finished printing, a character is lost. The Overrun Problem To fix this problem, use more than one location to store incoming characters. A circular buffer (or circular FIFO) data structure is typically used for this. First, a set of locations is reserved for storing characters, such as: Fixing the Problem volatile bdata unsigned char ibuf[BSIZE]; The ibuf array is used to stored incoming characters. The bdata designator is used to allocate this storage in a bank other than the access bank of the PIC as allows changes to the buffer size without depleting the available access bank memory. The volatile designator informs that compiler that this will be used within an interrupt service routine, and thus can change at any time. The BSIZE define sets the buffer size; use a value of 16 initially. Two pointers, called the head and tail respectively, are used to store and retrieve values from the buffer. Storing/Retrieving values from a circular buffer volatile unsigned char head; volatile unsigned char tail; When a character is received, the head pointer is incremented, and the character stored at ibuf[head]. To retrieve a character from the buffer, increment the tail pointer, then read the character from ibuf[tail]. When a head/tail pointer is incremented, check if it is equal to 8—7 Experiment 8: Interrupt-Driven IO Summer 2004/V0.2 BSIZE; if yes, then set the value to 0. In this way, the head/tail pointer wraps around to location 0 in the buffer (hence the name, circular buffer). Empty, Not-empty, Full The initial values of the head and tail pointers are 0. If head == tail, then the buffer is empty. If head != tail, then characters are available in the buffer. Recall that when a character is placed into the buffer, the head pointer is incremented. After the head pointer is incremented (and wrapped to 0 if necessary), if head == tail, then the buffer is full (actually, by these definitions there is room for one more character, but call this the full condition to simplify buffer operation). Implementing a circular buffer for input storage allows an interrupt-driven input system to tolerate bursts of input activity without data loss. However, no amount of buffering can prevent data loss if the rate that data is placed into the buffer is faster than the rate that data is taken out of the buffer for an extended period of time. Table 8–4: Circular Buffer Checkoff Checkpoint 1. 2. 8—8 Comment/Debugging Create a new version of the doroot.c program that implements circular buffering. Use a buffer size of 16. Turn on the overrun error LED if the buffer full condition is detected. This requires modification of the getch and pic_isr subroutines. The getch subroutine waits until data is available, then removes one character from the buffer. The pic_isr subroutine places data into the buffer and performs error checking. Determine how circular buffering has changed the number of entries required to cause overrun. Use the baud rates that you recorded overrun values for previously. When determining the number of entries needed to cause overrun, exact values are not needed (+/- 5 entries is close enough) Start simple and test the program for manually typed input. Then test it using the Paste-To-Host feature of Hyperterminal. Do not forget to wrap the head and tail pointers to 0 if they are equal to the maximum buffer size after incrementing them. Summer 2004/V0.2 Experiment 8: Interrupt-Driven IO DEMONSTRATE YOUR PROGRAM VERSION THAT IMPLEMENTS CIRCULAR BUFFERING. DISCUSS THE OVERRUN BEHAVIOR BEFORE AND AFTER CIRCULAR BUFFERING FOR DIFFERENT BAUD RATES. C. Report 1. Include source code listings of any C programs. 2. Give the bit time for each of your assigned baud rates. 3. Discuss the overrun behavior before and after circular buffering for different baud rates. 4. The overrun condition that is being checked in this lab is different from the OERR bit (Overrun error bit) in the RCSTA register (UART status register). In the original doroot.c code (or any of the successive versions that you write), the OERR bit in the RCSTA register will NEVER be set. Why is this? What is the fundamental property of the doroot.c code that prevents the OERR bit from being set? 5. To generate a framing error, Hyperterminal must use a slower baud rate than what the PIC expects. Why is this so? Explain in detail, and draw a diagram to support your argument. 8—9 Experiment 8: Interrupt-Driven IO 8 — 10 Summer 2004/V0.2 Summer 2004/V0.2 E x p e r i m e n t Experiment 9: Memory and the I2C Bus 9 Memory and the I2C Bus Memory is a good thing! Why, without memory, microprocessors would have difficulty with many things, such as transforming into rouge AIs that take over the world, enslaving the human race for use as Duracell® batteries. And, without memory, where would you store your 65th level über Everquest van Shir Beastlord? Motivated? Not? Onwards anyway! Summary Explore the workings of the I2C bus via a serial EEPROM. Write a program that uses page write mode to store a file sent via the serial port into the EEPROM. Verify the file was saved by using sequential reads to display the contents of memory. 9—1 Experiment 9: Memory and the I2C Bus Summer 2004/V0.2 A. Prelab Requirements Table 9–1: Prelab Checkoff Do This Comments 1. Wire all connections shown in the schematic. You will not receive prelab credit unless your protoboard is fully wired before lab. Use the 10K resistor SIP for the pull-ups. These are required because the drivers on the SCL, SDA lines only have pulldown capability because multiple connections may be made to these lines. 2. Become familiar with the memblk.c program attached to this lab. This program uses subroutines from the i2cmsu.c file. Modifications to this program are required as part of this lab, so understanding the behavior of this program is essential to success. Refer to the 24LC511 datasheet for details on the read/write operations for this device. 3. Demo to the TA an Excel spreadsheet that will calculate the correct SSPADD value for a desired I2C bus speed. Use crystal frequency 7.3728 MHz, HSPLL mode. 18F242 Vdd Microchip 24LC515 10K RC3/SCK/SCL Vdd SCL Vdd A2 A1 10K RC4/SDI/SDA SDA A0 If you have trouble distinguishing which 8pin DIP in your parts kit is the 24LC515, look for the Microchip symbol on the package. The 10K pullups are very important!!! The I2C bus will not work without them. The WP pin on the 24LC515 can be left unconnected. Figure 9.1 PIC to Serial EEPROM connection 9—2 Summer 2004/V0.2 Experiment 9: Memory and the I2C Bus B. Lab Activity The memblk program performs either a page write or sequential read operation to the serial EEPROM. In write mode, a page of 64 bytes is captured from the serial port and written as one page to the EEPROM. In read mode, 64 bytes are read sequentially from the EEPROM and then displayed via the serial port. The serial EEPROM read/write functions and basic I2C functions are in the file i2cmsu.c. This file must be included as part of the project source files during compilation. Familiarize yourself with the available functions in the i2cmsu.c file. Table 9–2: Serial EEPROM Operation Checkoff Checkpoint Comments/Debugging 1. Verify that the memblk program operates correctly on your protoboard. Use the file test.txt and the ‘Paste-to-Host’ functionality of Hyperterminal to test the program with different groups of 64 characters. 2. Change the wiring of the A1/A0 pins to alter the address of the EEPROM. Modify the memblk program to use this new address. Use the following values for A1/A0 based on the last digit of your student ID: a) 0,1,2 use ‘01’; b) 3,4,5 use ‘10’; c) 6,7,8,9 use ‘11. Modify memblk to prompt the user to choose one of two different I2C bus rates. One rate is 500 KHz (or as close as you can achieve), and the other is specified on the right. Use the following I2C bus speeds based on the last digit of your student id: a) 0 or 1 (50 KHz), b) 2 or 3 (100 KHz), c) 4 or 5 (175 KHz), d) 6 or 7 (250 KHz), e) 8 or 9 (325 KHz). 3. The ‘#define ROM 0xA0’ statement in memblk.c must be changed to accommodate the new A1/ A0 values. Review the command byte formatting in the 24LC515 datasheet to determine the new value. Even though 500 KHz is above the maximum specification for the memory part, it should still work as datasheet specifications are very conservative. However, this is only being done for illustrative purposes. Never design a system that relies on a part working beyond its specified performance. 9—3 Experiment 9: Memory and the I2C Bus Summer 2004/V0.2 DEMONSTRATE THE OPERATION OF MEMBLK USING THE MODIFIED EEPROM ADDRESS WITH YOUR ASSIGNED I2C BUS SPEED. CAPTURE THE FIRST 5 BYTES OF A PAGE WRITE OR SEQUENTIAL READ VIA THE OSCILLOSCOPE AND EXPLAIN THE FORMATTING/ PURPOSE OF EACH BYTE TO THE TA. USE A PAGE WRITE IF THE LAST DIGIT OF YOUR STUDENT ID IS ODD, ELSE USE A SEQUENTIAL READ. ON THE SCOPE, HAVE BOTH SCL AND SDA DISPLAYED AND SHOW THAT YOU HAVE ACHIEVED THE SPECIFIED BUS SPEED. AFTER THIS, DEMONSTRATE OPERATION AT THE 500 KHZ BUS SPEED. Streaming writes Capture 64 bytes from serial port to buffer Page Write of 64 bytes Use two buffers 9—4 The memblk program captures 64 bytes from the serial port and uses a page write to save this to the EEPROM. What is needed to support the saving of a continuous stream of data from the serial port to the EEPROM? The problem with the operation on the left is that during the page write operation, more bytes are arriving via the serial port. These bytes must be buffered by the input interrupt service routine somewhere so that they are not lost during the page write. The solution to this problem is to use two buffers. When one buffer is being written to the EEPROM, the other buffer is used for storing data, and vice-versa. Summer 2004/V0.2 Experiment 9: Memory and the I2C Bus The flowchart below shows how to modify the interrupt service routine to use two buffers. Char arrival triggers interrupt 0 Interrupt Service Subroutine 1 Active buffer? Save char in buff0 no 64 bytes? Save char in buff1 no 64 bytes? yes yes Write_flag = 1 Write_flag = 1 exit interrupt service Note that two variables are used, active_buffer and write_flag. The active_buffer variable indicates the buffer used for incoming data. The write_flag variable is set when a buffer is full, requiring a page write to EEPROM. The flowchart below shows how to implement streaming IO using this two buffer scheme. The addr value is incremented by 64 each time a page write is performed. Because addr is a 16-bit integer, its value will wrap to zero once 64K bytes are written. Check for 9—5 Experiment 9: Memory and the I2C Bus Summer 2004/V0.2 addr == 0 (64K) after it is incremented by 64 and halt writing if true as memory is full at this point. Streaming Write Loop 0 Write_flag? Wait for interrupt service routine to fill a buffer. 1 0 Active buffer? 1 Active buffer = 1 Active buffer = 0 Page write buff0 Page write buff1 Write_flag = 0 addr = addr + 64 Checking for Overrun 9—6 An overrun check should be placed in the interrupt service routine. The condition of write_flag==1 when a buffer becomes full indicates that the previous write has not completed. However, overrun will not happen in this testing environment. At the maximum baud rate of 115200, it takes approximately 5.5 ms to send 64 bytes. Even though individual characters are sent at this rate, Hyperterminal has excessive dead time between characters, so a block write is finished long before the second buffer fills up. However, in a later lab, this same technique is used and overrun checking is necessary. Summer 2004/V0.2 Experiment 9: Memory and the I2C Bus Table 9–3: Streaming IO Checkoff Checkpoint 1. Using memblk as a starting point, create a program that implements streaming writes. Verify that your program works for your assigned I2C bus rates. Comments/Debugging Use the flowcharts to help you understand how to solve this problem. Test your program by using the ‘Transfer → Send Text File’ command in Hyperterminal to send a complete file. Do not use large files for test cases as HyperTerminal takes too long to send text files even with a baud rate of 115200. Your streaming write program should do something like the following: Program Operation Enter ‘r’ for read, ‘w’ for write... If ‘w’ is entered, then capture bytes from the serial port and write to the EEPROM using page mode. Print a ‘*’ character for each block written so there is visual evidence of program operation. Stop writing once 64K is written. If ‘r’ is entered, dump the memory contents to the screen. Have a single keypress halt the output, the next keypress resumes character output. Stop reading if 64K bytes is read. When printing a character, use: putch(c); where c is the character to be printed. To allow Hyperterminal to display the text with carriage return/ line feeds, add the check: if ((c == 0xd) || (c == 0xa)) pcrlf(); else putch(); This causes end-of-lines to display correctly in Hyperterminal. 9—7 Experiment 9: Memory and the I2C Bus Summer 2004/V0.2 DEMONSTRATE YOUR STREAMING WRITE PROGRAM; BOTH WRITE AND READ CAPABILITIES. C. Report 1. Include source code listings of any C programs. 2. Discuss how the 24LC515 handles a random read or write to an address above 0x7FFF. 3. For your assigned I2C bus rate, compute the time required to perform a page write - the includes the time to specify the initial address, transfer the 64 bytes, and the 5 ms write time. 4. Explain the difference between a random read and a sequential read for the 24LC515. 5. Based on the last digit of your student ID, explain the reasoning behind each line of the one of the following subroutines in the file i2cmsu.c: 0 or 1 use i2c_idle(), 2 or 3 use i2c_stop(), 4 or 5 use i2c_start(), 6 or 7 use i2c_putbyte(), 8 or 9 use i2c_getbyte(). 9—8 Summer 2004/V0.2 E x p e r i m e n t Experiment 10: Talking to the Real World 1 0 Talking to the Real World It is a fact of life that our pristine digital domain must talk to devices that live in the brutish analog world will all of its messiness of voltages, currents, noise, etc. The silver lining is that with communication comes control, and with control comes world domination! Keeping this goal firmly in mine, proceed in discovering the secrets of DACs and ADCs. Summary Use the PIC on-chip Analog-to-Digital Converter (ADC) with an external I2C-based Digital-to-Analog converter (DAC) to form the basis for a signal processing system. 10 — 1 Experiment 10: Talking to the Real World Summer 2004/V0.2 A. Prelab Requirements Table 10–1: Prelab Checkoff Do This Comments 1. Wire all connections shown in the schematic. You will not receive prelab credit unless your protoboard is fully wired before lab. 2. Become familiar with the operation of the dactst.c program attached to this lab. 3. Demo to the TA a spreadsheet that calculates a ADC output voltage given a Vref, an input code value, and number of ADC input bits. Example: For Vref = 5 V, input code of 128 (decimal), number of bits = 8, the output voltage is 2.5 V. The Excel functions POWER(x,y); DEC2HEX(x), HEX2DEC(x) are useful (the hex conversion is optional). 4. Demo to the TA a spreadsheet that calculates a DAC output code given a Vref, Vin, and number of DAC output bits. Example: For Vref = 5 V, Vin = 2.5 V, number of bits = 8, the output code should be 128. Analog input Vdd Analog out, To multimeter or scope 18F242 RA0/AN0 10K Pot. Be sure to connect the OUT1 pin of the MAX517 to Vdd - this serves as the reference voltage input to the DAC. Maxim 517 OUT1 OUT0 AD1 RC3/SCK/SCL SCL RC4/SDI/SDA SDA AD0 Vdd If you have trouble distinguishing which 8-pin DIP in your parts kit is the MAX517, look for the Maxim symbol on the package. This diagram assumes that 10K pullups are already on the SCL/SDA lines from the previous lab. Figure 10.1 PIC to I2C DAC connections 10 — 2 Summer 2004/V0.2 Experiment 10: Talking to the Real World B. Lab Activity The dactst.c program attached to this lab uses the onchip ADC to convert an external voltage to a 10-bit value and prints this value to the serial port as ASCII hex. It then drops the two LSBs of the 10-bit conversion and sends the 8-bit value to the MAXIM 517 DAC. Start ADC conversion Conversion No complete? Table 10–2: dactst.c Checkoff Comments/ Debugging Checkpoint 1. 2. Verify that the dactest.c program functions on your board. Complete the measurements/computations listed in Table 10–3 and Table 10–4. Verify that SCL, SDA are connected correctly to the MAX517 and that the AD0, AD1 pins are grounded. Use the same probe for all measurements. Yes Read 10-bit ADC value, print to serial port Convert 10-bit to 8 bit value by dropping 2 LSBs Send 8-bit value to DAC Table 10–3: ADC Measurement Measurement Value a) Vdd (measure this value!) b) 1 LSB (Vdd/1024) c) PIC RA0 input voltage when displayed code is 0x200 (this should be Vdd/2 but may not be because of offset voltage) d) PIC RA0 input voltage when displayed code is 0. This is the offset voltage. e) Corrected Input voltage for code=0x200 (c - d) f) Absolute Error = Expected (Vdd/2) - Corrected (e) g) Relative Error in LSBs ((f) / 1 LSB) An acceptable error is less than 1/2 LSB 10 — 3 Experiment 10: Talking to the Real World Summer 2004/V0.2 Table 10–4: DAC Measurements Measurement Value a) Vdd (measure this value!) b) 1 LSB (Vdd/256) c) MAX517 output voltage when displayed code is 0x200 (this should be Vdd/2 but may not be because of offset voltage) d) MAX517 output voltage when displayed code is 0. This is the offset voltage. e) Corrected Input voltage for code=0x200 (c - d) f) Absolute Error = Expected (Vdd/2) - Corrected (e) g) Relative Error in LSBs = ((f) / 1 LSB voltage) An acceptable error is less than 1/2 LSB The use of Vdd as a reference voltage is not sufficient for precision data conversions; the voltage ripple on Vdd is usually several LSBs for a 10-bit converter. Stand-alone integrated circuits are available that provide a stable voltage reference. DEMONSTRATE DACTST OPERATION ON YOUR PROTOBOARD. CAPTURE A WRITE CYCLE ON THE I2C BUS TO THE MAX517 AND EXPLAIN THE BYTE FORMATTING TO THE TA. DISCUSS YOUR MEASUREMENT RESULTS WITH THE TA. 10 — 4 Summer 2004/V0.2 Experiment 10: Talking to the Real World Table 10–5: dactst Modification Checkoff Checkpoint 1. 2. Comments/Debugging Change the wiring of the AD1/AD0 pins to alter the address of the DAC. Modify the dactest program to use this new address. Modify the dactst program to allow the user to choose one of 4 different transformations to the output waveform: a) clipping, b) multiply by two, c) divide by two, d) inversion. Use the following values for AD1/AD0 based on the last digit of your student ID: a) 0,1,2 use ‘01’; b) 3,4,5 use ‘10’; c) 6,7,8,9 use ‘11. The ‘#define DAC 0x58’ statement in dactst.c must be changed to accommodate the new A1/ A0 values. Review the address byte formatting in the MAX517 datasheet to determine the new value. Use the clipping ranges as shown in the table below based upon the last digit of your student ID. Use shifts to do the multiply by two or divide by two. Inversion means that the input voltage value should be subtracted from the maximum value. For example, if input_value is the non-inverted 8-bit output value for the DAC, then the inverted value would be 0xFF - input_value. Table 10–6: Clipping Ranges If the last digit of your Student ID is... Your clipping range is... 0 between 1.1v and 4.3v 1 between 1.3v and 3.9v 2 between 0.8v and 4.1v 3 between 0.9v and 4.2v 4 between 1.2v and 4.4v 5 between 1.0v and 4.0v 6 between 1.4v and 3.8v 7 between 1.6v and 4.6v 8 between 1.5v and 4.5v 10 — 5 Experiment 10: Talking to the Real World Summer 2004/V0.2 Table 10–6: Clipping Ranges If the last digit of your Student ID is... 9 Your clipping range is... between 1.7v and 3.7v Your program should prompt the user as shown below: Operation choice: 0: inversion 1: multiply by 2 2: divide by 2 3: clipping Enter choice: DEMONSTRATE YOUR PROGRAM USING THE MODIFIED DAC ADDRESS. C. Report This is a formal lab report; be sure to follow the formatting guidelines posted on the lab web site. 1. Include source code listings of any C programs. 2. Include all DAC and ADC measurements. Formal Report Questions The following questions refer to the non-PIC microcontroller you are assigned via the lab web site. 3. What serial standards are supported with on-chip modules by your µP? Asynchronous serial trans- 10 — 6 Summer 2004/V0.2 Experiment 10: Talking to the Real World mission? SPI? I2C? What is the maximum synchronous transfer rate? 4. Does it have an on-chip A/D? If ‘yes’, what is the precision? 5. Does it have an on-chip DAC? If ‘yes’, what is the precision? 6. How are the special registers of the on-chip modules accessed? What is the range of memory addresses that correspond to these special registers? 7. At reset, what location is the first instruction instruction fetched from? 8. What are the minimum and maximum package sizes in terms of pin count? For the maximum package size, how many parallel port lines are available? 9. What is the maximum system clock frequency? 10.What is the minimum Vdd supported by the processor (This is the minimum Vdd the processor will operate at for normal operation; it is not the value in the ‘absolute maximum rating’ section of the datasheet; so do not give any negative values for this, please!). 10 — 7 Experiment 10: Talking to the Real World 10 — 8 Summer 2004/V0.2 Summer 2004/V0.2 E x p e r i m e n t Experiment 11: Controlling Time 1 1 Controlling Time The PIC18Fxx2 is capable of sophisticated time measurement and manipulation. Unfortunately, this does not include the capability to travel either forwards or backwards in time; only the PICT3000 can do that and it is currently busy looking for somebody named ‘Conner’. Alas, we have to stick to mundane things like precise waveform generation and leave time travel for grad school. Summary Pulse Width Modulation (PWM) is explored using the PIC PWM module, and waveform generation is performed using the PIC timer modules. 11 — 1 Experiment 11: Controlling Time Summer 2004/V0.2 A. Prelab Requirements Table 11–1: Prelab Checkoff Do This 1. Comments Connect the audio jack connector to the output of the DAC. Also connect an LED to pin ‘RC2/CCP1’ of the PIC, and the 10K potentiometer to the RA0/AN0 input. 2. Demo to the TA a spreadsheet that calculates the values required for Table 11-3. Your assigned target frequencies are in Table 11-2. The frequencies in Table 11–2 use the PWM mode for generating the square wave; this does NOT use the postscaler for frequency calculation. 3. The audio jack allows an external speaker to be driven by the DAC output. This capability is crucial for the last experiment, so it is tested in this experiment. The spreadsheet should calculate the PR2 values given a target frequency, and prescaling factors of 1, 4, and 16. The spreadsheet should also truncate the PR2 value to an integer value, then compute the %diff between the actual frequency obtained and desired frequency. Choose the pre-scale and PR2 value that gives the lowest %diff value. Become familiar with the sqwave.c, ledpwm.c, and sinegen.c programs attached to this lab. Maxim 517 Audio mini To determine which pin is ground on the jack, plug a cable from jack the line out of the PC into the jack, and use media player to play a MP3. Measure the voltage on the pins of the jack and determine the pin orientation provides a positive voltage. Do this before connecting the DAC to the jack. Do not attempt to plug the mini-jack into the protoboard; solder wires onto the connections for a more reliable connection. OUT0 Table 11–2: Assigned Frequencies If the last digit of your student ID is... 11 — 2 Use these frequencies 0 or 1 2500 Hz, 10 KHz, 121 KHz 2 or 3 3600 Hz, 15 KHz, 133 KHz Summer 2004/V0.2 Experiment 11: Controlling Time Table 11–2: Assigned Frequencies If the last digit of your student ID is... Use these frequencies 4 or 5 4200 Hz, 28 KHz, 144 KHz 6 or 7 5500 Hz, 37 KHz, 151 KHz 8 or 9 6100 Hz, 49 KHz, 165 KHz Fill in the table below for your three assigned frequenTable 11–3: Prescale, PR2 Values Target Frequency Prescale PR2 Actual Freq % diff a) b) c) cies. There might be more than one solution using different prescale values; use the prescale value that gives the best match for the target frequency. The ‘Actual Frequency’ column is the computed value using the prescale and PR2 values using the formula: PWM period=[(PR2)+1]*4*TOSC*Pre Freq = 1/(PWM Period) Tosc = 1/(Osc. Frequency) The ‘% diff ’ column is the percentage difference between Actual and Target frequencies computed as: (actual - target)/target * 100% 11 — 3 Experiment 11: Controlling Time Summer 2004/V0.2 B. Lab Activity The sqwave.c program uses the PWM module to generate a square wave on the RC2/CCP1 output. The program prompts the user to enter timer2 prescale and PR2 values. sqwave.c Table 11–4: Square wave generation checkoff Checkpoint 1. Debugging/Comments Use the sqwave.c program to check the values you computed for Table 11-3. Use a scope to monitor the output waveform on pin ‘RC2/CCP1’. Use the frequency measurement capability of the scope to check if the output frequency matches the ‘actual frequency’ column in Table 11-3. DEMONSTRATE THAT YOUR COMPUTED PRESCALE, PR2 VALUES GIVE THE EXPECTED FREQUENCIES. 11 — 4 Summer 2004/V0.2 Experiment 11: Controlling Time The ledpwm.c program outputs a square wave of a fixed frequency, but allows dynamic update of the duty cycle by reading the AN0 analog input. This 10bit value is used to set the value of the duty cycle. Adjusting the potentiometer adjusts the duty cycle of the square wave on the RC1/CCP1 pin. ledpwm.c Table 11–5: LED PWM Checkoff Checkpoint Comments/Debugging 1. Verify the operation of ledpwm.c on your PIC. What happens to the LED brightness as you adjust the duty cycle via the potentiometer? Monitor the waveform generated on pin RC2/ CCP1 with the oscilloscope. 2. Use a multimeter to measure the current through the LED for various duty cycles and complete Table 11-6. Table 11-16 requires two current measurements for particular duty cycles. The two duty cycles, based on your student ID, are: a) 0/1 5%/25%; b) 2/3 10%/30%; c) 4/5/6 15%/35%; d) 7/8/9 20%/40%. Also, measure current at the 85% duty cycle, and at a duty cycle midway between the two above. Record your current measurements in Table 11–6. Compute the expected current for the 3rd (halfway between 1st and 2nd duty cycles) and the 4th (85%) duty cycles. Ideally there is a linear relationship between the current and duty cycle. Use the first two measurements to compute a straight line slope that is used to predict the currents for the last two duty cycles. 11 — 5 Experiment 11: Controlling Time Summer 2004/V0.2 Table 11–6: PWM Current Measurements Duty Cycle (%) Duty Cycle (us) Measured Current (mA) Expected Current (mA) % Diff Pt1 N/A N/A Pt2 N/A N/A (Pt2+Pt1)/2 85% SLOPE: ____________________ (record slope here) WORK: (show work here) SHOW AND DISCUSS THE RESULTS OF TABLE 11-6. 11 — 6 Summer 2004/V0.2 Experiment 11: Controlling Time The sinegen.c program generates a sine wave using a table lookup approach via the MAX517 DAC. The program prompts the user to choose between a 16 entry or a 64 entry table. Timer2 is used to trigger an interrupt that reads the next entry from the table. The interrupt interval is set by a prescale value of 4, a postscale value of 3, and the PR2 value that is set by the A/D AN0 input. The sine wave period is: sinegen.c table_size * interrupt_interval he 16-entry and 64-entry sine wave tables are in sinegen.h. The PR2 value is limited by sinegen.c to be between 25 and 100. Table 11–7: Arbitrary Waveform Generation Checkpoint 1. Comments/Debugging Verify sinegen.c operation on your PIC. Hook the audio jack output to the powered speakers of the PIC. Vary the period of the sine wave via the potentiometer and make primitive music. Use the scope to monitor the output of the DAC. 2. Note what happens for the 16table case when the frequency is increased to near its maximum value. The interrupt interval becomes too small for the DAC to be updated with the new table value because of the I2C bus speed. This causes waveform values to be skipped, degrading waveform quality. 3. Fill in the computations and measurements required in Table 11– 8. If you do not hear a varying tone as you adjust the sine wave period, check the audio jack connections. 11 — 7 Experiment 11: Controlling Time Summer 2004/V0.2 Table 11–8: sinegen.c Measurements Measurement Expected Measured a. Min.TMR2 interrupt interval (PR2=25, PRE=4, POST=3), us N/A b. Max.TMR2 interrupt interval (PR2=100, PRE=4, POST=3), us N/A c. Min Sinewave Frequency, 16 entry (Hz) d. Max Sinewave Frequency, 16 entry (Hz) e. Min Sinewave Frequency, 64 entry (Hz) f. Max Sinewave Frequency, 64 entry (Hz) g. Measured I2C Bus Speed (KHz) N/A h. DAC update time (us) i. Max sinewave frequency (16 entry) (Hz) without losing DAC update values Comments on sinegen.c measurements Values (a), (b) can be computed from the datasheet formula for timer2 interrupt interval. For (c) through (f), the period of the sinewave is the interrupt interval times the number of table entries for the sinewave; the frequency is the inverse of the period. For (h), compute the DAC update time by multiplying the number of I2C bit times required for the DAC update by the measured I2C bus speed. The measured value can be obtained by using the scope on the I2C bus. For (i), the measured DAC update time determines the minimum time interval for each new sinewave value. The number of entries in the sinewave times this value gives the minimum period of the sinewave that can be reliability generated without skipping values. Sinewave values are skipped when the timer2 interrupt interval becomes less than the DAC update time. 11 — 8 Summer 2004/V0.2 Experiment 11: Controlling Time Table 11–9: Arbitrary Waveform Generation Checkpoint 1. Comments/Debugging Modify sinegen.c to generate an arbitrary waveform as described in Table 11-8. Following this table are detailed hints on how to implement the arbitrary waveform generator. Table 11-8 provides the details of the arbitrary waveform that you are required to generate. The waveform is one or more sine wave cycles, followed by one or more triangle wave cycles, followed by one or more square wave cycles that are then repeated. A 1x period is 64 time units; waveforms can have periods of 1x, 2x, or 0.5x. The waveform generated by sinegen.c has a 1x period by this definition. The interrupt interval for this program should be set in the same way as in sinegen.c. The triangle wave and square wave can also be inverted; Figure 11-1 shows examples of inverted triangle waves and square waves. If one cycle of a waveform is inverted, all cycles are inverted. Arbitrary Waveform Generation Table 11–10: Waveform Assignments If the last digit of your student id is: Your waveform is 0 1 cyc sine, 2 cyc triangle (0.5x per), 1 cyc square (0.5x per) 1 2 cyc sine, 1 cyc triangle (2x per), 2 cyc square (0.5x per) 2 1 cyc sine, 1 cyc triangle (0.5x per), 1 cyc square (2x per) 3 2 cyc sine, 2 cyc triangle (2x per), 1 cyc square (2x per) 4 1 cyc sine, 2 cyc triangle (2x per, inverted), 1 cyc square (2x per) 5 1 cyc sine, 2 cyc triangle (2x per, inverted), 1 cyc square (0.5x per) 6 2 cyc sine, 1 cyc triangle (0.5x per), 2 cyc square (0.5 x per, inverted) 11 — 9 Experiment 11: Controlling Time Summer 2004/V0.2 Table 11–10: Waveform Assignments If the last digit of your student id is: Your waveform is 7 1 cyc sine, 1 cyc triangle (0.5x per, inverted), 1 cyc square (0.5 x per, inverted) 8 2 cyc sine, 2 cyc triangle (0.5x per, inverted), 1 cyc square (2x per) 9 1 cyc sine, 2 cyc triangle (0.5x per, inverted), 2 cyc square (2x per, inverted) Because the sine wave always has a 1x period, use the 64-entry lookup table to generate this waveform. You can use this same approach for square and triangle waves, or you can compute the next value. The square wave only has two possible values, 0xFF or 0x00, so it is easy to compute its value. The triangle wave next value is computed by adding or subtracting a constant to the previous value. The constant is added when the slope is rising; the value is subtracted when the slope is falling. The constant added or subtracted depends on the period; you can figure this out. Be careful of wraparound of the triangle wave value at its peak point - the 8-bit value will wrap to 0x00, and a 0xFF is required for full scale output. Note the first value of any waveform is always 0x80 (Vdd/2). 11 — 10 Summer 2004/V0.2 Experiment 11: Controlling Time normal inverted normal inverted Figure 11.1 Examples of Normal and Inverted Waveforms Your program must track the current cycle number and the corresponding waveform to be generated. The tabmax variable in sinegen.c determines the period of a waveform; this value can be changed from cycle to cycle depending on the waveform being generated (i.e., for 2x period tabmax = 128, for a 0.5x period tabmax = 32). Write separate subroutines for square wave and triangle wave generation. DEMONSTRATE YOUR ARBITRARY WAVEFORM GENERATION PROGRAM. 11 — 11 Experiment 11: Controlling Time Summer 2004/V0.2 C. Report 1. Include source code listings of any C programs. 2. Include the values computed for Table 11–1. 3. Include the values computed for Table 11–6 including the slope computations. The accuracy of the current prediction degrades for higher values of duty cycle, why? (hint: look at Figure 16-16 in the PIC datasheet). 4. Include the measured and computed values for Table 11–8. Show your work for all computed values. Discuss reasons for any major discrepancies between expected and measured values (in particular, address the DAC update time computation). What limits the frequency of the sinewave generated by the table lookup method in sinegen.c? For a sinewave with a fixed number of table entries, how can this frequency be increased? 11 — 12 Summer 2004/V0.2 E x p e r i m e n t Experiment 12: Time Measurement 1 2 Time Measurement Precision time measurement is important to many folks, like the two-man bobsledding team who missed the gold medal in the World Cup by 0.06 seconds over 10 cumulative runs1. What makes such magical disappointments possible? Why the microprocessor, of course! Read on, and find out how you too can design a system that ruins somebody’s day! Summary Use the PIC capture module to decode an infrared pulse train via pulse width measurement. 1. No joke. FIBT Men’s 2-man bobsled, Altenberg, Germany 2002. 1st place total over 10 runs: 1:53.04. 2nd place: 1.53.10. I think that I would find a different sport. 12 — 1 Experiment 12: Time Measurement Summer 2004/V0.2 A. Prelab Requirements Table 12–1: Prelab Checkoff Do This Comments 1. Connect a momentary switch to the RC2/CCP1 input. 2. The program swdet.c uses Timer1 and the Capture module to measure the pulse width of a momentary switch. Read this program and understand its operation as you will need to modify it to fulfill the lab requirements. Refer to the schematic below. Vdd 18F242 10K RC2/CCP1 Figure 12.1 Momentary Switch to CCP1 12 — 2 Summer 2004/V0.2 Experiment 12: Time Measurement B. Lab Activity The swdet.c program uses the PIC’s capture module to measure the low pulse width of a momentary switch. The program captures the time of the falling edge, then changes the capture mode to rising edge and captures that time. The pulse width is the difference of these two times. The swdet.c program only produces the correct calculation if timer1 overflows once or none. You may have to push the button quickly to avoid multiple timer1 overflows. swdet.c Falling edge, capture time as ‘A’ Table 12–2: swdet.c Checkoff Checkpoint Rising edge, capture time as ‘B’, width is ‘B’ – ‘A’. Debugging 1. Verify the operation of swdet.c on your PIC. The ‘timer tics’ that is printed is the elapsed timer tics between the edges; the pulse width is the computed time in microseconds. 2. Fill in the table below for three button pushes. Use a scope in single trigger mode and capture the low pulse width. Table 12–3: Switch Pulse Width Results Trial Tics Computed Width Measured Width % diff 1 2 3 12 — 3 Experiment 12: Time Measurement Summer 2004/V0.2 . Multiple Timer1 Overflows Table 12–4: swdetnew.c Checkoff Checkpoint 1. 2. Debugging Create a new version of swdet.c called swdetnew.c. This new version must use a scaling factor of 2 and print out the correct time in microseconds even when timer1 has multiple overflows. Use a scope in single trigger mode and capture the low pulse width. Only the time calculation must be changed; no changes are required to the interrupt code. Fill in the table below for three button pushes. T Table 12–5: Switch Pulse Width Results Trial Tics Computed Width Measured Width % diff 1 2 3 DEMONSTRATE THE OPERATION OF SWDETNEW.C ON YOUR PIC. 12 — 4 Summer 2004/V0.2 Experiment 12: Time Measurement Place the IR receiver module from your parts kit on the protoboard, and connect the OUT pin to the RC2/ CCP1 pin of the PIC. IR Pulse Decoding Connect Out to pin RC2/CCP1 of the PIC. Bend carefully to get out of the way so can plug into protoboard. 3 Vcc 1 2 Out Gnd Obtain an IR universal remote from the TA to use as an IR source. Program the remote with your assigned code as found in Table 12–6. Monitor the OUT pin with the oscilloscope in single capture mode (falling edge), and use the VCR play button to trigger an output from the IR receiver module. The waveform should look something like the diagram below: # of bits depends on IR remote Start ‘0’ ‘1’ Stop The ‘0’ bit has a 50% duty cycle, while the ‘1’ bit has a 75% duty cycle with a period that is 2x that of the ‘0’ bit. The period of the start bit, ‘1’ bit, ‘0’ bit, and number of bits in the frame depends on the IR remote control and function (VCR, TV, DVD, SAT). The observed waveform may have different duty cycles for 12 — 5 Experiment 12: Time Measurement Summer 2004/V0.2 ‘1’, and ‘0’ depending on the remote control; always assume that the ‘1’ value has the longer period. Table 12–6: IR Remote Assignment If the last digit of your Student ID is... Your IR Remote Assignment is... 0 or 1 000 2 or 3 246 4 or 5 234 6 or 7 280 8 or 9 233 To program the remote with the assigned code, press and hold the setup button until the LED remains on. Release the setup button. Press and release the VCR button. Enter the 3-digit code above; the LED will blink for each keypress. At this point, the remote is programmed with the new code. The PIC’s capture module can be used to capture the number of timer1 counts between falling edges, and thus determine the sequence of ‘1’s and ‘0’s in a frame. ‘1’,’0’, Start periods 12 — 6 Complete Table 12–7 based on oscilloscope measurements. Determine a prescale value to use with the timer1 module that will give capture deltas between falling edges that can distinguish between a start, a ‘1’ bit, or a ‘0’ bit. Then use these values in a program that decodes the first two bytes of a frame. Summer 2004/V0.2 Experiment 12: Time Measurement Table 12–7: Period Measurement Bit Type Measured Period Timer1 Ticks Start Bit ‘0’ Bit ‘1’ Bit Prescale used: Table 12–8: IR Decoding Checkoff Checkpoint 1. Using swdetnew.c as a starting point, write a program called irdecode.c that decodes the first two bytes of an IR frame. Assume the bits are sent LSB to MSB in each byte. Use the computed timer1 tick values in the table above to help you detect the different bits. Do not use these exact values; use values that are somewhat less than these and check the bit type from longest to shortest. Comments/Debugging You should first check for a start bit, then start checking for either ‘1’ or ‘0’ bits, right shifting the received bit into a temporary byte. Once 8 bits are received, save this byte. Once two bytes are received, print the values of the two bytes and verify they are correct by decoding observed waveform. The following are suggestions on how to write your irdetect code; there are MANY other code variations that can accomplish this task. Hints for IR Decoding While the swdet/swdetnew programs provide a good starting point, there are important differences between swdet/swsdetnew and idecode. The swdet/swdetnew code measured time between a falling edge and a rising edge; the irdecode code must measure time between successive falling edges. This means that you should not change the compare mode 12 — 7 Experiment 12: Time Measurement Summer 2004/V0.2 once you have set it to falling edge triggered (the edge_type variable is not needed). The swdetnew code only made one measurement; irdecode must make several time measurements, where each measurement is used to distinguish a one or zero bit, and these bits are accumulated into two bytes to provide the decoded value. All of the time measurement and bit accumulation work can be done by the interrupt service routine (ISR). Because several measurements are made, there is a temptation to put a loop into the ISR to accumulate the 16 bits needed for the two decoded bytes. However, an ISR cannot have a loop in it as the ISR must exit so that another interrupt can occur. One or more variables must be used to keep track of what happens between different triggerings of the interrupt service routine. This is a finite state machine approach to programming, and typically a temporary variable called state is used to keep track of what the ISR should do on each interrupt trigger. Initially, set state to IDLE (you can assign any numbering scheme you wish for these states; here names are used for states for clarity). IDLE: Identify if the IR output has been idle; this can be done by counting timer1 overflows; once a particular count has been exceeded, change the state to START1. Checking for idle is important as in this way you can clearly identify when the start bit occurs. START1: A capture interrupt in the START1 state is the falling edge of the start bit; change the state to START2. START2: A capture interrupt in the START1 state is the falling edge of the first data bit; remember this capture time and change the state to DATA. 12 — 8 Summer 2004/V0.2 Experiment 12: Time Measurement DATA: Each capture interrupt in this state is the falling edge of a data bit. The time between the current capture and last capture is the pulse width of the last data bit. Determine if a ‘1’ or ‘0’ occurred, and shift these bits into a temporary variable. Once 8 bits have been captured, record this as the first byte. Record 8 more bits for the second data byte (a total of 16 bits has been captured). Set a flag called PRINT that will cause the main() routine to print out the bytes and set the state to IDLE to begin looking for an idle condition again. You will need to use a temporary variable to track the number of bits in a byte that has been captured, and another variable that identifies which byte is being used for recording the bits. The above code is placed in the interrupt service routine. The main() routine does configuration and enables interrupts, then enters an infinite loop that waits for PRINT to become a ‘1’, prints the two bytes that were received, resets PRINT to ‘0’, and loops back. Do NOT put any print statements in the ISR. Again, there are other ways to write irdetect. For example some of the above code could be placed in main(); the division of labor between the ISR and main() is a user preference. The only limitation on the amount of code in the ISR is that the execution time of the ISR must be shorter than the expected interrupt interval time so that interrupt events are not missed. DEMONSTRATE YOUR IR DECODING PROGRAM. CAPTURE A FRAME USING THE OSCILLOSCOPE AND VERIFY THAT THE DECODED BYTES MATCH THE OBSERVED BITSTREAM. 12 — 9 Experiment 12: Time Measurement Summer 2004/V0.2 C. Report 1. Include source code listings of any C programs. 2. Include the results of Table 12–3 and Table 12–7. 12 — 10 Summer 2004/V0.2 E x p e r i m e n t Experiment 13: The PIC Listens and Speaks 1 3 The PIC Listens and Speaks This is it, the last lab! Hurrah! After this you will have learned everything there is to know about µPs and will never have to suffer from µP brain strain again.....uh, sorry, no. At some later point in your career, you will be faced with µP WTH911 with 101 onboard modules including the latest serial standard KITSYNC. Hopefully, these lab experiences will help you to read the datasheets, strain your brain, and make sense of it. In other words, the fun with learning about µPs has just begun; welcome to life long learning! Summary Have the PIC record audio to serial EEPROM and then play it back, using different sampling rates. 13 — 1 Experiment 13: The PIC Listens and Speaks Summer 2004/V0.2 A. PreLab Requirements Table 13–1: Prelab Checkoff Do This Comments 1. Wire all connections shown in the schematic. You will not receive prelab credit unless your protoboard is fully wired before lab. Note that the serial EEPROM is not shown, but it is required as well for storing the digitized audio. The LM386 is an 8-pin DIP made by National Semiconductor. It provides a fixed analog gain of 20 with the output biased to 1/2 the power supply. No external components are required. 2. Read the notes below on audio sampling, then fill in the tables regarding sample rate computations. A simple spreadsheet would help in these calculations. 3. The audio.c file attached to the lab will sample the AN0 input at a fixed rate and store the values in EEPROM. Read and understand this program as playback functionality must be added to this program. Change the ROM, DAC define statements is audio.c to match the previously assigned I2C addresses for these devices. DAC DIP Switch Maxim 517 Open for record Closed for playback OUT0 Audio mini jack I2C bus 18F242 RA0/AN0 LM386 Vout + - use volume control on PC to adjust audio signal magnitude Figure 13.1 Audio Sampling Schematic 13 — 2 Summer 2004/V0.2 Experiment 13: The PIC Listens and Speaks The audio.c file attached to this lab uses timer2 to generate an interrupt at a fixed interval to sample the A/D input and store the result to EEPROM. The same double-buffered page write approach as used previously to capture serial data is used here. Two 64-byte buffers are used; while one buffer is being written to EEPROM, the other buffer is being used to capture data from the A/D. Audio Sampling The sampling interval is the time interval between reads of the A/D. The inverse of the sampling interval is the sampling frequency. The audio playback quality degrades if the sampling frequency is too low. A sampling frequency of 8 KHz (or sampling interval of 125 µs) is considered adequate for non-music audio. For music, a sampling rate of 14.4 KHz is commonly used. Audio samples are typically compressed in some manner to reduce storage requirements. The audio.c program only saves the most significant 8 bits from the A/ D value and does no compression when saving to EEPROM. Playback must be at the same sampling rate as used during record. For each sample, the value is read from EEPROM, then written to the DAC. Because reads are from sequential locations, a current address read is used each time to fetch a byte from EEPROM. This requires sending one command byte and then reading the return byte from the EEPROM; the following read is from the next sequential address. Read more about a current address read in the EEPROM datasheet. Complete Table 13–2 for playback and Table 13–3 for record to determine which is the critical path in limiting the sampling rate of the audio signal. For instruction overhead calculation, assume a 14.7456 MHz 13 — 3 Experiment 13: The PIC Listens and Speaks Summer 2004/V0.2 clock with each instruction taking 4 clock cycles to execute. Also assume a 400 KHz I2C bus speed. Table 13–2: Playback Calculations Category Time/Frequency a) DAC Write Time per sample b) EEPROM read time per sample c) Instruction overhead time per sample (assume 100 instructions) d) Total sample time (a+b+c) e) Max playback rate (1/d) Table 13–3: Record Calculations Category Time/Frequency a) I2C transfer time for page write b) Page write completion time 0.005 c) Instruction overhead per sample (assume 40 instructions) d) Total Write time (a + b + 64* c) e) Sample interval (d/ 64) f) Maximum sampling frequency (1/e) The instruction overhead for record is less than playback because it is principally the overhead of the interrupt routine whose only task is to store the A/D value in a buffer. IN THE PRELAB CHECKOFF, DISCUSS WHICH FUNCTION, RECORD OR PLAYBACK, IS THE LIMITING FACTOR FOR SAMPLE FREQUENCY. 13 — 4 Summer 2004/V0.2 Experiment 13: The PIC Listens and Speaks B. Lab Activity Table 13–4: Playback Checkoff Checkpoint 1. 2. Comments/Debugging Compile the audio.c program and verify that the connections are correct for audio sampling. Do this by using an audio cable to connect the line out from the PC to your audio plug. Use Windows Media Player to play any of the attached WAV files. Chose the calibrate option to determine if there is sufficient voltage variation on the AN0 input (also use the oscilloscope to view this waveform). Adjust the POT to change the amplitude of the input signal seen by the LM386 input; this changes the range of the input signal seen at the AN0 input of the PIC. Modify the audio.c to add a playback option. Test your playback first at 4 KHz, then try to achieve an 8 KHz playback. Also test at 2 KHz. Read the hints below on how to achieve an 8 KHz playback rate. The TA will provide the audio cable and mini-jack connector. Note how the audio quality improves as the sampling rate increases. The flowchart on the next page provides a basic idea of what is needed for playback. All of this work is done outside of the interrupt service routine, whose only job during playback is to set a flag indicating that an interrupt has occurred and that a sample should be read. Implementing Playback To set the EEPROM address to zero, a write command to location 0 is issued. However, instead of providing write data to the EEPROM after the address, a stop condition (i2c_stop() function) is issued. This aborts the write operation, but leaves the internal address counter pointing at location 0. Read more about this in the EEPROM datasheet. The interrupt_flag variable is set by the interrupt service routine to indicate that an interrupt has occurred. This is not the timer2 interrupt flag; the clearing of this bit is already handled by the interrupt service routine. 13 — 5 Experiment 13: The PIC Listens and Speaks To reach an 8 KHz sampling rate, the I2C bus must be run above the 400 KHz maximum bus rate. More importantly, the playback loop must be written as efficiently as possible. To improve execution time, flatten all subroutine calls. This means that instead of performing a call to i2c_GetByte(), copy the code from i2c_GetByte() directly into the loop to save the subroutine call and return overhead. Also, most of the i2c functions include a call to the i2c_idle function. This is really not necessary in this case as the PIC is the only master on the bus. Removing these calls saves a substantial amount of execution time. Initialize EEPROM address to 0 Enable tmr2 interrupt Read byte from EEPROM Wait for interrupt 0 Interrupt_flag? interrupt_flag=0 Write byte to DAC Summer 2004/V0.2 Note that the playback loop never exits; when the read reaches the last location in the EEPROM the internal address counter rolls over to 0. The playback continually loops through the entire EEPROM contents with the only exit being via a RESET condition. Place an overrun check before the ‘wait for interrupt’ box to determine if the interrupt_flag is already a ‘1’. If this is true, then the playback loop is too slow for the current sampling rate - write a ‘!’ to the serial port in this case to provide visual evidence of overrun. DEMONSTRATE YOUR AUDIO PLAYBACK AT THE FASTEST PLAYBACK THAT YOU WERE ABLE TO ACHIEVE (8 KHZ IS AS FAST AS YOU NEED TO GO). ALSO DEMONSTRATE A PLAYBACK AT A SPEED THAT SHOWS THAT YOUR OVERRUN CHECK IS WORKING. 13 — 6 Summer 2004/V0.2 Experiment 13: The PIC Listens and Speaks C. Report 1. Include source code listings of any C programs. 2. Include the results from Table 13–2 and Table 13– 3. 3. What is needed in order to reach a record and playback speed of 14.4 KHz? 13 — 7 Experiment 13: The PIC Listens and Speaks 13 — 8 Summer 2004/V0.2 Summer 2004/V0.2 A p p e n d i x Appendix A: Prototyping Hints A Prototyping Hints Read this for hints on building stuff. And boy, will you ever be busy building stuff!!! Breaking stuff, also, most probably. A favorite pastime of students is to connect VDD directly to GND. But this sorta does bad things to chips like...BLOW THEM UP!!! So read the hints in here and save the life of a chip, OK? A—1 Appendix A: Prototyping Hints Summer 2004/V0.2 A. Protoboard and Parts Protoboard Layout Above is a sample protoboard layout for the PIC processor and most of the components used in the lab exercises. DO NOT use this picture as schematic - it is not a substitute for datasheets that provide the pinout of each component. The above component placement can be used for the entire semester. Of course, this is only a suggested layout; it does not have to be followed. Some students in the past have ignored the above picture and placed components semi-randomly, only to find they have to completely rewire their protoboard halfway through the hardware labs because they don’t have enough room. So avoid this, and be careful in your component placement and neat in your wiring. The above picture has more components on it than what is needed for the initial hardware labs. Either place all of the components at once or place them as required by the lab exercises. The schematics in this lab manual do not have pin numbers on them. There are two reasons for this: 1. It is important for you to learn how to read datasheets to determine pin numbers and device capability. 2. If pin numbers were placed in the diagrams, then inevitably one or two would be wrong, causing you to become angry. And who needs that? Be happy, read the datasheets! In this appendix, pinout information is provided for some of the simpler components. For the more complex components (PIC, DAC, EEPROM, etc.) refer to the datasheets linked to the lab website. In reading some of the remaining comments about components, understand that over time the components in the parts kit may change over time and those changes may or A—2 Summer 2004/V0.2 Appendix A: Prototyping Hints may not be reflected in the current version of this document. How do you know if a component has changed? Well, if the component described here has 4 pins, and the component in your part kit has 50 pins, then the component has changed. Look for subtle differences like that, and you will be A-OK. This is the socket for the plug from the wall transformer. It has three pins: bottom, side, and back. The bottom pin is the GROUND pin and should go to the '' protoboard power rail. The back pin is the +V supply voltage (9V or 12V depending on the transformer), it should be connected to a pin on the power switch. The side pin is left unconnected. Power Connector DO NOT PLUG THIS CONNECTOR INTO THE BOARD. The power connector does not plug well into a protoboard, and will easily pop out if jostled. You MUST have a solid power connection to your protoboard. If your power connector has eyelets, then solder wires from your wiring kit onto each eyelet, and use these to provide power to your board. If your power connector does not have eyelets, then wirewrap a length of wire to each pin. For each wirewrap connection, add a dab of solder to make sure these are firmly connected. You can connect the other end of the wirewrap wire to a wirewrap header on your board, or solder them to a wire from your wirewrap kit and then plug the wire into the board. The 7805 is used to provide a regulated + 5V output. In the protoboard picture, the right pin is connected to the output of the power switch, and the left pin is the +5V output. Note that in the picture the labeling on the 7805 is facing away from the user. The middle pin is ground and should be connected to the '-' protoboard ground rail. After connecting the wall transformer, power switch, and voltage regulator for the first time, Voltage Regulator (7805) A—3 Appendix A: Prototyping Hints Summer 2004/V0.2 use a multimeter to verify that the 7805 is providing +5 V before plugging in any other components. PCB Fuse The parts kit contains two fast-blow PCB fuses. Use one of these between the voltage regulator and the +5V power to the rest of the protoboard. Be careful, even momentary shorts caused by touching VDD and GND together can blow the fuse. If the fuse is not used, then shorting power and ground will cause excessive current flow from the wall transformer, causing it to overheat and eventual permanent damage. When using the fuse, if your LED power light does not come on when the power is applied, then use the ohmmeter to check the resistance of the fuse (remove the fuse from the protoboard before checking the resistance). If the fuse does not have zero or very low resistance, then it has blown and must be replaced. Resistor SIP Packages The parts kit contains two resistor SIP packages (470 ohm and 10K ohm) whose pinout is shown below. The 470 ohm resistors are used for current limiting LEDs. The 10K ohm resistors are used as pull-ups for switches. Figure A.1 SIP Package, Isolated Resistors Capacitors (1.0 µF/0.1 µF) A—4 The parts kit contains 1.0 µF tantalum capacitors if your kit has a MAX232, or 0.1 µF if your kit has a MAX202. These capacitors have clearly marked + (positive supply), - (ground) terminals. Place a capacitor between the Vdd and Vss pins on the PIC - this Summer 2004/V0.2 Appendix A: Prototyping Hints helps protect the PIC from noise on the power supply. The capacitors are also needed for the MAX232/202 chip used in the RS-232 serial interface labs. An LED is useful as a visual indicator for a digital output. The diagram below shows how to identify the cathode/anode terminals on a LED. The diagram also shows the two ways to drive an LED from a digital output. Light Emitting Diodes (LEDs) +5V 470 ohm Low True output Anode (long lead) PIC output =0, LED on High True output =1, LED off PIC output =1, LED on Cathode (short lead) =0, LED off 470 ohm Figure A.2 LED Usage Connect one LED using a 470 ohm resistor so that it turns on when power is applied. This provides a warm and fuzzy feeling that power is on when trying to figure out why the circuit is not working. Power LED A—5 Appendix A: Prototyping Hints Summer 2004/V0.2 Power Switch There is no power switch with the wall transformer in the power kit. Remove power by unplugging the wall transformer from the wall, or from the power jack on the protoboard. There is also a slide switch in the parts kit than can be used as an on/off power switch as shown in the protoboard picture. Do not plug/unplug any chips (especially the PIC) when power is applied the device may be damaged if it is momentarily placed in the wrong protoboard location. Momentary Pushbutton Switches The parts kit contains one or more momentary pushbutton switches (closed on push). The pinouts on these switches are not standard, so use an ohmmeter to determine which two pins are shorted (have zero resistance) when the button is pushed. The diagram below shows how to connect the pushbutton to a digital input. +5V 10K ohm PIC input Input read as ‘0’ when switch is pressed, read as ‘1’ otherwise. Push button, momentary closure when pushed. Figure A.3 Pushbutton Usage 7.3828 MHz Crystal A—6 A crystal and two 15 pF capacitors are used for the oscillator option. The crystal is easily identifiable as it Summer 2004/V0.2 Appendix A: Prototyping Hints has a cylindrical metal casing with two pins. Because the crystal sticks up from the protoboard it is easy to knock it askew when adding wires; be careful. A potentiometer (i.e, 'pot') is a variable resistor; they have three pins as shown below. On a three pin package, the middle pin is the 'wiper' lead as shown. To produce a variable voltage on the wiper pin, connect pin 1 to VDD and pin 3 to GND (or vice-versa). Adjusting the potentiometer will change the resistance, changing the voltage present on pin 2. The potentiometer will be used to provide a variable voltage whose value can be measured using the PIC onchip analog-to-digital converter. The potentiometer in your parts kit has two back pins that are close together; these are the pins that should be connected to VDD and GND. The other two pins are spaced widely apart; either of these can serve as the wiper pin. Use wire wrap wires or soldered wires to provide a reliable connection from the potentiometer to the protoboard. The potentiometer in the pictures uses wire wrap wires from the pot to the 5 pin header plugged into the protoboard. Potentiometers Figure A.4 Potentiometer A—7 Appendix A: Prototyping Hints Summer 2004/V0.2 Audio Connector The audio mini-jack is a mono jack with three pins. Looking into the connector, the middle pin is ground, and the left pin is the signal pin. Wire Wrapping Wire wrapping is quickly becoming a lost art. Soon, only Jedi Masters will know the proper technique for wielding a wire wrap tool. Wire wrap is useful for creating reliable, non-solder connections. It is used in this lab to interface the protoboard to external connectors (DB9, modular jack) that cannot directly plug into the protoboard. In these experiments, the total number of connections made via wire wrap can be as little as 3, or at most 11, so do not worry about spending hours and hours becoming a wire wrap guru. The TA can demonstrate everything there is to know about wire wrapping in 30 seconds; use the description below for reference. Wrap end Unwrap end Wire stripper Wire wrap creates connections that look like this. The picture above shows the wire wrap tool available from the TA; this tool wraps 30 AWG wire. The steps for creating a wire wrap connection between two posts are: 1. Cut a section of wire the appropriate length. Leave plenty of slack, length is not important in these connections. Use scissors, pliers, or even the strip tool on the wire wrap tool to cut the wire. Do not use your teeth; your dentist would not approve. 2. Use the wire stripper on the tool and strip about 1/2 inch from each end. 3. Look into the wrap end of the tool. Find the hole in the center; this fits over the post. Look more closely, and find the small second hole near the side corresponding to the slit that runs along the side of A—8 Summer 2004/V0.2 Appendix A: Prototyping Hints wrapping end. Insert the bare end of the wire into this small second hole; the bare wire should be visible along the side slit. The wire cannot be inserted past where the insulation has been stripped. 4. Place the wire wrap tool over a post, and turn in a clockwise direction until all of the bare wire has been wrapped around the post (for the clock-challenged, clockwise == righty-tighty). 5. Repeat 3,4 for the second post. If a mistake is made, insert the unwrap end over the post and turn in a counter-clockwise direction to unwrap. Wire wrap connections are nearly foolproof. One potential problem occurs if all of the bare wire is not wrapped around the post. For the unlucky, this unwrapped bare portion of the wire shorts against an adjacent post on the connector creating a debugging headache. If your protoboard is old, chips and devices may have trouble staying in; they may pop out over time or be loose even after being seated in the board. Get a decent protoboard! Here is a piece of advice -- if you have an old protoboard which exhibits this problem, GET A NEW BOARD!!!!!! Save the TAs, and the poor students who have to work near you in lab the agony hearing you cry like a baby in frustration because you CANNOT GET THE BOARD TO WORK. You will have problems enough with a good protoboard; having a flakey protoboard makes finishing the hardware exercises a near impossibility, and will have you questioning the wisdom of majoring in EE, CPE or CS in the first place as it forces you to take this unbelievably frustrating course. A—9 Appendix A: Prototyping Hints Summer 2004/V0.2 Your PIC system will have to live through several hardware labs, so the components will have to stay on the board between labs. A tackle box or sewing kit box makes a good container for carrying your board and other components. Get a multimeter! A — 10 There are multimeter at each station in the lab, but it is handy to have an extra multimeter that is dedicated to monitoring current -- that way you can easily see if a short has occurred. A small multimeter is fairly inexpensive from electronics stores and useful around the house (well, at least it is useful around my house with its pre-colonial wiring). You will find it useful in other electrical engineering labs as well, so go ahead and invest in one. Summer 2004/V0.2 Appendix A: Prototyping Hints B. Debugging Here is a common situation observed in lab: a student stares intently at their board, trying to figure out what is wrong. Meanwhile, the scope and multimeter sit unused. Unless you possess X-ray vision, staring at a board does not do much help. Repeat after me three times “I SOLEMLY PLEDGE TO USE THE INSTRUMENTATION TO DEBUG MY PROBLEMS -- IN THIS WAY I WILL NOT DRIVE THE POOR TA CRAZY.” Read the next appendix and become familiar with a scope and multimeter; a little time spent becoming familiar with their operation will save you literally hours of debugging time later. When debugging a problem, follow a step by step procedure and eliminate potential problems sources in a methodical way. Again, this will save time, which is always good! The following debug checklists can be used to help locate common problems. 1. Used multimeter to check VDD to PIC? (yes/no) 2. Are all VSS pins (yes, there are more than one!) on the PIC are connected to ground? (yes/no) 3. Used scope to see if crystal is working (yes/no). 4. Used scope to ensure reset line works (yes/no). 5. Checked PIC with older test program (like ledflash) (yes/no). 6. Checked PIC in TA board to see if board problem? (yes/no). My board used to work and now it doesn’t! To solve this problem, do not use a fuse until the short is located, and use a multimeter to monitor the current flow. My fuse keeps blowing, my board used to work, help! 1. Disconnect one half of the protoboard from the other half and determine which half the problem is in. Only connect power for a brief period of time to see if short still exists. A — 11 Appendix A: Prototyping Hints Summer 2004/V0.2 2. Remove all ICs from problem half of board and see if short is fixed. 3. If short still exists, remove any capacitors. 4. If short still exists, then remove any switches. 5. If short still exists, then remove any LEDs. 6. If short still exists, then it must be a direct wiring connection between Vdd/GND. My RS232 interface does not work and/or serial bootloader does not work. The following steps can be used assuming your PIC is programed with the serial bootloader firmware -- use the serial bootloader Windows client and attempt to program your PIC. After pressing ‘program’ from the bootloader window on the PIC, the PC client sends a character periodically to the PIC in an attempt to connect to the PIC bootloader firmware in the PIC. This gives you serial data to look for with the scope. 1. Is MAX202 Vdd/GND connected? (yes/no) 2. Is MAX202 is producing +/- 10V? (yes/no) 3. Remove power from the PIC, press ‘Program’ on the bootloader Windows client interface, turn power on to the PIC. 4. Is character from PC arriving at DB9 TX pin? (yes/ no) 5. Is character from PC arriving at MAX202 Rin pin? (yes/no) 6. Is character from PC arriving at MAX202 Rout pin? (yes/no) 7. Is character from PC arriving at PIC RX pin? (yes/ no) 8. Is a character from PIC seen at PIC TX pin? (yes/ no) If YES, then follow the remaining steps, the bootloader firmware is attempt to send bytes back to the PC. 9. Is character from PIC reaching the MAX202 TIN pin? (yes/no) 10. Is character from PIC reaching the MAX202 TOUT pin? (yes/no) A — 12 Summer 2004/V0.2 Appendix A: Prototyping Hints 11.Is character from PIC reaching the DB9 TX pin? (yes/no)? (If yes, try a bootloader on a different PC). If you did not see a character from the PIC at step 8, then get the TA to reprogram your PIC with the bootloader firmware. Verify your PIC works in the TA board, and download the sercomm program and verify sercomm works in the TA board. If your PIC still does not work in your board, then verify the PIC to DB9 link use steps 8-11 above. Be sure that Hyperterm is configured with no flow control. 1. Verified both SCL and SDA have VDD via pullups when idle. (yes/no) 2. Do you have SCL/SDA swapped? (SCL is the CLOCK!) (yes/no) 3. Verified transmission by PIC on both SCL/SDA (yes/no) 4. Verified I2C device address in your program (yes/ no) 5. Verified I2C device address on A1/A0 pins of EEPROM/DAC (yes/no) 6. Is I2C Device (EEPROM/DAC) sending an ACK for each byte transmission? (yes/no)? My I2C interface does not work. 1. Check the reset pin and ensure that a 10K PULLUP is on this pin, with the reset switch configured to pull the MCLR line low when pressed. 2. Ensure that the configuration bits have Low Voltage Programming (LVP) DISABLED. If LVP is enabled, then pin RB5 must be grounded. You can ground RB5 and see if the problem disappears. My PIC seems to be spontaneously resetting?! A — 13 Appendix A: Prototyping Hints Summer 2004/V0.2 3. Program the PIC with the pertest.c sample code and see if it is a power-on reset or watchdog timer reset, or neither. My A/D input does not work? A — 14 1. Used a multimeter to check A/D input voltage variation (yes/no). 2. Verified that analog input connected to correct A/D input (yes/no). 3. Verified that PORTA is configured for analog input (yes/no). 4. Used print statement to print individual A/D result bytes (yes/no). Summer 2004/V0.2 A p p e n d i x Appendix B: Instrumentation B Instrumentation Instead of screaming at your protoboard during a debugging session, try using an oscilloscope -- it might be more productive! A. TDS 210 Oscilloscope The picture above shows the TDS 210 scope used in the lab. The numbers on the diagram are used to explain the scope functionality. 1. Turn on the oscilloscope via the power button on the top left. 2. Hook the Channel 1 oscilloscope probe (found below button #14) to the test output that is under button #11. Be sure to connect the ground input of the probe (the alligator clip) to the ground of the Displaying a continuous waveform B—1 Appendix B: Instrumentation Summer 2004/V0.2 test output. The test output provides a continuous 1 KHz square wave output that is 5 V peak-to-peak. 3. Press the AUTOSET button (button #27) on the oscilloscope. The AUTOSET button automatically adjusts the display settings of the oscilloscope to provide a readable waveform. After a few seconds, a square wave waveform should be visible on the screen. If no waveform is visible, press the CH1 Menu buttons (button #16) a couple of times until the waveform appears, then press the AUTOSET button again. Pressing the Ch1 Menu and Ch2 Menu buttons will show or hide the corresponding waveforms. Voltage/Time Scaling 4. Turn the Channel 1 VOLTS/DIV knob (#14) a few times. This knob changes the scale factor for viewing the channel 1 waveform. As the knob is turned, notice how the waveform is scaled taller or shorter accordingly. Knob #15 does the same for the channel 2 waveform. 5. Turn the SEC/DIV knob (knob #21). This changes the time-base for the waveform. As the seconds per division is increased, the waveform is 'compressed', and vice versa. Twist the SEC/DIV knob clockwise to reduce the time per division, expanding the waveform. Adjust the time-base so that approximately two cycles of the waveform are displayed. Measure Function 6. Press the measure button (#2). This displays the measure menu choices on buttons #7 through #11. 7. Press #7 until Source is highlighted. This changes the source of a measurement for buttons #8 through #11. 8. Press button #8 a couple times; notice that this switches measurement choices between channels 1 and 2. Press button #8 until CH1 is highlighted, and do the same for buttons #9, #10. B—2 Summer 2004/V0.2 Appendix B: Instrumentation 9. Now press #7 to change from Source to Type. This changes the type of measurement for buttons #8 through #11. 10. Press #8 until the Pk-Pk measurement is selected. Notice that the peak-to-peak voltage value of the waveform is displayed. 11. Press #9 until the Period measurement is selected. Note that the period of the waveform is now selected. 12. Press #10 until the Freq measurement is selected. Note that the frequency of the waveform is now selected. 13. Press the cursor button (#5). This changes buttons #7 through #11 to the cursor menu. 14. Press button #7 until Voltage is selected. This button selects Voltage, Time or Off for cursor mode. 15. Press button #8 until CH1 is selected as the source. 16. Use knobs #12 and #13 to adjust the positions of cursors #1 and #2 respectively. Note how the delta value opposite button #9 displays the voltage difference between the two cursors. 17. Press button #8 until Time is selected. Note that this changes the cursors from horizontal lines to vertical lines. 18. Adjust the cursors to measure the high pulse width of the square wave waveform. The delta value opposite button #9 displays the time difference between the two cursors. Cursor Function, measuring voltage difference, pulse width Button #23 controls the trigger menu. The trigger function determines when the scope captures a particular waveform. The capture can be triggered off the waveform on CH1, CH2 or an external input. The trigger can be tied to a particular edge (rising or falling) and a particular voltage point. In normal trigger mode, the display is updated each time the trigger con- Trigger Function, continuous or single shot capture B—3 Appendix B: Instrumentation Summer 2004/V0.2 dition is met. In single trigger mode, the display is updated with the first waveform that trips the trigger. 19. Press button #23 to display the trigger menu choices on buttons #7 through #11. 20. Use button #7 to select Edge as the trigger mode; this is the mode that is normally used. 21. Use button #11 to select Normal trigger mode. 22. Use button #8 to select between Rising and Falling edge triggered. Note how the waveform shifts one half clock cycle each time you change edges, with the active edge being in center of the screen. 23. Use the horizontal position knob (#19) to change the horizontal location of the trigger point. This is useful in observing complex waveforms where the trigger point is moved to the left edge of the screen in order to use all of the screen for viewing the captured waveform. 24. Use the trigger level knob (#22) to adjust the voltage level of the trigger point. Typically, this level is set midway between the peak-to-peak point of the waveform. 25. Use button #11 to select Single trigger mode. Note that the trigger status at the stop of the screen says ‘Stop’ because the trigger has been tripped, and the waveform captured. In a repeating waveform like a square wave, this mode is not very useful. However, this mode proves vital to capturing one-time events such as data being sent over a serial line. To capture another event after the trigger has been tripped, use button #11 to select Normal, then back to Single again (this procedure clears the waveform from the screen). The Run/Stop button (#29) can also be used by pressing it once so that Run appears at the top of screen, arming the trigger capture. AC vs. DC Coupling B—4 In a couple of the menus, such as the trigger and the channel menus, a choice between AC and DC cou- Summer 2004/V0.2 Appendix B: Instrumentation pling is given. AC coupling removes any DC value from the waveform and thus the waveform is displayed with the 0 V reference midway between the waveform’s peak-to-peak value. DC coupling displays the waveform referenced to ground. The Ground choice in the coupling menu displays the position of the ground reference. B. Multimeter A multimeter is used to measure voltage, resistance, and current. In this lab, the multimeter is principally used to measure resistance and current since the scope can be used to measure voltage. The multimeter type varies between lab stations, but all of them have the same general functionality. The black lead should be plugged into the Common or ground input, with the red lead into the V/Ω input. To measure the voltage of a pin on a protoboard, connect the black lead to the ground of the protoboard, the red lead to the pin that is the voltage measurement target. Use the DC(V) button on the multimeter to select voltage measurement. Use the Range buttons to select the voltage range. A value of 20 means that 20 V is the maximum that can be measured. Choosing smaller ranges provides more digits to the right of the decimal point in the display. Measuring Voltage Use the OHMs button (or KΩ) to select resistance measurement. The range values are in Kohms (1K = 1000 ohms). The display should blink indicating an open circuit (infinite resistance). Touch the leads together to short them, and the display should read a value near 0 (a short is zero resistance). Attach the leads across the pins of the device that is the resistance measurement target. The device should be out of the protoboard; do not try to measure resistance when the device is plugged into the protoboard. A good test Measuring Resistance B—5 Appendix B: Instrumentation Summer 2004/V0.2 case is a switch, either push button or slide switch. In the open position the resistance across the switch terminals should be infinite, in the closed position the resistance should be zero (a short). Measuring Current To measure current, plug the red lead into the ma input of the multimeter, and select the DC (mA) function. The range values refers to milliampere (1 mA = 0.001 A). To measure current flowing through a device, the multimeter is connected in series with the device. The figure below shows how to measure the current consumption of a PIC. +5V multimeter DC mA Common PIC Vdd Vss Figure B.1 Current Measurement with multimeter To measure total current through your board, place the multimeter in series your power switch to the 7805 voltage regulator. B—6