The Atmel AVR Microcontroller: Mega and XMega in Assembly and C Han-Way Huang Minnesota State University • Mankato Australia • Brazil • Japan • Korea • Mexico • Singapore • Spain • United Kingdom • United States Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. This is an electronic version of the print textbook. Due to electronic rights restrictions, some third party content may be suppressed. Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. The publisher reserves the right to remove content from this title at any time if subsequent rights restrictions require it. For valuable information on pricing, previous editions, changes to current editions, and alternate formats, please visit www.cengage.com/highered to search by ISBN#, author, title, or keyword for materials in your areas of interest. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. The Atmel AVR Microcontroller: Mega and XMega in Assembly and C Han-Way Huang Vice President, Editorial: Dave Garza Director of Learning Solutions: Sandy Clark Acquisitions Editor: Stacy Masucci Managing Editor: Larry Main © 2014 Delmar, Cengage Learning ALL RIGHTS RESERVED. No part of this work covered by the copyright herein may be reproduced, transmitted, stored, or used in any form or by any means graphic, electronic, or mechanical, including but not limited to photocopying, recording, scanning, digitizing, taping, Web distribution, information networks, or information storage and retrieval systems, except as permitted under Section 107 or 108 of the 1976 United States Copyright Act, without the prior written permission of the publisher. Senior Product Manager: John Fisher Editorial Assistant: Kaitlin Murphy Director, Brand Management: Jason Sakos Brand Manager: Kristin McNary Director, Market Development: Debbie Yarnell For product information and technology assistance, contact us at Cengage Learning Customer & Sales Support, 1-800-354-9706 For permission to use material from this text or product, submit all requests online at www.cengage.com/permissions. Further permissions questions can be e-mailed to permissionrequest@cengage.com Market Development Manager: Erin Brennan Senior Production Director: Wendy Troeger Production Manager: Mark Bernard Content Project Manager: Barbara LeFleur Production Technology Assistant: Emily Gross Library of Congress Control Number: 2012934976 ISBN-13: 978-1-133-60729-8 ISBN-10: 1-133-60729-2 Senior Art Director: David Arsenault Technology Project Manager: Joe Pliss Delmar 5 Maxwell Drive Clifton Park, NY 12065-2919 USA Cengage Learning is a leading provider of customized learning solutions with office locations around the globe, including Singapore, the United Kingdom, Australia, Mexico, Brazil, and Japan. Locate your local office at: international.cengage.com/region Cengage Learning products are represented in Canada by Nelson Education, Ltd. To learn more about Delmar, visit www.cengage.com/delmar Purchase any of our products at your local college store or at our preferred online store www.cengagebrain.com Notice to the Reader Publisher does not warrant or guarantee any of the products described herein or perform any independent analysis in connection with any of the product information contained herein. Publisher does not assume, and expressly disclaims, any obligation to obtain and include information other than that provided to it by the manufacturer. The reader is expressly warned to consider and adopt all safety precautions that might be indicated by the activities described herein and to avoid all potential hazards. By following the instructions contained herein, the reader willingly assumes all risks in connection with such instructions. The publisher makes no representations or warranties of any kind, including but not limited to, the warranties of fitness for particular purpose or merchantability, nor are any such representations implied with respect to the material set forth herein, and the publisher takes no responsibility with respect to such material. The publisher shall not be liable for any special, consequential, or exemplary damages resulting, in whole or part, from the readers’ use of, or reliance upon, this material. Printed in the United States of America 1 2 3 4 5 6 7 16 15 14 13 12 Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. Contents Preface Chapter 1 Introduction to Microcontroller 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9 1.10 1.11 1.12 1 Objectives 1 A Brief History of the Computer 2 1.2.1 Mainframe Computers 3 1.2.2 Minicomputers 4 1.2.3 Microcomputers 4 1.2.4 Supercomputers 5 Computer Hardware Organization 6 The Processor 6 1.4.1 The Arithmetic Logic Unit (ALU) 6 1.4.2 Registers 7 1.4.3 The Control Unit 8 1.4.4 The Language Issue 8 The Microprocessor 9 The Microcontroller 10 Embedded Systems 10 1.7.1 Characteristics of Embedded Systems 11 1.7.2 User Interfaces 11 Memory 11 1.8.1 Magnetic Memory 11 1.8.2 Optical Memory 12 1.8.3 Semiconductor Memory 12 1.8.4 Nonvolatile and Volatile Memory 12 1.8.5 Random Access Memory (RAM) 12 1.8.6 Read-Only Memory (ROM) 13 Memory-System Operation 14 1.9.1 Read Operation 15 1.9.2 Write Operation 15 Program Execution 16 1.10.1 The Program Counter Circuit 16 1.10.2 Starting Program Execution 17 1.10.3 Instruction Execution Process 18 Summary 18 Exercises 20 Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. iv Contents Chapter 2 Introduction to the AVR Microcontroller 2.1 2.2 2.3 2.4 2.5 2.6 2.7 2.8 2.9 Objectives 21 An Overview of the AVR Microcontroller Family 22 The AVR Memory Space 22 The AVR CPU Register 24 2.4.1 The RAMPX, RAMPY, and RAMPZ Registers 25 2.4.2 The Extended Indirect Register (EIND) 25 2.4.3 The RAMPD Register 25 2.4.4 The Status Register (SREG) 26 The AVR Instruction Set 27 AVR Addressing Modes 27 2.6.1 Register Direct Mode 28 2.6.2 I/O Direct Mode 28 2.6.3 Direct Data Mode 28 2.6.4 Data Indirect with Displacement Mode 28 2.6.5 Data Indirect Mode 29 2.6.6 Data Indirect with Pre-Decrement 29 2.6.7 Data Indirect with Post-Increment 29 2.6.8 Program Memory Constant Addressing Using the LPM, ELPM, and SPM Instructions 30 2.6.9 Program Memory with Post-Increment Using the LPM Z+ and ELPM Z+ Instructions 30 2.6.10 Direct Addressing, JMP and CALL 30 2.6.11 Indirect Program Addressing, IJMP and ICALL 31 2.6.12 Relative Program Addressing, RJMP and RCALL 31 A Sample of AVR Instructions 31 2.7.1 The Data Transfer Instructions 31 2.7.2 Addition Instruction 35 2.7.3 Subtract Instructions 37 Summary 38 Exercises 39 Chapter 3 AVR Assembly Language Programming 3.1 3.2 3.3 21 Objectives 41 AVR Assembly Language Program Structure 3.2.1 Label Field 42 3.2.2 Operation Field 42 3.2.3 Operand Field 43 3.2.4 Comment Field 43 Expressions 43 3.3.1 Operands 43 3.3.2 Functions 44 3.3.3 Operators 44 3.3.4 Formats of Constants 45 41 42 Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. v Contents 3.4 3.5 3.6 3.7 3.8 3.9 3.10 3.11 3.12 3.13 3.14 3.15 3.16 Memory Class 46 Assembler Directives 47 3.5.1 The BYTE Directive 47 3.5.2 The CSEG Directive 48 3.5.3 The DB Directive 48 3.5.4 The DEF Directive 48 3.5.5 The DEVICE Directive 49 3.5.6 The DSEG Directive 49 3.5.7 The DW Directive 49 3.5.8 The MACRO and ENDMACRO Directives 3.5.9 The EQU Directive 50 3.5.10 The ESEG Directive 51 3.5.11 The EXIT Directive 51 3.5.12 The INCLUDE Directive 51 3.5.13 The LIST and NOLIST Directives 51 3.5.14 The LISTMAC Directive 51 3.5.15 The ORG Directive 51 3.5.16 The Set Directive 52 AVR Assembly Program Template 52 Software Development Issue 53 Writing Programs to Perform Arithmetic 55 3.8.1 The Carry/Borrow Flag 57 3.8.2 Multiprecision Addition 57 3.8.3 The C Flag and Subtraction 58 3.8.4 Multiprecision Subtraction 59 3.8.5 Multiplication and Division 59 Accessing Data in Data and Program Memory 61 Writing Program Loops 62 3.10.1 The Infinite Loop 62 3.10.2 The For-Loop 63 3.10.3 The While-Loop 65 3.10.4 The Repeat-Until Loop 67 Shift and Rotate Instructions 70 Boolean Instructions 74 Bit Manipulating Instructions 75 Create Time Delay Using Program Loops 76 Summary 77 Exercises 78 49 Chapter 4 Hardware and Software Development Tools for the AVR 81 4.1 4.2 4.3 Objectives 81 Development Tools for the Atmel AVR 82 Hardware Development Tools 82 4.3.1 Choosing a Demo Board for Learning the AVR 4.3.2 The EasyAVR M1280 Demo Boards 83 82 Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. vi Contents 4.4 4.5 4.6 4.7 4.8 4.9 4.3.3 Stingray XMega Demo Board 84 4.3.4 Arduino Demo Kits 85 4.3.5 Debug Adapters from Atmel 86 Software Development Tools 88 Using the AVR Studio IDE 88 4.5.1 Create a Project 89 4.5.2 Enter the Program 90 4.5.3 Assemble (or Build) the Project 90 4.5.5 Program Execution and Debugging 93 Tips for Assembly Program Debugging 98 4.6.1 Syntax and Semantic Errors 98 4.6.2 Logical Errors 101 4.6.3 General Debug Strategy 101 4.6.4 Common Program Logical Errors 101 Project File Structure 102 Summary 102 Lab Assignments 103 Chapter 5 Advanced Assembly Programming and Subroutine Calls 105 5.1 5.2 5.3 5.4 5.5 5.6 5.7 5.8 5.9 5.10 Objectives 105 Introduction 106 The Stack Data Structure 106 5.3.1 Initializing the Stack Pointer 107 5.3.2 Instructions for Stack Operation 107 An Example of Subroutine 108 Issues Related to Subroutine Calls 109 5.5.1 Parameter Passing 109 5.5.2 Local Variable Allocation and Deallocation 109 5.5.3 Result Returning 110 5.5.4 Accessing Local Variables in the Stack 111 5.5.5 Register Usage Issue 111 5.5.6 Instructions for Subroutine Call 111 Writing Subroutines to Perform Multiprecision Arithmetic 114 5.6.1 Writing Subroutines to Perform 16-Bit Unsigned Multiplication 114 5.6.2 Writing a Subroutine to Perform 16-bit Signed Multiplication 116 5.6.3 Writing Subroutines to Perform Unsigned Multiprecision Division 118 5.6.4 Converting an Internal Binary Number into a BCD String 120 5.6.5 Signed Division Operation 122 5.6.6 Finding the Square Root 123 5.6.7 Prime Test Subroutine 126 Subroutines with Local Variables in Stack 128 5.7.1 Subroutine to Convert a BCD String to a Binary Number 128 5.7.2 Bubble Sort 133 Summary 138 Exercises 139 Lab Assignments 140 Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. vii Contents Chapter 6 C Language Programming 6.1 6.2 6.3 6.4 6.5 6.6 6.7 6.8 6.9 6.10 143 Objectives 143 Introduction to C 144 Types, Operators, and Expressions 145 6.3.1 Data Types 145 6.3.2 Variable Declarations 145 6.3.3 Constants 146 6.3.4 Arithmetic Operators 146 6.3.5 Bitwise Operators 148 6.3.6 Relational and Logical Operators 149 6.3.7 Precedence of Operators 149 Control Flow 150 6.4.1 If Statement 150 6.4.2 If-Else Statement 151 6.4.3 Multiway Conditional Statement 151 6.4.4 Switch Statement 152 6.4.5 For-Loop Statement 152 6.4.6 While Statement 153 6.4.7 Do-While Statement 153 6.4.8 Goto Statement 153 Input and Output 154 Functions and Program Structure 155 6.6.1 Function Prototype 157 6.6.2 Writing a C Program with Multiple Functions 157 Pointers, Arrays, Structures, Unions, and Type Definition 158 6.7.1 Pointers and Addresses 158 6.7.2 Arrays 159 6.7.3 Pointers and Arrays 160 6.7.4 Passing Arrays to a Function 160 6.7.5 Initializing Arrays 161 6.7.6 Structures 161 6.7.7 Unions 163 6.7.8 The typedef Statement 163 6.7.9 Enumerated Data Types 164 Miscellaneous Items 165 6.8.1 Automatic/External/Static/Volatile 165 6.8.2 Scope Rules 165 6.8.3 Type Casting 166 6.8.4 Pointer to Functions 167 The C Preprocessor 168 6.9.1 The #define Statement 168 6.9.2 The ## Operator 169 6.9.3 The #include Statement 170 6.9.4 Conditional Compilation 171 Using the AVR Studio C Compiler 172 6.10.1 AVR Peripheral Register Naming Convention 173 6.10.2 AVR Peripheral Register Bit Naming Convention 173 Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. viii Contents 6.11 6.12 6.13 6.14 6.15 6.10.3 Accessing AVR Mega Device Peripheral Registers in C 174 6.10.4 Accessing AVR XMega Device Peripheral Registers in C 174 Using the AVR Studio IDE to Develop C Programs 177 6.11.1 Create a New Project 177 6.11.2 Entering C Programs in AVR Studio IDE 180 6.11.3 Add C Files into the Project 181 6.11.4 Compile (or Build) the Project 182 6.11.5 Execute and Debug the Project 183 Multiple-File Project 190 Summary 193 Exercises 194 Lab Assignments 195 Chapter 7 System Clock Configuration 7.1 7.2 7.3 7.4 7.5 7.6 Objectives 197 Overview of System Clock Generation 198 The Clock System of the AVR Mega Devices 198 7.3.1 Clock Sources 198 7.3.2 Default Clock Source 199 7.3.3 External Clock 200 7.3.4 Watchdog Oscillator 200 7.3.5 Low-Frequency Oscillator 200 7.3.6 Timer/Counter Oscillator 200 7.3.7 System Clock Prescaler 200 Clock System of the XMega Devices 204 7.4.1 Internal Oscillators 205 7.4.2 External Clock Sources 205 7.4.3 System Clock Selection and Prescalers 206 7.4.4 PLL Circuit 209 7.4.5 DFLL 2 MHz and DFLL 32 MHz 210 7.4.6 External Oscillator Failure Detector 213 Summary 215 Exercises 216 Chapter 8 Parallel I/O 8.1 8.2 8.3 197 217 Objectives 217 I/O Introduction to I/O PORTs 218 8.2.1 I/O Addressing Issue 218 8.2.2 I/O Synchronization 219 8.2.3 Synchronization Issue for Parallel PORTs 219 8.2.4 Synchronization Issue for Serial Interface 219 I/O Pin Driving Circuit Structure 220 8.3.1 Totem Pole 220 8.3.2 Bus Keeper 221 Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. ix Contents 8.4 8.5 8.6 8.7 8.8 8.9 8.10 8.11 8.3.3 Wired-OR 222 8.3.4 Wired-AND 222 Electrical Characteristic Consideration for I/O Interfacing 222 8.4.1 Voltage-Level Compatibility 223 8.4.2 Current Drive Capability 225 8.4.3 Timing Compatibility 226 Overview of the AVR Mega Parallel PORTs 227 8.5.1 Configuring the Mega I/O Pins 228 8.5.2 Toggling the Mega I/O Pin 228 8.5.3 Reading the Pin Value 228 8.5.4 Unconnected Pins 229 8.5.5 Alternate PORT Functions 229 Overview of AVR XMega Parallel PORTs 233 8.6.1 Setting the Direction of PORT Pins 234 8.6.2 Controlling the Output Value of PORT Pins 235 8.6.3 Reading the Logic State of PORT Pins 235 8.6.4 Pin Configuration 235 8.6.5 Multipin Configuration 237 8.6.6 Virtual PORTs 237 8.6.7 Alternate PORT Functions of XMega 239 Simple I/O Devices 239 8.7.1 Interfacing with LEDs 239 8.7.2 Interfacing with Seven-Segment Displays 242 8.7.3 Generating a Digital Waveform Using an I/O Pin 247 8.7.4 Making a Sound using an I/O Pin 248 8.7.5 Interfacing with DIP Switches 250 Interfacing with a D/A Converter 251 8.8.1 The AD7302 DAC 251 8.8.2 Interfacing the AD7302 with the AVR Mega or XMega Devices Summary 254 Exercises 254 Lab Assignments 256 Chapter 9 Interrupt Handling, Resets, and Power Management 9.1 9.2 9.3 9.4 252 259 Objectives 259 Basic Concepts on Interrupt 260 9.2.1 Why Interrupt Is Useful 260 9.2.2 Enabling and Disabling Interrupts 260 9.2.3 Prioritizing Multiple Interrupts 261 9.2.4 Servicing the Interrupt 261 9.2.5 The Interrupt Vector 261 9.2.6 Writing an Interrupt-Driven Program 262 Resets 262 The AVR Mega Interrupts 263 9.4.1 AVR Mega Device Interrupt Vectors 263 9.4.2 The Mega AVR Microcontroller Configuration Register (MCUCR) 266 Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. x Contents 9.5 9.6 9.7 9.8 9.9 9.10 9.11 9.12 9.4.3 AVR Mega External Interrupt Pins 267 9.4.4 Pin Change Interrupt 268 9.4.5 Writing Interrupt Service Routine in C for AVR Mega Devices The XMega Device Interrupts 272 9.5.1 PMIC Operation 273 9.5.2 XMega Maskable Interrupts 273 9.5.3 XMega Nonmaskable Interrupt 273 9.5.4 XMega Interrupt Level 273 9.5.5 XMega Interrupt Priority 274 9.5.6 PMIC Registers 274 9.5.7 XMega Interrupt Sources 276 9.5.8 XMega PORT Interrupt 277 AVR Mega Reset 283 AVR Mega Watchdog Timer 284 XMega Reset 286 9.8.1 XMega Brown-Out Reset 287 9.8.2 Spike Detector Reset 288 9.8.3 XMega Watchdog Timer 288 9.8.4 XMega WDT Programming 291 Power Management and Sleep Modes 293 9.9.1 Mega Sleep Modes 293 9.9.2 XMega Sleep Modes 297 Summary 300 Exercises 302 Lab Assignments 302 Chapter 10 Advanced Parallel I/O 10.1 10.2 10.3 10.4 10.5 10.6 270 305 Objectives 305 Interfacing a Parallel PORT to a Keypad 306 10.2.1 Keypad Scanning 306 10.2.2 Keyboard Debouncing 307 10.2.3 ASCII Code Lookup 309 Driving the Stepper Motor 311 10.3.1 Principles of Rotation 311 10.3.2 Discrete Stepper Motor Drivers 315 10.3.3 Integrated Stepper Motor Driver 318 Direct Memory Access (DMA) Transfer 319 10.4.1 Overview of the XMega DMA Controller 319 10.4.2 DMA Registers 319 10.4.3 DMA Channel Operation 321 Liquid Crystal Displays (LCDs) 329 The HD44780 LCD Controller 330 10.6.1 Display Data RAM 334 10.6.2 Character Generator ROM (CGROM) 334 10.6.3 Character Generator RAM (CGRAM) 334 Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. xi Contents 10.7 10.8 10.9 10.6.4 LCD Controller Registers 334 10.6.5 Instruction Description 335 10.6.6 Interfacing the HD44780 to the AVR Microcontroller 10.6.7 LCD Startup Sequence 338 10.6.8 Writing LCD Programs 339 Summary 346 Exercises 347 Lab Assignments 348 Chapter 11 Timer Functions of the Mega AVR 11.1 11.2 11.3 11.4 11.5 11.6 11.7 11.8 11.9 11.10 336 351 Objectives 351 Introduction to the Microcontroller Timer System 352 11.2.1 Using a Timer to Create Time Delays 352 11.2.2 Input Capture 352 11.2.3 Output Compare 353 11.2.4 Pulse-Width Modulation (PWM) 353 Overview of the Mega AVR Timer System 355 11.3.1 Timers Pin Assignment 355 11.3.2 8-Bit Timer Building Blocks 355 11.3.3 16-Bit Timer Building Blocks 357 Timer Clock Source Selection 357 Timer/Counter Operation Modes 360 11.5.1 8-Bit Timer/Counter Operation Modes 360 11.5.2 16-Bit Timer/Counter Operation Modes 362 Applications of Each Timer/Counter Operation Mode 366 Using the Timer Normal Mode 366 11.7.1 Using the Normal Mode in Creating Time Delays 366 11.7.2 Using the Timer Normal Mode in Waveform Generation 368 11.7.3 Using the Normal Mode to Make Sound 373 11.7.4 Using the Normal Mode to Play a Song 375 11.7.5 Using the Normal Mode to Measure Signal Frequency 381 11.7.6 Measuring Signal Period Using the Normal Mode 384 Using the CTC Mode 386 11.8.1 Using the CTC Mode to Create Time Delay 386 11.8.2 Using the CTC Mode to Generate Waveform 387 Using the Fast PWM Mode 391 11.9.1 Compare Match Pin Action in Fast PWM Mode 391 11.9.2 Using OCRnA to Hold the TOP Value 391 11.9.3 Using ICRn to Hold the TOP Value 391 11.9.4 Extreme Cases for the Fast PWM 392 Using the Phase-Correct PWM Mode 393 11.10.1 The Choice of the TOP Value 394 11.10.2 Pin Action on Compare Match in the Phase-Correct PWM Mode 394 Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. xii Contents 11.11 11.12 11.13 11.14 11.15 Using the Phase and Frequency Correct PWM Mode 396 Driving the DC Motor 397 11.12.1 DC Motor Driver ICs 398 11.12.2 Driving a DC Motor Using the SN754410 398 Summary 399 Exercises 401 Lab Assignments 402 Chapter 12 Event System and Timer Functions of XMega 12.1 12.2 12.3 12.4 12.5 12.6 12.7 12.8 12.9 12.10 12.11 Objectives 405 The XMega Event System 406 12.2.1 Signaling Events 406 12.2.2 Data Events 406 12.2.3 Manually Generating Events 407 12.2.4 Event Routing Network 407 12.2.5 Event Timing 409 12.2.6 Applications of Events 410 An Overview of the XMega Timer System 410 XMega Timer Operation and Configuration 413 12.4.1 Timer Clock Source 413 12.4.2 Timer Operation Modes 413 12.4.3 Double Buffering 414 The Normal Mode 415 12.5.1 Input Capture 416 12.5.2 General Input Capture 417 12.5.3 Frequency Capture 420 12.5.4 Pulse-Width Capture 423 12.5.5 32-Bit Input Capture 423 12.5.6 Capture Overflow 426 12.5.7 Creating Time Delays 426 The Frequency (FRQ) Waveform Generation Mode The Single-Slope PWM Generate Mode 439 The Dual-Slope PWM Mode 440 Summary 442 Exercises 443 Lab Assignments 443 405 433 Chapter 13 Universal Synchronous Asynchronous Receiver Transmitter (USART) 449 13.1 13.2 13.3 Objectives 449 Fundamental Concepts of Serial Communication 450 The TIA-232 Standard 450 13.3.1 TIA-232 Electrical Specification 450 13.3.2 TIA-232 Functional Specification 451 Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. xiii Contents 13.4 13.5 13.6 13.7 13.8 13.9 13.10 13.11 13.3.3 TIA-232 Mechanical Specification 454 13.3.4 TIA-232 Procedural Specification 455 13.3.5 Data Format 457 13.3.6 Data Transmission Errors 458 13.3.7 Null Modem Connection 459 The AVR USART 459 13.4.1 USART Signal Pin Assignment 459 13.4.2 Features of the USART Module 460 USART Baud Rate Generation 462 13.5.1 The Mega USART Baud Rate Generator 462 13.5.2 The XMega USART Baud Rate Generator 463 The USART Operation 465 13.6.1 USART Initialization 467 13.6.2 USART Data Transmission 470 13.6.3 USART Data Reception 475 Data Exchange with USART via the TIA-232 Interface 483 Terminal and Terminal Emulation 484 Summary 485 Exercises 486 Lab Assignments 488 Chapter 14 The SPI Function 14.1 14.2 14.3 14.4 14.5 14.6 14.7 14.8 14.9 491 Objectives 491 Introduction to the SPI Function 492 SPI Signal Pins 492 SPI-Related Registers 493 14.4.1 SPI Registers of Mega Devices 493 14.4.2 Registers Related to the XMega SPI Operation 494 The SPI Operation 496 14.5.1 Data Modes 496 14.5.2 SPI Circuit Connection 497 14.5.3 Configuring the SPI for Data Transfer 498 14.5.4 Writing Common SPI Data Transfer Functions 500 SPI-Compatible Chips 504 The 74HC595 Shift Register 504 The TC72 Digital Temperature Sensor 507 14.8.1 Operation of the TC72 507 14.8.2 The Temperature Data Format 508 14.8.3 The Serial Bus Interface 509 14.8.4 Internal Register Structure 509 The 12-Bit D/A Converter MCP4922 513 14.9.1 Signal Pins 514 14.9.2 Data Format 515 14.9.3 MCP4922 Output Voltage 515 14.9.4 Format Data to be Sent to the MCP4922 515 14.9.5 Interfacing the MCP4922 with the AVR 516 Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. xiv Contents 14.10 14.11 14.12 14.13 14.14 Using the USART in the SPI Mode 519 14.10.1 Clock Generation in the MSPI mode 520 14.10.2 USART Registers of Mega Devices in MSPI Mode 520 14.10.3 USART Registers of XMega Devices in the MSPI Mode 521 14.10.4 USART Module Operation in MSPI Mode 523 Interfacing the MC14489 to the USART in the MSPI Mode 527 14.11.1 The Signal Pins of MC14489 528 14.11.2 Operation of the MC14489 529 14.11.3 Cascading the MC14489s 534 Summary 538 Exercises 539 Lab Assignments 541 Chapter 15 Two-Wire Interface (TWI) 15.1 15.2 15.3 15.4 15.5 15.6 15.7 15.8 543 Objectives 543 Introduction to the Two-Wire Interface (TWI) 544 15.2.1 TWI Addressing 544 15.2.2 The TWI Signal Components 545 15.2.3 Bus Arbitration in TWI 547 15.2.4 Clock and Clock Stretching 547 15.2.5 Clock Synchronization 548 15.2.6 Handshaking 548 15.2.7 Data Transfer Format 549 The TWI of the Mega MCU 550 15.3.1 The SCL and SDA Pins 551 15.3.2 The Bit-Rate Generator Unit 551 15.3.3 The Bus Interface Unit 551 15.3.4 The Address Match Unit 552 15.3.5 The Control Unit 552 Using the Mega TWI Module 554 Mega TWI Programming using the Polling Approach 555 15.5.1 Generating the START Condition 555 15.5.2 Generating the STOP Condition 555 15.5.3 Writing Data to the TWI Bus 556 15.5.4 Read Data Byte from the TWI Bus 556 Interfacing with Serial EEPROM AT24C08B 557 15.6.1 Pin Assignment and Block Diagram of AT24C08B 15.6.2 Device Addressing of AT24C08B 557 15.6.3 The AT24C08B Write Operation 558 15.6.4 The AT24C08B Acknowledge Polling 558 15.6.5 The AT24C08B Read Operation 559 Interrupt-Driven Mega TWI Programming 565 Using the Digital Thermostat DS1631A 571 15.8.1 The DS1631A Pin Assignment 571 15.8.2 The DS1631A Functional Description 571 557 Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. xv Contents 15.9 15.10 15.11 15.12 15.13 15.14 15.8.3 DS1631A Registers 572 15.8.4 The DS1631A Operation 573 15.8.5 DS1631A Command Set 574 15.8.6 Interfacing the DS1631A with the AVR Mega MCU 574 The XMega TWI Module 589 15.9.1 The XMega TWI Bus States 589 15.9.2 XMega TWI Master Registers 590 15.9.3 The XMega TWI Master Mode Operation 593 15.9.4 The TWI Slave Mode Registers 596 15.9.5 The XMega TWI Slave Mode Operation 598 Using the XMega TWI Module 600 Using the Real-Time Clock DS1337 606 15.11.1 DS1337 Signal Functions 607 15.11.2 The DS1337 Address Map 607 15.11.3 The DS1337 Clock and Calendar 607 15.11.4 The DS1337 Special Registers 607 15.11.5 The DS1337 Alarms 609 15.11.6 Interfacing the DS1337 with the XMega128A1 610 Summary 616 Exercises 617 Lab Assignments 619 Chapter 16 Analog-to-Digital Converter 16.1 16.2 16.3 16.4 621 Objectives 621 Basics of A/D Conversion 622 16.2.1 A Data Acquisition System 622 16.2.2 Analog Voltage and Digital Code Characteristic 622 16.2.3 A/D Conversion Algorithms 623 16.2.4 Optimal Voltage Range for A/D Conversion 625 16.2.5 Scaling Circuit 626 16.2.6 Voltage Translation Circuit 627 16.2.7 Conversion Ranges 628 The Mega ADC Module 629 16.3.1 Signal Pins of Mega ADC 629 16.3.2 Prescaling and Conversion Timing of Mega ADC 632 16.3.3 Differential Channels of Mega ADC 633 16.3.4 Changing Channel or Reference Selection for Mega ADC 633 16.3.5 Mega ADC Noise Canceller 635 16.3.6 Mega ADC Conversion Result 637 The XMega ADC Module 639 16.4.1 Pipelined Architecture and Virtual Channels of XMega ADC 640 16.4.2 Input Gain Stage of XMega ADC 641 16.4.3 Input Sources of XMega ADC 643 16.4.4 Reference Voltage of XMega ADC 645 16.4.5 Conversion Result of XMega ADC 646 Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. xvi Contents 16.5 16.6 16.7 16.8 16.9 16.10 16.11 16.4.6 Result Presentation of XMega ADC 647 16.4.7 Compare Function of XMega ADC 647 16.4.8 XMega ADC Interrupts 647 16.4.9 Starting an XMega ADC Conversion 649 16.4.10 XMega ADC Clock and Conversion Timing 650 16.4.11 XMega ADC Free-Running Mode 651 16.4.12 XMega ADC Calibration 652 Interfacing with Analog Temperature Sensor TC1047A 658 Measuring Barometric Pressure 661 Measuring Relative Humidity 666 XMega Digital to Analog Converter (DAC) 669 16.8.1 Enabling XMega DAC 670 16.8.2 XMega DAC Conversion Triggering 670 16.8.3 XMega DAC Single and Dual Channel Operation 672 16.8.4 Left- and Right-Adjusted Values 673 16.8.5 XMega DAC Calibration 674 16.8.6 The XMega DAC Status 674 Summary 681 Exercises 682 Lab Assignments 685 Chapter 17 Controller Area Network (CAN) 17.1 17.2 17.3 17.4 17.5 687 Objectives 687 Overview of Controller Area Network 688 17.2.1 Layered Approach in CAN 688 17.2.2 General Characteristics of CAN 689 CAN Messages 689 17.3.1 Data Frame 690 17.3.2 Remote Frame 693 17.3.3 Error Frame 693 17.3.4 Overload Frame 694 17.3.5 Interframe Space 695 17.3.6 Message Filtering 695 17.3.7 Message Validation 696 17.3.8 Bit Stream Encoding 696 Error Handling 696 17.4.1 Bit Error 696 17.4.2 Stuff Error 696 17.4.3 CRC Error 696 17.4.4 Form Error 696 17.4.5 Acknowledgment Error 696 17.4.6 Error Signaling 696 Fault Confinement 697 17.5.1 CAN Node Status 697 17.5.2 Error Counts 697 Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. xvii Contents 17.6 17.7 17.8 17.9 17.10 17.11 17.12 17.13 17.14 17.15 17.16 17.17 CAN Message Bit Timing 697 17.6.1 Nominal Bit Time 697 17.6.2 Length of Time Segments 698 Synchronization Issue 698 17.7.1 Resynchronization Jump Width 698 17.7.2 Phase Error of an Edge 699 CAN System Configuration 699 Overview of the MCP2515 700 17.9.1 CAN Module 700 17.9.2 Control Logic 700 17.9.3 SPI Protocol 701 MCP2515 Transmit/Receive Buffers/Masks/Filters 17.10.1 Transmit Buffers 702 17.10.2 Transmit Priority 704 17.10.3 Initiating Transmission 704 17.10.4 One-Shot Mode 704 17.10.5 TXnRTS Pins 705 17.10.6 Aborting Transmission 706 Message Reception 706 17.11.1 Receive Buffers 707 17.11.2 Receive Priority 710 17.11.3 Start-of-Frame (SOF) Signal 710 17.11.4 RX0BF and RX1BF Pins 710 Message Acceptance Filters and Masks 711 17.12.1 Filter Matching 713 17.12.2 Filter Hits 713 17.12.3 Data Byte Filtering 714 Bit Timing 714 17.13.1 Oscillator Tolerance 715 17.13.2 Bit Timing Configuration 715 Modes of Operation 720 17.14.1 Configuration Mode 720 17.14.2 Sleep Mode 721 17.14.3 Listen-Only Mode 721 17.14.4 Loopback Mode 722 17.14.5 Normal Mode 722 Error Detection 722 Interrupts 723 17.16.1 Interrupt Code Bits 723 17.16.2 Transmit Interrupt 724 17.16.3 Receive Interrupt 724 17.16.4 Message Error Interrupt 724 17.16.5 Bus Activity Wake-up Interrupt 724 17.16.6 Error Interrupt 724 Oscillator 724 17.17.1 CLKOUT Pin 725 17.17.2 RESET Pin 725 702 Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. xviii Contents 17.18 17.19 17.20 17.21 17.22 17.23 Appendices 759 A B C D E F G References Glossary The SPI Interface 725 17.18.1 Reset Instruction 726 17.18.2 Read Instruction 726 17.18.3 Read RX Buffer Instruction 727 17.18.4 Write Instruction 727 17.18.5 Load TX Buffer Instruction 727 17.18.6 Request-to-Send (RTS) Instruction 728 17.18.7 Read Status Instruction 728 17.18.8 RX Status Instruction 728 17.18.9 Bit Modify Instruction 729 Physical CAN Bus Connection 729 17.19.1 The MCP2551 CAN Transceiver 730 17.19.2 Building a CAN Node Using AVR, MCP2515, and MCP2551 731 Programming the MCP2515 for Data Communications 732 17.20.1 MCP2515 Initialization 733 17.20.2 Transmit Message Frames to the MCP2515 737 17.20.3 Receive Message Frames 741 17.20.4 A Complete Program 745 Summary 753 Exercises 754 Lab Assignments 756 Summary of Atmel AVR Instruction Set 759 XMega Devices Interrupt Vector Symbolic Names 763 XMega Devices Interrupt Vector Number Symbolic Names 767 XMega Module Definitions 771 Alternate PORT Functions of XMega64A1/128A1/192A1/ 256A1/384A1 773 Music Note Frequencies 781 Example of the LCD Circuit for Mega AVR and LCD Functions 783 787 789 Index 797 Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. Preface A Brief History of AVR The 8-bit Atmel AVR architecture was initially conceived and developed by two Norwegian college students, Alf-Egil Bogen and Vegard Wollan, at the Norwegian Institute of Technology. The AVR is a modified Harvard architecture machine where programs and data are stored in separate physical memory systems that appear in different address spaces, but it has the capability to read data items from program memory, using special instructions. The AVR is a reduced instruction set (RISC) microcontroller (MCU). The AVR CPU is pipelined, and hence the majority of AVR instructions are executed in one clock cycle. The AVR CPU incorporates 32 general-purpose registers (GPR). Most of these registers can be used as operands of arithmetic and logical instructions. An arithmetic or logical instruction can only operate on a GPR or an immediate value. Only load and store instructions can access memory locations. The AVR family of microcontrollers is divided into four subgroups: • Tiny AVR • Mega AVR • Application specific AVR • XMega AVR The first three groups of AVRs share the same peripheral design but differ in the number of supported peripheral modules. These three groups can operate at a frequency up to 20 MHz. The XMega was introduced later and has peripheral modules designed differently from the other three subgroups. In addition to the peripheral modules implemented in the Mega AVR, the XMega AVR supports direct-memory-access (DMA) transfer, implements event systems for interperipheral communication, provides an on-chip digital-to-analog converter (DAC), and performs data encryption and decryption in hardware. The XMega can operate at a frequency up to 32 MHz. All four of these groups share the same instruction set. Not all instructions are implemented in all AVR devices. Since its debut in 1996, the AVR MCU has attracted many adopters because of the following reasons: • Atmel provides a free integrated development environment (IDE) AVR Studio. By installing the free WINAVR C compiler, the user has a full-blown IDE with C language support. Starting with version 5, the AVR Studio already includes the C compiler. • Inexpensive development boards are available from Atmel and third-party vendors. • The AVR MCU is easy to use. • The device is inexpensive. Today, the Atmel AVR has become one of the most popular 8-bit microcontrollers (MCUs). Many universities all over the world are teaching the AVR MCU. This text is written for learning the AVR MCU. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. xx Preface Intended Audience This book is written for two groups of readers: 1. Students in electrical and computer engineering and technology who are taking an introductory course of microprocessor interfacing. For this group of readers, this text serves as a systematic, step-by-step tutorial. 2. Senior electrical and computer engineering students and working engineers who want to incorporate the AVR in their design projects. Because this book also provides many more complicated examples, the reader can explore the possible applications of the AVR peripheral modules in their design projects. Prerequisites The author of this book has assumed that the reader has taken a course on digital logic design and has been exposed to at least one high-level language (preferably C) programming. Knowledge of digital logic design will greatly facilitate learning the AVR. Knowledge of assembly language programming is not required because one of the goals of this book is to teach AVR assembly language programming. Organization of the Book Chapter 1 gives a brief history of computing, outlines the computer hardware organization, describes the overall organization of a processor, details the characteristics of a microcontroller and embedded system, classifies memory technologies according to volatility and read/ writability, and summarizes the 8-bit, 16-bit, and 32-bit microcontroller market. Chapter 2 provides an overview of the AVR MCU family, discusses the AVR memory space and CPU registers, and examines the AVR addressing modes and a subset of the AVR instructions. Chapter 3 introduces basic assembly language programming skills such as arithmetic operations, program loops, data shifting, and time delay creation. Chapter 4 introduces development tools, recommends demo boards for learning AVR, and gives a tutorial on how to use the Atmel AVR Studio to enter, assemble, and execute the program, using a simulator or demo board. Chapter 5 describes how to write subroutines and make subroutine calls, discusses the issues related to subroutine calls, and makes recommendation on the use of registers. Chapter 6 provides a brief tutorial on C language, describes the use of the AVR Studio C to manipulate the AVR registers and bits, and provides a tutorial on using the AVR Studio to develop C programs. Chapter 7 deals with the issue of CPU clock signal generation. Chapter 8 introduces the concepts of parallel I/O; discusses electrical compatibility between integrated circuits made of different semiconductor technologies; explores the possible I/O pin configurations; and demonstrates how to use parallel I/O PORTs to drive LEDs, sevensegment displays; and DAC, and how to generate waveforms. Chapter 9 introduces the concepts of interrupts, delineates the interrupt mechanism of the Mega and XMega devices, demonstrates interrupt programming, discusses the mechanism and applications of reset and watchdog timers, and describes the AVR power management schemes. Chapter 10 presents a few more applications of parallel I/O PORTs, including keypad input, stepper motors driving, and liquid crystal display interfacing. This chapter also introduces the direct memory access method to speed up data transfers. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. Preface xxi Chapter 11 first discusses how to use timers to create a time delay, capture event arrival time, perform output compare operation, and generate waveforms using pulse-width modulation (PWM). It then gives an overview on the Mega timers and their operation modes. Finally, this chapter explores the applications of each operation mode. Chapter 12 introduces the event system that is an interperipheral communication protocol unique to XMega, provides an overview on the XMega timer system, and explores the applications of the XMega timer functions. Chapter 13 introduces the TIA-232 protocol, delineates the operation modes of the USART module of the Mega and XMega devices, and demonstrates the applications of the USART module. Chapter 14 introduces the serial peripheral interface (SPI) protocol, illustrates the SPI modules of the Mega and XMega devices, and demonstrates the applications of the SPI module. Chapter 15 introduces the I2C and TWI protocols, describes the AVR TWI module, and demonstrates how to use the TWI module to interface with the peripheral chips. Chapter 16 describes the basic structure of a data acquisition system, delineates the AVR ADC modules, and demonstrates how to use the ADC to measure physical quantities such as voltage, temperature, humidity, and barometric pressure. Chapter 17 introduces the controller area network (CAN) protocol, describes the configuration and operation modes of the CAN controller MCP2515, and demonstrates how to use the MCP2515 and an AVR MCU to build a CAN node to perform data communication. Pedagogical Features Each chapter starts with a list of objectives. Every subject is presented in a step-by-step manner. Background issues are presented before the specifics related to each AVR function are discussed. Numerous examples are then presented to demonstrate the use of each AVR peripheral function. Procedural steps and flowcharts are used to help the reader understand the program logic in most examples. Both the assembly and C languages are used to illustrate the programming of the AVR functions. Using assembly language gives students an intimate feel about the functioning of the MCU, whereas using C language yields higher productivity. The instructor can opt to use only assembly language, only C language, or both in teaching the AVR MCU. Development Tools To learn the programming and interfacing of a microcontroller, the learner needs both the software and hardware development tools. Software Development Tools The software tools that the learner needs include the text editor, cross-assembler, crosscompiler, simulator, debugger, and the device driver for the hardware debug adapter. Software vendors often put together these software programs and sell them as a package called an integrated development environment (IDE). Atmel provides a free IDE called AVR Studio to the AVR user. Before version 5, the user had to install the WINAVR C compiler in order to use the C language as his or her developing language. Starting with version 5, the C compiler became part of the IDE. Currently, the AVR Studio supports all 8-bit and 32-bit AVR MCUs. Eventually, the AVR Studio will also support the Atmel ARM microcontrollers. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. xxii Preface Hardware Development Tools The minimum hardware that a learner needs is a demo board and a programmer. The programmer connects to the host computer (usually a PC), and the demo board via a USB cable. The programmer circuit can also be built into the demo board. This way the user only needs a demo board and a USB cable. Both the demo board EasyAVR M1280 from AVRVI and the Stingray XMega from XBIT Inc. have this capability built in. However, program debugging is a difficult process. A debugger is highly desirable and consists of both the hardware and software. First of all, the microcontroller must have a debug support circuit. The AVR provides a proprietary programming debug interface called PDI that uses two dedicated pins (PDI_CLK and PDI_DATA) for the host computer to access the MCU internal resources such as registers, data memory, and program memory nonintrusively. Commands can be sent to reset the program counter, set breakpoint, step the program, run-to-cursor, read out register and memory contents, and so on, through the PDI interface. The AVR also supports the industrial standard JTAG interface that uses four pins (TMS, TCK, TDI, and TDO) to perform programming and debugging. JTAG interface is the acronym for Joint Test Action Group interface, which is the boundary-scan interface defined by the IEEE 1149.1 standard. Second, software is needed to run on the host computer that sends commands to reset the program counter, step the instruction, set the breakpoint, add program variables to the watch list, execute the program until the cursor position, and so on. This software is called a debugger and is part of the IDE. Third, a debug adapter that connects the host computer and the demo board is required. The debug adapter receives commands coming from the host computer, converts them into appropriate PDI instructions, and sends them to the MCU in serial format. Atmel provides four debug adapters (Dragon, JTAGICE3, JTAGICE mkII, and AVR ONE!) to AVR users. Dragon is the least expensive, whereas the AVR ONE! is the most expensive debug adapter. All of these debug adapters support all AVR 8-bit and 32-bit devices. Demo Boards Some of the demo boards include many I/O devices and peripheral chips, whereas other demo boards are bare kits. Some of the peripheral chips are either very small or use a package that is difficult to handle manually. If these chips are not pre-soldered on the demo board, then it will be difficult to perform the experiment. Bare kits will be cheaper. However, when the costs of all the I/O devices and peripheral chips required in learning the AVR MCU are added up, the bare kits may be much more expensive. Because the instructor may opt to teach only the Mega AVR or the XMega AVR, the learner will only need a Mega-based or an XMega-based demo board. Because the Mega MCUs were introduced a few years before the XMega MCUs, there are a lot more Mega-based demo boards than XMega-based demo boards available in the market. If the instructor wants to teach all the topics in the text, then the EasyAVR M1280 from AVRVI (enshop.avrvi.com) is the only Mega-based demo board, and the Stingray XMega from XBIT Inc. (xbitinc.com) is the only XMega-based demo board that provides all the required features. If the instructor does not plan to teach Chapter 17, which covers CAN, then more demo boards can be used. The user can find additional AVR demo boards from ebay.com by entering “Mega128” as the search key. For example, Waveshare Electronics (wvshare.com) produces quite a few Mega-based (for example, OpenM128 package B) and XMega-based (for example, EVK XA1) demo boards that are suitable for learning the Mega and XMega devices. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. xxiii Preface Complementary Material The following materials are useful in learning the AVR and are placed on the complementary CD: • The source code of all example programs in the text • The PDF files of datasheets of the Mega2560, XMegaA1, and all the peripheral chips covered in the text • Utility programs (in assembly and C languages) for time delay, system clock generation, LCD, USART, and SPI Supplements An Instructor Resource CD is available for this text (ISBN 1133608884). The elements of the instructor resource link directly to the text to provide a unified instructional system. With the instructor resource you can spend your time teaching, not preparing to teach. Features in the instructor resource include the following: • A Solution Manual with solutions to the exercises is available to instructors as a PDF file. • An Image Gallery of all the figures and tables is also available. • ExamView Test Bank: Questions of varying levels of difficulty are provided for each chapter. This versatile tool enables the instructor to manipulate the test banks to create original tests. • Chapter Presentations in PowerPoint: These slides provide the basis for a lecture outline to present concepts and material. Key points and concepts can be graphically highlighted for student retention. Professors can request a copy of the instructor resource from their sales representatives. These files are also available through an instructor companion website. Feedback and Update The author has tried his best to eliminate errors from this text. However, it is impossible to get rid of all of the errors. The solutions in the examples of this book may not be the best either. Error reports and suggestions are welcomed. Please send them to han-way.huang@mnsu.edu. Acknowledgments This book would not have been possible without the help of a number of people. I would like to thank the following reviewers who provided valuable opinions on how to improve the quality of this book: Rabah Aoufi DeVry, Irving, Texas Christopher Cischke, Michigan Technological University Fanourios Halkiadakis, CalState Polytechnic University, Pomona, California Max Rabiee, University of Cincinnati, Cincinnati, Ohio Roman Stembrok, San Diego, California Ron Tinckham, Santa Fe College, Gainesville, Florida Hanqi Zhuang, Florida Atlantic University, Boca Raton, Florida Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. xxiv Preface I would also like to thank Stacy Masucci, acquisitions editor, and John Fisher, senior product manager, of Cengage Learning for their enthusiastic support during the preparation of this book, and the Cengage Learning staff for their outstanding production work. I would like to express my heartfelt appreciation to my students and colleagues at the Department of ECET at Minnesota State University, Mankato, who allowed me to test out the manuscript. Finally, I would like to express my thanks to my wife, Su-Jane, and my sons, Craig and Derek, for their encouragement and support during the entire preparation of this book. Han-Way Huang Mankato, Minnesota March 1, 2012 Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 1 Introduction to Microcontroller 1.1 Objectives After completing this chapter, you will be able to • Describe the characteristics of a mainframe computer. • • • • • • Describe the characteristics of a minicomputer. Describe the characteristics of a microcomputer. Describe the characteristics of a supercomputer. Describe the characteristics of a microprocessor. Describe the characteristics of a microcontroller. Describe the characteristics of an embedded system. • Explain the structure of a computer hardware. • Explain the memory technologies. • Explain the structure of an ALU that performs ADD, SUB, AND, and OR operations. • Explain the instruction execution process. • Understand the 8-bit, 16-bit, and 32-bit microcontroller markets. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 2 Chapter 1 ■ Introduction to Microcontroller 1.2 A Brief History of the Computer The word computer first appeared in 1613 [1]. It refers to a person who performs the task of computation, or calculation. At the end of the nineteenth century, the meaning of the word changed so that it no longer refers to a person but instead to a machine that carries out the task of calculation. A computer consists of hardware and software. The computer hardware implements the binary digital logic that performs the desired computation. The binary digital logic was invented by Claude Shannon in 1937. Boolean algebra provides the theoretical foundation for the binary digital logic. The subjects of binary digital logic and Boolean algebra are covered in many textbooks [2,3,4] on digital logic design. The smallest unit of information manipulated by the computer is referred to as a bit, which represents on or off, open or closed, or 1 or 0. A group of 8 bits is referred to as a byte; a group of bytes (either 2 or 4) is referred to as a word; and a group of 64 bits is referred to as a double word. The relationship among a bit, a byte, a word, and a double word is illustrated in Figure 1.1, where a bit is represented by a rectangle; a byte is represented by eight rectangles; a word is represented by 32 rectangles; and a double word is represented by 64 rectangles. The number above a rectangle refers to the bit number, or the bit position, within a byte, a word, or a double word. Within a byte, the bits are numbered from 7 down to 0. Within a double word, the bits are numbered from 63 down to 0. A bit with a higher bit number is more significant than a bit with a lower bit number. 0 7 6 5 4 3 2 1 0 Byte 31 30 29 28 27 26 25 24 7 6 5 4 3 2 1 0 Word 63 62 61 60 59 58 57 56 31 30 29 28 27 26 25 24 7 6 5 4 3 2 1 0 Double word Figure 1.1 ■ Source: Atmel Corporation, The Atmel AVR Microcontroller Bit Relative sizes of a bit, byte, word, and double word The defining feature of modern computers that distinguishes them from other machines is their programmability. The hardware of a modern computer consists of processor, input devices, output devices, and memory. The processor carries out all the computations. It is designed to execute a set of instructions. An instruction is simply a group of bits that tells the computer what operation to perform. The operands are also specified in the instruction (using addressing modes). An instruction may perform the operation of addition, subtraction, multiplication, division, AND, OR, shift left, shift right, and so on. A program is a sequence of selected instructions that performs certain tasks such as finding the square root of an integral number or measuring the frequency of an unknown signal. By providing different programs to the computer, the same computer can perform different operations. In early computers, programming was performed by changing wires and switches. This proved to be a difficult task. Starting in 1940s, the stored program architecture was adopted to provide programmability to the computer. The program is stored in memory, as are the data to be manipulated by the program. Because this design was first proposed by John von Neumann in 1945, the stored Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 1.2 ■ 3 A Brief History of the Computer Memory Control unit Arithmetic logic unit (ALU) Input Figure 1.2 ■ Central processing unit (CPU) Output Source: Atmel Corporation, The Atmel AVR Microcontroller program architecture is also called von Neumann Architecture. The outline of this architecture is shown in Figure 1.2. The von Neumann Architecture has a processing unit and a single storage structure that holds both instructions and data. The combination of control unit and the arithmetic logic unit is referred to as the central processing unit (CPU) or simply the processor. A deviation from the von Neumann Architecture is the Harvard Architecture, in which program and data are stored in different memories. The Harvard Architecture allows the computer to access program and data simultaneously. von Neumann architecture The maximum number of bits that can be operated on by the ALU in one operation is referred to as the word length of the processor. A processor may be called 8-bit, 16-bit, 32-bit, or 64-bit because it can operate on 8-bit, 16-bit, 32-bit, or 64-bit operands in one operation, respectively. 1.2.1 Mainframe Computers The earliest digital computers are made of vacuum tubes and were housed in enormous, room-sized metal boxes or frames. Due to their huge size, they are called mainframe computers. Mainframe computers are expensive, and only large companies and organizations can afford them. Later on, the term was used to distinguish high-end commercial computers from less powerful ones. A mainframe computer has a lot of storage serving simultaneously many users through terminal stations. The CPU time of the mainframe is divided into slots, with each time slot assigned to one user. The mainframe computer market is dominated by the IBM System 360–compatible product line. The IBM System 360 product line was introduced in 1965. It allowed the users to start with a small system and later on upgrade by adding more memory and faster CPU when their needs grew. The IBM System 360 was considered one of the most successful computers in history. In 1970, the IBM System 370 family was introduced as the replacement of System 360. System 370 was backward software compatible to the System 360; that is, all the programs written for System 360 can also be executed by the System 370. The System 390 was introduced to take the place of System 370. The latest IBM mainframe family (as of December 2011) is the system z, which is also software compatible with the earliest System 360. In addition to a fast CPU, a mainframe has the following features: 1. High reliability and security is provided by the redundant design. 2. There are extensive input/output facilities. 3. It has strict backward compatibility with older software; a newer generation of machines can run software written for older machines. This feature is extremely important for a computer family to be successful in the market. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 4 Chapter 1 ■ Introduction to Microcontroller 4. The high utilization rate supports massive throughput. 5. Repairs and hardware upgrades take place during normal operation. 1.2.2 Minicomputers Minicomputers, called mini because they are smaller than mainframe computers, appeared in the 1960s. The small size of these computers is made possible by the use of transistors, core memory, and the integrated circuit. Minicomputers usually took up one or a few cabinets the size of a large refrigerator. The first successful minicomputer was Digital Equipment Corporation’s (DEC) 12-bit PDP-8 introduced in 1964. Other minicomputer vendors include Prime, Data General, Wang Laboratory, Apollo Computer, and HP. The off-the-shelf 7400 series digital logic integrated circuits started appearing in minicomputers in the later 1960s. These chips provide many functions useful in a computer and greatly simplify the design and implementation of minicomputers. Starting in the 1980s, many minicomputers used very large-scale integration (VLSI) circuits. Many minicomputers in this period were 32-bit and hence were called superminicomputers. Minicomputers have decent processing power and capacity and hence satisfy the computation needs of many midsize organizations. Like mainframe computers, minicomputers supported multi-users. DEC was the leading minicomputer manufacturer. At one time, DEC was the second largest computer company after IBM. The PDP-11 and VAX-11 families of minicomputers from DEC were very popular in the 1970s and 1980s but started to decline in the late 1980s. Today, all of the minicomputer manufacturers have disappeared from the computer market due to the competition of personal computers (PC) and servers. A server is a computer that provides database access, file access, printing, email, web browsing services and so on to users of other computers in the network. 1.2.3 Microcomputers A microcomputer is a computer that uses a microprocessor as its central processing unit. The microprocessor is explained in a later section. The first batch of microcomputers appeared in the 1970s. Some of them were sold as kits to be assembled by the user and came with as little as 256 bytes of memory and no input/output (I/O) devices other than indicator lights and switches. As microprocessors and semiconductor memory became less expensive in the mid1970s, microcomputers in turn grew faster and cheaper. This resulted in an explosion in their popularity during the later 1970s and 1980s. Companies such as Cromemco, Altos, and others have been very successful in producing systems designed for a resourceful end user or consulting firms to deliver business applications such as accounting, database management, and word processing to small businesses. Some of these microcomputers are single-user systems, whereas others are multi-user systems. The Apple II computer, introduced in 1977 by Apple, has become one of the most successful computers in the world. Due to its popularity, many clones have appeared. Unlike earlier microcomputers, the Apple II was designed to target individual users. For this reason, the Apple II was called a personal computer instead of a microcomputer. The introduction of Apple II attracted the attention of many software developers. The Macintosh (often called MAC) introduced in 1984 was the successor of Apple II. The MAC has gone through several generations and used several different microprocessors as its CPU. Today’s MAC has several versions that cover desktop, laptop, and all-in-one categories. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 1.2 ■ A Brief History of the Computer 5 The first IBM PC was introduced in 1981 and used the 8-bit microprocessor 8088 from Intel as its CPU. In order to bring the product to market quickly, the IBM PC was designed to use off-the-shelf components and hence was easy to clone. The IBM PC was a big success after its introduction. The success of the IBM PC was the impetus for many compatibles. All these compatibles were sold at a lower price and had more features than the true IBM PC. Before long, there were more PC compatibles sold than true IBM PCs. In general, these IBM PC compatibles were also sold at a much lower price than the MAC from Apple. As a result, the PC market was dominated by the IBM compatibles. Today, the word PC has been used to refer to the IBM PC compatibles, and IBM has been forced out of the PC business (IBM sold its PC division to Lenovo in December 2004). 1.2.4 Supercomputers A supercomputer is a computer with its speed of computation at the frontline. Control Data Corporation (CDC) introduced the first commercial supercomputers in the 1960s. These supercomputers were designed by Seymour Cray and dominated the market into the 1970s, until Cray left CDC to form his own company, Cray Research. He then took over the supercomputer market with his new designs, holding the top spot for five years (1985–1990). In the 1980s, a large number of smaller competitors entered the supercomputer market, but most of them disappeared in the supercomputer market crash. Today, the U.S. supercomputer market is dominated by traditional companies such as Cray, HP, and IBM. The fastest supercomputer in the world has changed position several times in the past. This situation will remain the same in the future. Supercomputers are used for calculation-intensive tasks such as problems involving weather forecasting, climate research, quantum mechanics physics, molecular modeling (calculating the structures and properties of chemical compounds, biological macromolecules, polymers, and crystals), physical simulations (such as simulations of airplanes in wind tunnels, simulation of the detonation of nuclear weapons, and research into nuclear fusion), cryptanalysis, and many others. Major universities, military agencies, and scientific research laboratories are the main users of supercomputers. Some supercomputers were designed using custom CPUs in order to gain speed over conventional computers through the use of innovative designs that allow them to perform many tasks in parallel. They tend to be specialized for certain types of operations, usually numerical calculations, and perform poorly at more general tasks of calculation. The memory system of supercomputers is carefully designed to ensure that the processor is kept fed with data and instructions at all times. In fact, much of the performance difference between slower computers and supercomputers is due to the memory bandwidth. The I/O systems of supercomputers are also designed to support high bandwidth, with latency being less of an issue because supercomputers are not used in business transaction processing. In the 1960s, the supercomputers only ran instructions much faster than other types of computers. In the 1970s, most supercomputers were vector processors in which one instruction could operate on multiple data items. The early and mid-1980s saw machines with a modest number of vector processors working in parallel become the standard. Typically, the number of processors ranged from four to sixteen. In the late 1980s and 1990s, attention turned from vector processors to massively parallel processing systems. These supercomputers were made of thousands of either off-the-shelf ordinary commercial microprocessors (those from Intel or AMD) or custom microprocessors. These microprocessors are grouped into clusters and connected using custom interconnects. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 6 Chapter 1 ■ Introduction to Microcontroller 1.3 Computer Hardware Organization A computer consists of hardware and software. The hardware of a computer contains the processor, input devices, output devices, and memory. These parts are interconnected by buses made of groups of conducting wires. Inside each of these parts are thousands to trillions of small electronic circuits that are turned on or off by means of an electronic switch. Each circuit represents a bit of information so that when the circuit is on, it represents a 1, and when off, it represents a 0 (in positive logic representation). The circuits are arranged in logic gates so that one or more of the circuits may control the state of one or more of the other circuits. • Processor. The processor is responsible for performing all of the computational operations and coordinating the usage of a computer’s resources. A computer system may consist of one or multiple processors. A processor may perform general-purpose computations or special-purpose operations, such as graphics rendering, printing, or network accessing. • Input devices. A computer is designed to execute programs that manipulate certain data. Input devices are needed to enter the program to be executed and data to be processed into the computer. There are a wide variety of input devices: keyboards, keypads, scanners, bar code readers, sensors, and so on. • Output devices. Whether the user uses the computer to perform computations or to find information from the Internet or a database, the end results must be displayed or printed on paper so that the user can see them. There are many media and devices that are used to display information: cathode-ray-tube (CRT) displays, flat-panel liquid crystal displays (LCD), seven-segment displays, light-emitting diode (LED), and so on. • Memory devices. Users write programs to tell the computer what to do with the data at hand. Programs to be executed and data to be processed must be stored in memory devices so that the processor can readily access them. 1.4 The Processor The processor is also referred to as the central processing unit (CPU). A processor consists of three major components: arithmetic logic unit (ALU), control unit, and registers. Early CPUs were composed of many separate components but since the mid-1970s CPUs have typically been constructed on a single integrated circuit (IC) called a microprocessor. 1.4.1 The Arithmetic Logic Unit (ALU) The ALU is designed to perform two classes of operations: arithmetic and logic. The set of arithmetic operations that a particular ALU supports may be limited to addition and subtraction or might include multiplication or dividing, trigonometry functions (sine, cosine, etc.), and square roots. Some only operate on whole numbers (integers), whereas others operate on real numbers represented in floating-point format. However, any computer that performs even the simplest operations can be programmed to break down the more complex operations into simple steps that it can perform. Therefore, any computer can be programmed to perform any arithmetic operation—although it takes more time to do so if its ALU does not directly support the operation. An ALU may also compare two numbers and return Boolean truth values (true or false) depending on whether one is equal to, greater than, or less than the other. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 1.4 ■ 7 The Processor Logic operations involve Boolean logic: AND, OR, XOR, and NOT. These are useful both for creating complicated conditional statements and processing Boolean logic. A computer may contain multiple ALUs so that it can execute several instructions at the same time. The complexity of the ALU varies from one computer to another. If the processor designer wants to implement more operations directly in the hardware, then the ALU gets more complicated. An ALU that implements addition, subtraction, AND, and OR operation is illustrated in Figure 1.2. The four-operation ALU operates in the following manner: 1. When opcode = 00, the adder selects the n-bit A as it’s X input, the n-bit B as its Y input, and CIN as its carry input (ci), and generates SUM and Carry as its outputs. MUX3 selects SUM to become Result, whereas Carry is connected to Cout directly. For this opcode, the ALU performs the ADD operation. 2. When opcode = 01, the comparator output is 1, and the inversion of B input (change 0 to 1 and 1 to 0) is selected as the Y input. Then 1 is selected as the ci input to the adder. The adder essentially adds the two’s complement of B to A, which is equivalent to performing the SUB operation. Because opcode is 01 and SUM is connected to both the 00 and 01 inputs, it is selected and sent to Result. For this opcode, the ALU performs the SUB operation. 3. When opcode = 10, the MUX3 multiplexer selects the value connected to the 10 input and sends it to Result. Therefore, the ALU performs the AND operation. 4. When opcode = 11, the MUX3 multiplexer selects the value connected to the 11 input and sends it to Result. Therefore, the ALU performs the OR operation. An ALU that performs more operations can be implemented by expanding the circuit shown in Figure 1.3. B n OpCode CIN 1 0 1 MUX1 0 1 MUX2 Comparator ci Y X Adder Inverters n 01 SUM 00 Carry Cout AND OR ■ n 10 n MUX3 01 Figure 1.3 Opcode 00 = ADD 01 = SUB 10 = AND 11 = OR 2 n Result 11 Source: Atmel Corporation, The Atmel AVR Microcontroller A n An ALU that implements ADD, SUB, AND, and OR operations 1.4.2 Registers The operands to be operated by instructions are stored in memory. However, memory is usually slower than the CPU. To speed up the CPU operation, a small set of high-speed memory Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 8 Chapter 1 ■ Introduction to Microcontroller circuits are included in the CPU to hold operands to be used by instructions. These high-speed memory circuits are called registers. The number of registers varies greatly from processor to processor. Some processors add a special register called an accumulator and include it as one of the operands for most instructions. This approach can shorten the machine instructions. A processor that has one or more accumulators is called an accumulator machine. Other processors, however, may include many general-purpose data registers (16 or 32) in the CPU and allow any data register to be used as any operand of most instructions with two or three operands. This provides great freedom to the compiler during the program translation process. A processor designed with this approach is considered to be orthogonal. 1.4.3 The Control Unit The computer is designed to execute machine instruction only. A machine instruction is a combination of 0s and 1s that instructs the CPU what operation to perform and what operands to work on. The control units reads and interprets (decodes) the program instructions, transforming them into a series of control signals which activate other parts of the computer. Because computer programs consist of many instructions (stored in memory), the processor has to keep track of the location in memory of the next instruction to be executed, using a special register called a program counter (PC). Whenever the processor fetches an instruction from memory, the program counter is incremented by the length of that instruction so that it points to the next instruction. The fetched instruction is placed in a circuit called the instruction register (IR), decoded, and then executed. To make the instruction execution time predictable, a clock signal is used to synchronize and set the pace of instruction execution. A clock signal is also needed to control the access to registers in the processor and external memory. The clock frequencies of the 8-bit and 16-bit microcontrollers range from a few MHz to over 100 MHz. A program normally is not sequential. The execution order of machine instructions may be changed due to the need to execute instructions on the basis of the value of a certain condition or to repeat a group of instructions. This is called program flow control. The decision to change program flow is often based on certain conditions, for example, whether the previous instruction caused carry out to be 1, whether the result of the previous operation is zero, or whether the result of the previous operation is negative. These conditions are often collected in a status register so that they can be used to make decisions. This type of program flow change is implemented by a conditional branch instruction (also called a conditional jump instruction). There is a limit to the distance that the processor can branch (or jump) conditionally. The branch distance (referred to as branch offset or jump offset) is from –128 to 127 bytes for most 8-bit microcontrollers, because they use 8 bits to specify the branch offset. In other situations, the programmer wants to force the processor to execute instruction in any location within the available memory space. A jump instruction is used for this purpose. The jump target may be specified in 16 bits, 21 bits, 32 bits, or 64 bits, depending on the width of the program counter. 1.4.4 The Language Issue Because computers are designed to execute machine instructions only, the earliest programmers were forced to write programs directly in machine language. It is easy to figure out that writing programs in machine language is extremely difficult and unproductive. The first logical improvement to this difficulty is to use a mnemonic name to represent each machine instruction and write programs directly using the mnemonic names. The mnemonic name of a machine instruction is called an assembly instruction. The complete set of mnemonic names is called the assembly language, and a program written in assembly language is called an assembly program. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 1.5 ■ 9 The Microprocessor Machine instruction Machine instruction Operation 0000 1100 0001 0000 add r1, r0 r1 ← r1 + r0 0010 0000 0010 0011 and r2, r3 r2 ← r2 AND r3 0010 1011 0000 0010 or r16, r18 r16 ← r16 OR r18 1001 0100 0000 1010 dec r0 r0 ← r0 – 1 0010 1100 0100 1010 mov r4, r10 r4 ← r10 0001 1010 1010 0000 sub r10, r16 r10 ← r10 – r16 Source: Atmel Corporation, The Atmel AVR Microcontroller Table 1.1 ■ A sample of AVR machine and assembly instructions A sample of the AVR machine and assembly instructions is given in Table 1.1. Because the computer cannot execute an assembly program directly, a translator is needed to translate the assembly program into machine instructions. The translator of the assembly program is called an assembler. A program written in assembly language is not hard to understand. However, assembly language is still at a very low level. When the problem at hand is complicated, writing programs in assembly language could be overwhelming. High-level languages were invented to overcome the shortcoming of the assembly language. Over the years, FORTRAN, COBOL, ALGOL, PASCAL, BASIC, C, C++, JAVA, and many other high-level languages were invented. These high-level languages improve the programmers’ productivity dramatically. A translator is needed to translate a program written in a high-level language into machine instructions before the program can be executed on the computer. The translator of a highlevel language is called either a compiler or an interpreter. A compiler translates the program into machines instructions, whereas an interpreter performs the operation specified by the program directly. The programs written in assembly and high-level languages are also called source code. 1.5 The Microprocessor The earlier processors may be implemented in one or multiple printed circuit boards. With the advent of integrated circuit technology, a complete processor can be implemented in one integrated circuit (an integrated circuit often is called a chip). A microprocessor is a processor implemented in a single integrated circuit. In 1971, the first microprocessors (Intel 4004 and TI TMS 1000) were introduced. Both the Intel 4004 and TI TMS 1000 are 4-bit microprocessors. In 1972, Intel introduced the 8008, which is the first 8-bit microprocessor in the world. Several other 8-bit microprocessors were introduced after the Intel 8008, including the Intel 8080, Zilog Z80, Motorola 6800, and so on. Microprocessors quickly were used as the controller of many products. Because of their small size (compared to discrete logic), programmability, ease-of-use, and low cost, microprocessors were well received and quickly replaced discrete logic devices. However, the microprocessor still has a few disadvantages: 1. It does not have on-chip memory. The designer has to add external memory chips and other “glue” logic circuits, such as decoder and buffer chips, to provide program and data storage. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 10 Chapter 1 ■ Introduction to Microcontroller 2. The microprocessor cannot drive the I/O devices directly because the microprocessor may not have enough current to drive the I/O devices or because of the incompatibility in voltage levels between the microprocessor and I/O devices. This problem is solved by adding peripheral chips as a buffer between the microcontroller and the I/O devices. The Intel 8255 parallel interface chip is one of the earliest interface chips. 3. The microprocessor does not have peripheral functions, such as timers, analog-todigital (A/D) converters, communication interfaces, and so on. These functions must be implemented using external chips. Because of these limitations, a product designed with microprocessors cannot be made as compact as might be desired. One of the design goals of microcontrollers is to eliminate these problems. 1.6 The Microcontroller A microcontroller (MCU) incorporates the processor and one or more of the following modules in one very large-scale integrated (VLSI) circuit: • • • • • • • • • Memory Timer functions Serial communication interfaces, such as USART, SPI, I2C, and CAN Analog-to-digital (A/D) converter Digital-to-analog (D/A) converter Direct memory access (DMA) controller Parallel I/O interface (equivalent to the function of the Intel 8255) Memory-component interface circuitry Software-debugging support hardware Most of these functions or modules need more explanation. However, the discussion of these functions is the subject of this textbook. Since their introduction, MCUs have been used in almost every application that requires a certain amount of intelligence. They are used as controllers for displays, printers, keyboards, modems, charge-card phones, palm-top computers, and home appliances (such as refrigerators, washing machines, and microwave ovens). They also are used to control the operations of engines and machines in factories. One of the most important applications of MCUs is probably the automobile control. A contemporary luxurious car may use more than 100 MCUs. Today, most homes have one or more MCU-controlled electronic appliance. 1.7 Embedded Systems An embedded system is a special-purpose computer system designed to perform a dedicated function. Unlike a general-purpose computer (such as a personal computer), an embedded system performs one or a few predefined tasks (usually with very specific requirements) and often includes task-specific hardware and mechanical parts not usually found in a general-purpose computer. Because the system is dedicated to specific tasks, design engineers can optimize it, reducing the size and cost of the product. Embedded systems are often mass-produced, benefiting from the economy of scale. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 1.8 ■ Memory 11 Physically, embedded systems range from portable devices (such as digital watches and MP3 players) to large stationary installations (like traffic lights, factory controllers, or the systems that control power plants). In terms of complexity, embedded systems run from simple (with a single microcontroller chip) to very complex (with multiple units, peripherals, and networks mounted inside a large chassis or enclosure). Mobile phones or handheld computers share some elements with embedded systems (such as the operating systems and microprocessors which power them) but are not truly embedded systems themselves, because they tend to be more general purpose, allowing different applications to be loaded and peripherals to be connected to them. 1.7.1 Characteristics of Embedded Systems Embedded systems have the following characteristics: • Embedded systems are designed to perform a specific task, rather than being a general-purpose computer for multiple tasks. Some also have real-time performance constraints that must be met for reasons such as safety and usability; others may have low or no performance requirements, allowing the system hardware to be simplified to reduce costs. • An embedded system is not always a separate block—very often it is physically built into the device it is controlling. • The software written for embedded systems is called firmware and is stored in read-only memory or flash memory chips rather than a disk drive. It often runs with limited computer-hardware resources: small or no keyboard, small screen, and little memory. 1.7.2 User Interfaces Embedded systems range from having no interface at all—dedicated to only one task—to full user interfaces similar to desktop operating systems in devices such as PDAs. A simple, embedded system may use buttons for input and use LEDs or a small characteronly display for output. A simple menu system may be provided for users to interface with. A more complex system may use a full graphical screen that has touch sensing or screenedge buttons to provide flexibility while minimizing space. The function of the buttons changes with the screen. Handheld systems often have a screen with a “joystick button” for a pointing device. The rise of the World Wide Web has given embedded designers another option: providing a Web page interface over a network connection. This avoids the cost of a sophisticated display yet provides complex input and display capabilities when needed on another computer. Network routers take advantage of this ability. 1.8 Memory There are three major memory technologies in use today: magnetic, optic, and semiconductor. 1.8.1 Magnetic Memory The magnetic drum, magnetic tape, and magnetic hard disk are three major magnetic memory devices that have been invented. The magnetic drum has long been obsolete, and magnetic tape is only used for data archival. Currently, only the magnetic hard disk still is being used Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 12 Chapter 1 ■ Introduction to Microcontroller in almost every PC, workstation server, mainframe computer, and supercomputer. Hard-drive vendors are still vigorously improving the hard disk density. It doesn’t seem possible that any memory technology can totally replace the hard disk yet. 1.8.2 Optical Memory There are two major optical memory technologies in use today: compact disc (CD) and digital video disc (DVD). The CD was introduced to the market in 1982 and has several variations. The most popular single-sided CD has a 12 cm diameter and holds about 700 MB of data. The CD-R version of the compact disc can be recorded once, whereas the CD-RW disc can be re-recorded many times. In 1993, two DVD storage formats were being developed. At the end of 1995, a unified DVD format was finalized. A single-sided DVD with 12 cm diameter holds 4.7 GB of data. There are several versions of DVD—among them, the DVD-R that can be recorded only once, and the DVD-RW, which the end user can re-record many times. In 2006, a new format called the Blu-ray Disc, designed by Sony, Philips, and Panasonic, was released as the successor to DVD. A dual layer Blu-ray Disc stores 50 GB of information. 1.8.3 Semiconductor Memory Semiconductor memory is the dominant memory technology used in embedded systems. Memory technologies are classified according to several criteria. Two common criteria are volatility and read-writability. Based on volatility, semiconductor memories are divided into volatile and nonvolatile memories. Based on read-writability, semiconductor memories are divided into random access memory (RAM) and read-only memory (ROM). 1.8.4 Nonvolatile and Volatile Memory A memory device is nonvolatile if it does not lose the information stored in it even without the presence of power. If a memory device cannot retain its stored information in the absence of power, then it is volatile. 1.8.5 Random Access Memory (RAM) RAM allows the CPU to read from or write into any location within the chip for roughly the same amount of time. RAM can be volatile or nonvolatile. RAM also is called read–write memory, because it allows the processor to read from and write into it. As long as the power is on, the processor can write data into a location in the RAM chip and later read back the same contents. Reading memory is nondestructive. Writing memory is destructive. When the processor writes data to memory, the old data is written over and destroyed. There are four types of commercially available RAM technology: dynamic RAM (DRAM), static RAM (SRAM), magnetoresistive RAM (MRAM), and ferroelectric RAM (FRAM). DRAMs are memory devices that require a periodic refresh of the stored information. Refresh is the process of restoring binary data stored in a particular memory location. The DRAM uses one transistor and one capacitor to store 1 bit of information. The information is stored in the capacitor in the form of electric charges. The charges stored in the capacitor leaks away over time, so a periodic refresh operation is needed to maintain the contents in the DRAM. The time interval over which each memory location of a DRAM chip must be refreshed at least once in order to maintain its contents is called its refresh period. Refresh periods typically range from a few milliseconds to over a hundred milliseconds for today’s highdensity DRAMs. SRAMs are designed to store binary information without needing periodic refreshes and require the use of more complicated circuitry for each bit. Four to six transistors are needed to store 1 bit of information. As long as power is stable, the information stored in the SRAM will not be degraded. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 1.8 ■ Memory 13 MRAMs were first developed by IBM. Several other companies also were involved in the research, development, and marketing of this technology. MRAMs use a magnetic moment to store data. An MRAM chip combines a magnetic device with standard silicon-based microelectronics to achieve the combined attributes of nonvolatility, high-speed operation, and unlimited read and write endurance. The first MRAM device from Freescale is the 4 Mbit MR2A16A. This device is a parallel memory (8 or 16 bits are accessed in one operation) and has a 35 ns access time (reported in 2006). In 2008, Freescale joined with several venture capital companies to form a company called Everspin to research and produce the MRAM product. The MRAM technology has good potential. Research teams from IBM and Germany have demonstrated the MRAM devices with a 1 ns access time. To realize this access time would require the most advanced semiconductor technology to be used (possibly 60 nm process or less). FRAMs use the property of ferroelectric crystal to store data bits. Much of the present FRAM technology was developed by Ramtron International. The FRAM technology has already achieved high maturity. Both the serial and parallel versions of FRAM chips are available. Ramtron even incorporates FRAM in some of its 8051 microcontroller products. At the time of this writing, the fastest access time of FRAM from Ramtron is 55 ns (reported in 2009). However, the access time of FRAM may improve over time in the future. RAMs are mainly used to store dynamic programs or data. A computer user often wants to run different programs on the same computer, and these programs usually operate on different sets of data. The programs and data must therefore be loaded into RAMs from the hard disk or other secondary storage, and for this reason they are called dynamic. 1.8.6 Read-Only Memory (ROM) The ROM is nonvolatile. When power is removed from the ROM and then reapplied, the original data is still there. As its name implies, ROM data only can be read. If the processor attempts to write data to a ROM location, the ROM does not accept the data, and the data in the addressed ROM memory location are not changed. However, this statement is not completely true. For some ROM technologies (EEPROM and flash memory), the user program can still write data into the memory by following a special procedure prescribed by the manufacturer. The mask-programmed read-only memory (MROM) is a type of ROM that is programmed when it is manufactured. The semiconductor manufacturer places binary data in the memory according to the request of the customer. To be cost-effective, many thousands of MROM memory units—each consisting of a copy of the same data (or program)—must be sold. MROM is the major memory technology used to hold microcontroller application programs and constant data. Most people simply refer to MROM as ROM. The design of MROM prevents it from being written into. The programmable read-only memory (PROM) was invented in 1956 by Wen Tsing Chow. It is a form of memory where the setting of each bit is locked by a fuse or antifuse. The memory can be programmed just once after manufacturing by “blowing” the fuses (using a PROM blower), which is an irreversible process. Blowing a fuse opens a connection, whereas blowing an antifuse closes a connection (hence the name). Programming is done by applying high-voltage pulses that are not encountered during normal operation (typically 12 to 21 volts). Fused-based PROM technology is no longer used today. The erasable programmable read-only memory (EPROM) was invented by Dov Frohman in 1971. It is an array of floating-gate transistors individually programmed by an electronic device that supplies higher voltages than those normally used in electronic circuits. Programming is achieved via hot carrier injection onto the floating gate. Once programmed, an EPROM can be erased only by exposing it to strong ultraviolet (UV) light. That UV light usually has a Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 14 Chapter 1 ■ Introduction to Microcontroller wavelength of 235 nm for optimum erasure time. EPROMs are recognizable by the transparent fuse-quartz window in the top of the package, through which the silicon chip can be seen and which permits UV light to go through during erasing. As the quartz window is expensive to make, one-time programmable (OTP) EPROM chips were introduced; the only difference is that the EPROM chip is packed in an opaque package, so it cannot be erased after programming. OTP versions are manufactured for both EPROMs themselves and EPROM-based microcontrollers. However, the OTP EPROM (whether separate or part of a larger chip) is being increasingly replaced by EEPROM for small amounts where the cell cost isn’t too important and flash memory for larger amounts. A programmed EPROM chip retains its data for about 10 to 20 years and can be read an unlimited number of times. The erasing window must be kept covered with a foil label to prevent accidental erasure by any type of light in the UV spectrum. Old PC basic input/ output system (BIOS) chips were often EPROMs, and the erasing window often was covered with a label containing the BIOS publisher’s name, the BIOS revision, and a copyright notice. The electrically erasable programmable read-only memory (EEPROM) was developed in 1983 by George Perlegos at Intel. It was built on earlier EPROM technology but used a thingate oxide layer so that the chip could erase its own bits without requiring a UV source. The EEPROM is programmed and erased using the process called field emission (more commonly known in industry as Fowler-Nordheim tunneling). The EEPROM allows the user to selectively erase a single location, a row, or the whole chip. This feature requires a complicated programming circuitry. Because of this, the EEPROM cannot achieve the density of the EPROM technology. The flash memory was invented by Fujio Masuoka while he was working for Toshiba in 1984. It incorporates the advantages and avoids the drawbacks of the EPROM and EEPROM technologies and can be erased and reprogrammed in the system without using a dedicated programmer. The flash memory achieves the density of the EPROM, but it does not require a window for erasure. Like the EEPROM, the flash memory can be programmed and erased electrically. However, it does not allow individual locations to be erased—the user can only erase a block or the whole chip. Today, the BIOS programs of many high performance PCs are stored in flash memory. Most microcontrollers introduced today use on-chip flash memory as their program memory. Flash memory chips also have been used in flash disk memory (also called solid state drive (SSD)), personal digital assistant (PDA), digital cameras, cell phones, and so on. At the time of this writing, more and more computer vendors provide SSD as a replacement for the hard drive. With the widespread use of the SSD, its price will come down quickly. 1.9 Memory-System Operation A simplified memory-system block diagram is shown in Figure 1.4. A memory system may consist of one or multiple memory chips. Both memory chips and memory systems are organized as an array of memory locations. A memory location may hold any number of bits (most common numbers are 4 bits, 8 bits, 16 bits, 32 bits, and 64 bits). The memory organization of a memory chip or a memory system is often indicated by m × n, where m specifies the number of memory locations in the memory chip or memory system and n specifies the number of bits in each location. Every memory location has two components: contents and address. The memory chip or system only can be accessed (read or write) one location at a time. This is enforced by implementing a decoder on the memory chip to select one, and only one, location to be accessed. There are two types of memory accesses: read and write. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. ■ 15 Memory-System Operation Microprocessor Address RD OE WR WE Data Figure 1.4 ■ Memory system Source: Atmel Corporation, The Atmel AVR Microcontroller 1.9 Block diagram of a simplified memory system 1.9.1 Read Operation Whenever the processor wants to read a memory, it sends out the address of the location it intends to read. Because the memory access can be a read or a write, the processor needs to use a control signal to inform the memory the type of access. In Figure 1.4, the RD signal from the processor indicates a read access, whereas the WR signal indicates a write operation. The memory chip also has control signals to control the read or write operation. The OE signal in Figure 1.4 means output enable and is connected to the RD signal from the processor, whereas the WE signal means write enable and is connected to the WR signal from the processor. For digital systems, there are three logic states for each signal: high, low, and high-impedance (no current flows). When the OE input to the memory chip is low, the data pins are in high-impedance state. The processor uses a set of signal (referred to as address signals) to specify a memory location to access. The number of address signals needed for selecting a memory location is log2m, where m is the number of memory locations in the memory. The set of conductor wires that carry address signals is referred to as an address bus. The number of conductor wires that carry the data must be equal to the number of bits in each memory location. The set of conductors that carry the data to be accessed is called a data bus. To read a memory location, the processor sends out the address of the memory location to be accessed and applies a logic 1 (high voltage) to the RD signal and a logic 0 to the WR signal (this specifies a read operation). In response, the memory system decodes the address input and enables the specified memory location to send out its contents to the data bus, to be read by the processor. 1.9.2 Write Operation To write a value to a location of the memory system in Figure 1.4, the processor places the data to be written on the data bus, places the address of the memory location on the address bus, applies a logic 1 (high voltage) to the WR signal, and a logic 0 to the RD signal (this specifies a write operation). In response, the memory system uses its address decoder to select a location and writes the value on the data bus to that location. The actual memory system design and the signals involved may be different from those in Figure 1.4, but the concept would be the same. The semiconductor vendors may use RD instead of RD and WR instead of WR to refer to read and write signals. These types of signals are active low (i.e., when they are low they are considered to be at logic 1). Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 16 Chapter 1 ■ Introduction to Microcontroller 1.10 Program Execution In order to allow the computer to execute a program immediately after the power is turned on, part of the program must be stored in nonvolatile memory. All computers place the startup program in the nonvolatile memory, which performs the system initialization. After the system initialization is completed, it loads additional programs from secondary storage, such as hard disk or optical storage into the semiconductor memory (often called main memory), for execution. Mainframe computers, minicomputers, and personal computers follow this approach. After power is turned on, the processor starts to execute the program from the basic input/output system (BIOS), which performs the system initialization. After the system initialization is completed, the processor loads additional programs, such as the Windows operating system, into the main memory for execution. Other computers (including most embedded systems) place all of their programs in the nonvolatile memory. After power-up, the processor starts to execute programs from the nonvolatile memory. The following sections deal with several important issues related to program execution. 1.10.1 The Program Counter Circuit D Q clk Set Reset Source: Atmel Corporation, The Atmel AVR Microcontroller The program counter consists of flip-flops and other additional logic gates. There are several types of flip-flops in use. Among them, the D-type flip-flop is the most popular one. The block diagram of a D-type flip-flop with set and reset capabilities is shown in Figure 1.5. Figure 1.5 ■ Block diagram of a D flip-flop with set and reset In Figure 1.5, • Depending on the design, the D value may be transferred to Q on either the rising or the falling edge (but not both edges) of the clk input. • • The clk signal is the clock input of the D flip-flop. • The set and reset inputs are active low (low voltage means logic 1) and cannot be low at the same time. When set is low, the Q signal is forced to 1. When reset is low, the Q signal is forced to 0. The Q signal of all the flip-flops of the program counter determines the address of the next instruction to be executed. As described in Section 1.4.3, a microprocessor or microcontroller has instructions to change the program flow. The design of the program counter circuit must support the possible Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 1.10 ■ 17 Program Execution program counter changes required by the instruction set. Figure 1.6 shows the block diagram of a possible program counter of an 8-bit microcontroller that allows the program counter to be Forced to 0 Incremented by 1 Incremented (or decremented) by a field in the IR register Loaded with a jump target address 1 Branch Branch offset 0 1 MUX 16 Adder To program memory Qs 16 16 1 0 MUX Jump target clk 16 Ds Reset clk Power On Jump Source: Atmel Corporation, The Atmel AVR Microcontroller • • • • Figure 1.6 ■ A simplified block diagram of the program counter (PC) of an 8-bit microcontroller For the program counter circuit shown in Figure 1.6, • Whenever power is turned on to the microcontroller, the program counter is forced to 0, and the instruction fetch starts from address 0. • If the instruction being executed is a conditional branch instruction and the branch condition is true, the Branch signal is 1 and the sum of the current PC and branch offset is loaded into the PC, and instruction execution continues from there. • If the instruction being executed is a jump instruction, then the value of the jump target will be loaded into PC. • If the instruction being executed is not a program flow-control instruction, then the PC is incremented by 1 after each instruction byte is fetched. Other microprocessors or microcontrollers may have different program flow-control schemes and may fetch more instruction bytes in one fetch; the program counter shown in Figure 1.6 must be modified accordingly. 1.10.2 Starting Program Execution Because the program counter holds the address of the next instruction to be fetched, the value of the program counter must be known when the power is turned on. One approach is to force the PC to a fixed value when the power is turned on. The circuit in Figure 1.6 forces the PC to 0 whenever the power is turned on. Many 8-bit microcontrollers (including Atmel AVR) use this approach because it is easy to implement. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 18 Chapter 1 ■ Introduction to Microcontroller Another approach is to fetch the program starting address from a fixed (known) memory location whenever the power is turned on. The Freescale microcontrollers use this approach. The 16-bit HCS12 microcontroller from Freescale fetches the program starting address from memory locations at 0×FFFE and 0×FFFF into the PC and then starts program execution from there. Another way to restart program execution is to apply a reset signal to the processor. All microprocessors and microcontrollers have a reset pin that allows the user to force the processor to start from scratch. The effect of the reset signal is identical to turning on the power. 1.10.3 Instruction Execution Process After power on or a reset, the processor starts to fetch and execute instructions one after another. The procedure for executing each instruction is as follows: 1. Read the next instruction from the memory location indicated by the program counter. 2. Decode the fetched instruction into a set of commands or signals for each of the components of the processor. 3. Increment the program counter so it points to the next instruction. 4. Read whatever data the instruction requires from memory (or input device). The location of this required data is typically stored within the instruction code. 5. Provide the necessary data to an ALU or register. 6. If the instruction requires an ALU or specialized hardware to complete, the processor instructs the hardware to perform the requested operation. 7. Write the result from the ALU back to a memory location or to a register or perhaps an output device. 8. Jump back to step 1. 1.11 Summary The invention of the microprocessor in 1968 resulted in a revolution in electronic history. The first microprocessor, the Intel 4004, incorporated a simplified CPU into an integrated circuit. Following the introduction of 4004, Intel introduced the 8-bit 8008, 8080, and 8085 in the following three years. The 8085 was a big success because of its programmability. Through this programmability, many products could be designed and constructed. Other companies joined in the design and manufacturing of microprocessors. Zilog, Motorola, and Rockwell are among the more successful of these companies. A microprocessor is limited in the fact that it does not have on-chip memory and peripheral functions. The microcontroller incorporates the CPU, some memory, and several peripheral functions onto the same chip. This approach has had the following impacts: • • • External memory is no longer needed for many applications. I/O interfacing is greatly simplified. System design time is dramatically reduced. There are 8-bit, 16-bit, and 32-bit microcontrollers. Renesas/NEC, Microchip, ST Microelectronics, Freescale, and Atmel are the top five vendors of 8-bit microcontrollers in the world at the time of this writing. The PIC16 and PIC18 of Microchip, the R8C from Renesas, the AVR of Atmel, the 8051 variants from more than 50 vendors, and the S08 of Freescale are among the Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 1.11 ■ Summary 19 most popular 8-bit microcontrollers in the market. Eight-bit microcontrollers are mainly used in consumer electronics and automotive applications. The MSP430 from TI, the M16C from Renesas, the C166 and XC166 from Infineon, the HCS12 from Freescale, and the PIC24 from Microchip are the most popular 16-bit microcontrollers in the market. The MSP430 is famous for its low-power design. The M16C, C166, and XC166 have been in the market for a very long time. The HCS12 of Freescale is most successful in the automotive market and is widely taught in universities in the United States. The PIC24 is a latecomer but is growing fast. The V850 from Renesas, the Coldfire from Freescale, the power PC from IBM and Freescale, and the ARM microcontrollers from many vendors are the most successful 32-bit microcontrollers in the world. The V850 is dominating in the automotive and overall 32-bit markets. The Coldfire- and power PC–based microcontrollers are also extremely popular in automotive applications. The ARM microcontrollers have been very successful in mobile applications. A microcontroller is not designed to build a desktop computer. Instead, it is used as the controller of many products. End users of these products do not care what microcontrollers are used in their appliances; they only care about the functionality of the product. A product that uses a certain microcontroller as its controller and has this characteristic is called an embedded system. Automobiles, cable modems, HDTVs, and home security systems are well-known embedded systems. Over the last 20 years, we have clearly seen that a microcontroller must incorporate some or all of the following peripheral functions in order to be useful: • Timer modules that incorporate input capture, output compare, real-time interrupt, and counting capability • • • • • • • • Pulse-width modulation (PWM) functions for easy waveform generation Analog-to-digital converters for data acquisition Digital-to-analog converters for waveform generation Temperature sensors Direct memory access controllers Parallel I/O interfaces Serial I/O interfaces, such as UART, SPI, I2C, USB, and CAN Memory component interface circuitry The AVR from Atmel incorporates most of these peripheral modules and the CPU in one VLSI chip. Memory is where software programs and data are stored. Semiconductor memory chips are classified into two major categories: random access memory and read-only memory. RAM technology includes DRAM, FRAM, MRAM, and SRAM. MROM, PROM, EPROM, EEPROM, and flash memory are read-only memories. Both the FRAM and MRAM have the advantages available in flash memory and SRAM and also have good performance. They could be used to replace the flash memory and SRAM in many applications, but that didn’t happen. Cost is the main reason. However, the cost of memory chips is determined by the volume of production. The true reason that FRAM and MRAM did not take off is because the semiconductor vendors (such as Samsung and Micron) are not willing to allocate fabrication capacity to these two technologies. Therefore, there is no opportunity to lower the cost of MRAM and FRAM and thus increase their popularity in the market. Programs are known as software. A program is a set of instructions that the computer hardware executes. In the past, system designers mainly used assembly language to write Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 20 Chapter 1 ■ Introduction to Microcontroller microcontroller application software. The nature of assembly language forces an assembly programmer to work on the program logic at a relatively low level. This hampers programming productivity. In the last 15 years, most people have turned to high-level language to improve their programming productivity. C is the most widely used language for embedded system programming. Although system designers use assembly or high-level language to write their programs, the microcontroller only executes machine instructions. Programs written in assembly or high-level language must be translated into machine instructions before they can be executed. The program that performs the translation work is called an assembler or compiler, depending on the language to be translated. 1.12 Exercises E1.1 What is a processor? E1.2 What is a microprocessor? What is a microcontroller? E1.3 What makes a microcontroller different from a microprocessor? E1.4 How many bits can the AVR CPU manipulate in one operation? E1.5 Modify the ALU circuit in Figure 1.3 so that it can also perform shift right, shift left, and NOT operations on operand A, in addition to the four operations in Figure 1.3. E1.6 Suppose a microcontroller has a 16-bit branch offset. What is its range of branch offset? E1.7 Why must every computer have some amount of nonvolatile memory? E1.8 Why must every computer have some amount of volatile memory? E1.9 What is the source code? What is the machine code? E1.10 How does a microprocessor or microcontroller start program execution after a reset or power on? Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 2 Introduction to the AVR Microcontroller 2.1 Objectives After completing this chapter, you will be able to • Understand the AVR memory space configuration. • Describe the AVR CPU registers. • Use X, Y, and Z registers together with RAMPX, RAMPY, and RAMPZ to access data and program memory space above 64 kB. • Use appropriate addressing modes to specify operands for instructions. • Use appropriate load instructions to access data memory and program memory locations. • Perform the add operation on appropriate operands. • Perform the subtract operation on appropriate operands. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 22 Chapter 2 ■ Introduction to the AVR Microcontroller 2.2 An Overview of the AVR Microcontroller Family The 8-bit Atmel AVR was introduced in 1996. It is believed that the AVR basic architecture was conceived and developed by two students, Alf-Egil and Vegard, at the Norwegian Institute of Technology. The AVR adopts a modified Harvard architecture, with program and data stored in separate physical memory address space, but has the ability to read data items from program memory, using special instructions. The AVR family of microcontrollers is divided into four subgroups: • • • • TinyAVR Mega AVR XMega AVR Application-specific AVR The difference between these devices lies in the available features. The AVR architecture implements 142 instructions, but not all the devices implement all of the 142 instructions. The tinyAVR devices have less memory (1–8 kB), support fewer instructions (between 54 and 120 instructions, depending on the device), implement less peripheral functions, and are housed in a very small package (6–32 pins). The highest clock frequency for the tinyAVR is 20 MHz. The Mega devices have from 4 to 256 kB of program flash memory, implement extensive peripheral functions, support most of the AVR instructions (130–135), and are housed in a package with from 28 up to 100 pins. The highest clock frequency for the Mega AVR is 20 MHz. The XMega devices have from 32 to 384 kB of memory, implement all 142 instructions and an extensive set of peripheral functions (more than Mega AVR), and are housed in a larger package. The XMega devices may run at a clock with a frequency as high as 32 MHz. XMega devices may be housed in a package with from 44 up to 100 pins. Application-specific AVR are Mega AVR devices with special features not found on the other members of the AVR family, such as LCD controller, USB controller, advanced PWM, CAN controller, and so on. This book focuses on the Mega and XMega AVR devices only. 2.3 The AVR Memory Space The program and data are stored in separate memory spaces. Some Mega and XMega devices also have EEPROM memory. For the Mega devices, EEPROM is separate from the data memory. For the XMega devices, EEPROM and data memory share the same memory space. The Mega AVR implements only internal program memory. As shown in Figure 1.6, the on-chip flash memory is divided into two sections: application program section and boot program section. An AVR instruction is either 16 bit or 32 bit. The AVR program memory is organized as an m × 16 matrix; that is, every location has 16 bits. The flash program memory of the XMega is also divided into two sections similar to those shown in Figure 2.1. A third section inside the Application section is referred to as the application table section, which has separate lock bits for storage of write or read/write protection. The application table section is used for storing nonvolatile data or application software. The flash program memory map for the XMega384A1 is shown in Figure 2.2. Addresses in Figure 2.1 and 2.2 are hexadecimal numbers. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 2.3 ■ 23 The AVR Memory Space Application flash section Boot flash section Figure 2.1 ■ Mega AVR program flash memory map 0x00000 Application section (384 kB) 0x2EFFF 0x2F000 0x2FFFF 0x30000 Application table section (8 kB) Boot section (8 kB) 0x30FFF Figure 2.2 ■ Source: Atmel Corporation, The Atmel AVR Microcontroller Upto 0x1FFFF Source: Atmel Corporation, The Atmel AVR Microcontroller 0x00000 XMega384A1 program memory map The Mega AVR devices have a 64 kB data memory space that accommodates CPU registers, I/O registers, and data memory (on-chip and external). The size of the on-chip data memory varies with the device. For example, the data memory map of the Mega2560 is shown in Figure 2.3. The XMega devices support a 16 MB data memory space. The on-chip EEPROM also resides in this memory space. The data memory map of the XMega384A1 is shown in Figure 2.4. 64 I/O Registers 0x60 0x1FF 0x200 0x21FF 0x2200 416 External I/O registers Internal SRAM (8 kB) External SRAM (56832 bytes) 0xFFFF Figure 2.3 ■ Source: Atmel Corporation, The Atmel AVR Microcontroller 32 Registers Mega2560 data memory map Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. Chapter 2 ■ Introduction to the AVR Microcontroller 0x000000 I/O Registers (4 kB) 0x001000 EEPROM (4 kB) 0x002000 Internal SRAM (32 kB) 0x00A000 External memory (0 to 16 MB) 0xFFFFFF Figure 2.4 ■ Source: Atmel Corporation, The Atmel AVR Microcontroller 24 XMega384A1 data memory map 2.4 The AVR CPU Register The AVR CPU has a register file of thirty-two 8-bit general-purpose registers with single clock cycle access time. This allows single-cycle ALU operation. In a typical ALU cycle, the operation is performed on two register operands, and the result is stored back in the register file. Six of the 32 registers can form 16-bit address pointers (referred to as X, Y, and Z pointers) for addressing data memory. The Z register can also be used as an address pointer to read from and/ or write to the flash program memory, signature rows, fuses, and lock bits. Each CPU register of the Mega AVR devices is assigned a memory address, as shown in Figure 2.5. Figure 2.5 0x00 R1 0x01 R2 0x02 R13 0x0D R14 0x0E R15 0x0F R16 0x10 R17 0x11 R26 0x1A X-register low byte (XL) R27 0x1B X-register high byte (XH) R28 0x1C Y-register low byte (YL) R29 0x1D Y-register high byte (YH) R30 0x1E Z-register low byte (ZL) R31 0x1F Z-register high byte (ZH) ■ Source: Atmel Corporation, The Atmel AVR Microcontroller Addr. R0 AVR CPU general purpose registers Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 2.4 ■ 25 The AVR CPU Register To access program memory or data memory above 64 kB, the address pointer must be longer than 16 bits. This is done by concatenating one register to one of the X, Y, or Z registers. This register (RAMPX, RAMPY, or RAMPZ) then holds the most significant byte (MSB) in a 24-bit address or address pointer. These registers are available only on devices with external bus interface and/or more than 64 kB of program or data memory space. For these devices, only the number of bits required to address the whole program and data memory space in the device is implemented in the registers. 2.4.1 The RAMPX, RAMPY, and RAMPZ Registers The RAMPX, RAMPY, and RAMPZ registers are concatenated with the X, Y, and Z pointers, respectively, to enable indirect addressing of the whole data memory space above 64 kB and up to 16 MB. The combinations of these registers with X, Y, and Z registers are shown in Figure 2.6. 16 15 8 7 RAMPX 23 XL 16 15 8 7 RAMPY 23 YL 16 15 ■ 0 YH 8 7 RAMPZ Figure 2.6 0 XH 0 ZH ZL Source: Atmel Corporation, The Atmel AVR Microcontroller 23 The combined RAMPX 1 X, RAMPY 1 Y, and TAMPZ 1 Z registers When reading (extended load program memory [ELPM]) and writing (store program memory [SPM]) program memory locations above the first 128 kB of the program memory, RAMPZ is concatenated with the Z register to form the 24-bit address. The LPM instruction is not affected by the RAMPZ setting. 2.4.2 The Extended Indirect Register (EIND) The EIND register is added to support extended indirect subroutine call and indirect jump in devices with program memory larger than 128 kB. To make extended subroutine calls and indirect jump in these devices, the user must use the EICALL and EIJMP instruction, respectively. The EIND register is concatenated with the 16-bit ZH:ZL register, as shown in Figure 2.7. 23 16 15 EIND 8 7 ZH 0 ZL Source: Atmel Corporation, The Atmel AVR Microcontroller Figure 2.7 ■ The Z-pointer used by EICALL and EIJMP instructions 2.4.3 The RAMPD Register The XMega AVR devices provide this register to support direct addressing of the whole data memory space above 64 kB. This register is concatenated with the k operand in the instruction, as shown in Figure 2.8. The content of this register and the k field in the instruction are used as the direct address to access data memory. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 26 Chapter 2 ■ Introduction to the AVR Microcontroller 23 16 15 0 RAMPD k Source: Atmel Corporation, The Atmel AVR Microcontroller ■ Figure 2.8 The combined RAMPD 1 K register 2.4.4 The Status Register (SREG) The SREG register contains information about the result of the most recently executed arithmetic or logic instruction. The contents of the SREG register are shown in Figure 2.9. 7 6 5 4 3 2 1 0 I T H S V N Z C Source: Atmel Corporation, The Atmel AVR Microcontroller Figure 2.9 ■ The SREG register I: THE GLOBAL INTERRUPT ENABLE FLAG This flag is the global interrupt enable flag and must be set to 1 in order for each individual interrupt source to be enabled. If this flag is cleared to 0, all of the interrupt sources would be disabled. This flag is set and cleared by the application with the SEI (set global interrupt flag) and CLI (clear global interrupt flag) instructions. Interrupt handling is discussed in Chapter 9. T: BIT COPY STORAGE This flag is used by the bit load (BLD) and bit store (BST) instruction as the source or destination operand bit. A bit from a register in the register file can be copied into T by the BST instruction, and the BLD instruction can copy the T bit into a bit of a register in the register file. H: HALF CARRY FLAG The half carry flag (H) indicates a half carry in some arithmetic operation. Half carry is useful in BCD (binary-coded decimal) arithmetic. S: SIGN BIT, S = N { V This flag indicates the sign of the previous operation result and is always the exclusive OR of the N and V flags. V: TWO’S COMPLEMENT OVERFLOW FLAG This flag indicates whether an overflow occurs in the previous operation. N : N E G AT I V E F L A G This flag indicates whether the previous arithmetic or logical operation result is negative. Z: ZERO FLAG This flag indicates whether the previous arithmetic or logical operation result is zero. C: CARRY FLAG This flag indicates whether a carry is generated in the previous arithmetic or logical operation. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 2.6 ■ AVR Addressing Modes 27 2.5 The AVR Instruction Set An AVR instruction can be divided into two parts: opcode and operand fields. The opcode field specifies the operation to be performed, whereas the operand field specifies the operands to be operated on. Some instructions are 16 bit, whereas others are 32 bit. The AVR instruction set consists of 142 instructions. These instructions are divided into the following categories: 1. Arithmetic: Instructions in this category are used to perform addition, subtraction, multiplication, increment, and decrement operations. 2. Control flow: Instructions in this category may perform jump, conditional branch, conditional skip, compare, subroutine call, and return from subroutine operations. These instructions are indispensible for implementing program loops and making decisions. 3. Data transfer: Instructions in this category allow us to copy data from register to register, from data memory to a register, from a register to data memory, from program memory to a register, from a register to program memory, from input device to a register, and from a register to an output device. 4. Bit field manipulation: Instructions in this category allow the user to shift or rotate a register to the right, shift or rotate a register to the left, set one or a few bits in a register to 1, clear one or a few bits in a register to 0 and so on. 5. Logical: Instructions in this category allow the user to perform logical operations such as AND, OR, XOR, and NOT operations, and so on. 6. Miscellaneous: Instructions in this category include BREAK, NOP, SLEEP, and WDR. An AVR instruction may have none, one, two, or three operands. When an instruction has three operands, the third operand would be the carry flag. When an instruction has two operands, the first operand would be used as a source and the destination operand. For example, in the instruction add r2, r3 Register r2 is both a source operand and the destination operand of the add instruction. The operations performed by these operations are explained in appropriate chapters. A summary of the AVR instruction set is given in Appendix A. 2.6 AVR Addressing Modes Addressing modes are used to specify instruction operands. The explanation of addressing modes cannot be done without some knowledge of AVR instructions and vice versa. To explain addressing modes, appropriate instructions are also introduced. To facilitate explanation, we use [] to refer to the contents of a register or a memory location. For example, [r0] and [0x1000] refer to the contents of register r0 and data memory location at 0x1000, respectively. We use the notation mem(addr) to refer to a data memory location with the address addr. For example, the notation mem(0x1000) refers to data memory location at 0x1000. We use the notation pmem(addr) to refer to a program memory location with the address addr. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 28 Chapter 2 ■ Introduction to the AVR Microcontroller 2.6.1 Register Direct Mode This mode uses five bits to specify a register to be worked on. The programmer specifies the names of the registers directly as the operands of the instruction, and the assembler translates the register name into the corresponding 5-bit code of the register. This is the most common addressing mode because every arithmetic or logic instruction specifies either one or two registers as operands. For example, the instruction add r0, r1 ; r0 d [r0] 1 [r1] adds the contents of registers r0 and r1 together and places the sum in r0. Both r0 and r1 are specified using 5 bits. The instruction and r16,r17 ; r16 d [r16] AND [r17] performs the bitwise AND operation to the contents of registers r16 and r17 and places the result in r16. The instruction dec r1 ; r1 d [r1] 2 1 decrements r1 by 1. 2.6.2 I/O Direct Mode In this mode, the AVR architecture allows the user to use 6 bits to specify one of the first 64 I/O registers as an operand of an instruction. When writing an assembly program, the user uses the register name instead of the 6-bit I/O register to specify the I/O register as an operand. For example, in r0,PORTB ; r0 d [PORTB] reads the contents of the PORTB register and stores them in the r0 register. out PORTD,r1 ; PORTD d [r1] outputs the contents of the r1 register to PORTD. Some complex AVR devices have more peripheral registers than can be supported within the 64 locations reserved in the instruction for the I/O direct addressing. The extended I/O memory can only be reached by using the data memory addressing. I/O registers in the extended I/O memory space must be accessed using load (LD/LDS/LDD) and store (ST/STS/ STD) instructions. 2.6.3 Direct Data Mode This mode uses a 16-bit value to specify the operand address. Instructions using this mode are 32 bit. For example, lds r1,0x1000 copies the contents of the data memory location at 0x1000 to r1. sts 0x1000,r0 ; mem(0x1000) d [r0] stores the contents of r0 in the data memory location at 0x1000. 2.6.4 Data Indirect with Displacement Mode This addressing mode forms the data memory address by adding the 6-bit field from the instruction and the Y or Z pointer. The operation of this mode is illustrated in Figure 2.10. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 2.6 ■ 29 AVR Addressing Modes Depending on the instruction, the field that starts from bit 6 to 10 may specify the source (Rr) or destination (Rd) register. For example, ; r10 d [[Y] 1 20] ldd r10,Y120 loads the content of the memory location at the address specified by the sum of the pointer Y and 20 into the register r10. ; mem([Y] 1 10) d [r0] std Y110,r0 Data memory space 0x0000 15 0 Y or Z register 15 10 6 5 Opcode Rr/Rd 0 q RAMEND Figure 2.10 ■ Source: Atmel Corporation, The Atmel AVR Microcontroller stores the content of r0 to the memory location with address equal to the sum of the pointer Y and 10. Data indirect with displacement mode 2.6.5 Data Indirect Mode This mode uses the contents of one of the pointers (X, Y, or Z) to specify the address of the data memory location to access. For the AVR devices without on-chip SRAM, this mode is called register indirect addressing, which is a subset of data indirect addressing because the data space from 0 to 31 is the register file. For example, ld r0,X ; r0 d [[X]] loads the contents of the memory location with address specified by the pointer X. 2.6.6 Data Indirect with Pre-Decrement In this mode, the contents of the pointer X, Y, or Z are decremented by 1 and then used as an address to access data memory. For example, st 2X,r0 ; X d [X] 2 1; mem([X]) d [r0] decrements X by 1 and then stores the contents of r0 in the memory location pointed to by X. ld r1,2X ; X d [X] 2 1; r1 d [[X]] decrements X by 1 and then copies the contents of the memory location pointed to by X to r1. 2.6.7 Data Indirect with Post-Increment This addressing mode accesses the memory location pointed to by the pointer X, Y, or Z and then increments the pointer by 1. For example, st X1,r0 ; mem([X]) d [r0]; X d [X] 1 1 Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 30 Chapter 2 ■ Introduction to the AVR Microcontroller stores the contents of r0 in the memory location pointed to by X and then increments X by 1. ld ; r1 d [[Y]]; Y d [Y] 1 1 r1,Y1 copies the contents of the memory location pointed to by Y to r1 and then increments Y by 1. 2.6.8 Program Memory Constant Addressing Using the LPM, ELPM, and SPM Instructions These three instructions use the Z pointer to specify the program memory location to access. The Z pointer specifies a byte address. When the ELPM instruction is used, the RAMPZ register is used to extend the Z pointer. For example, lpm r0,Z ; r0 d [[Z]] loads the contents of the program memory location pointed to by Z into r0. elpm r0,Z ; r0 d [[RAMPZ:Z]] loads the contents of the program memory location pointed to by the concatenation of RAMPZ and Z. 2.6.9 Program Memory with Post-Increment Using the LPM Z+ and ELPM Z+ Instructions The LPM Z+ instruction uses the Z pointer to specify the program memory location to access whereas the ELPM Z+ instruction uses the concatenation of the RAMPZ and Z to specify the program memory location to access. After the access either the Z pointer or the concatenation of RAMPZ and Z is incremented by 1. For example, lpm r0,Z1 loads the contents of the program memory location pointed to by Z into r0 and then increments Z by 1. 2.6.10 Direct Addressing, JMP and CALL These two instructions are 32 bit. The JMP instruction specifies the 22-bit address of the target instruction to jump to. The CALL instruction specifies the 22-bit address of the subroutine to be called. The format of these two instructions is shown in Figure 2.11. Program memory 6 msb 16 lsb PC FLASHEND Figure 2.11 ■ Source: Atmel Corporation, The Atmel AVR Microcontroller 0x0000 Opcode Data program addressing, JMP and CALL Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 2.7 ■ 31 A Sample of AVR Instructions 2.6.11 Indirect Program Addressing, IJMP and ICALL The indirect jump (IJMP) instruction uses the Z pointer to specify the address of the target instruction to jump to and the indirect call (ICALL) instruction uses the Z pointer to specify the address of the subroutine to be called. 2.6.12 Relative Program Addressing, RJMP and RCALL The relative jump (RJMP) instruction uses a 12-bit value to specify the distance (from the instruction after RJMP) of the target instruction to jump to. The relative call (RCALL) instruction uses a 12-bit value to specify the distance (from the instruction after RCALL) of the subroutine to call. The address calculation is illustrated in Figure 2.12. Program memory 1 15 12 11 OP 0 k FLASHEND Figure 2.12 ■ Source: Atmel Corporation, The Atmel AVR Microcontroller 0x0000 PC Relative program addressing, RJMP and RCALL 2.7 A Sample of AVR Instructions It is very helpful to learn a small set of AVR instructions that is used most often, before we formally learn the AVR assembly language programming. In the following, we examine data movement, addition, and subtraction instructions. The AVR provides a large group of data movement instructions. The arithmetic and logic instructions of the AVR cannot use memory locations as their operand. The value stored in a memory location must be copied to a register before it can be operated on. 2.7.1 The Data Transfer Instructions The AVR supports the following types of data transfer instructions: • • • • • • • Data transfer from register to register Loading a constant in a register Data transfer from a data memory location to a register Data transfer from a register to a data memory location Data transfer from a program memory location to a register Data transfer from a register to a program memory location I/O operation Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 32 Chapter 2 ■ Introduction to the AVR Microcontroller INSTRUCTIONS TO T R A N S F E R D ATA REGISTER FROM TO REGISTER The instruction mov Rd, Rr copies the contents of the register Rr to the register Rd. For example, mov r0, r1 ; r0 d [r1] copies the contents of r1 to r0. The instruction movw Rd, Rr copies the contents of the register pair Rr+1:Rr to the register pair Rd+1:Rd. Both r and d must be an even number. For example, movw r10,r20 ; r11:r10 d [r21]:[r20] copies the contents of r20 to r10 and the contents of r21 to r11, respectively. This instruction can also be written as follows: movw r11:r10,r21:r20 INSTRUCTION TO LOAD A C O N S TA N T INTO A REGISTER There is often a need to provide an initial value to a program variable. The AVR provides the following instruction for this purpose: ldi Rd,k ; Rd d k For example, ldi r0,10 initializes r0 with the value of 10. INSTRUCTION TO T R A N S F E R D ATA FROM D ATA M E M O R Y TO A REGISTER There are 12 instructions in this category (listed in Table 2.1). For example, lds r0,0x100 loads the contents of the data memory location at the address 0x100 into register r0. The instruction sequence ldi ldi ld r26,0x00 r27,0x10 r0,X ; place 0 in XL ; place 0x10 in XH ; r0 d [0x1000] initializes the X pointer with the value of 0x1000 and then loads the contents of the data memory location at 0x1000 into r0. The instruction sequence ldi ldi ld r28,0x00 r29,0x20 r1,Y1 ; place 0 in YL ; place 0x20 in YH ; r1 d [0x2000]; Y d 0x2001 initializes the Y pointer with the value of 0x2000, loads the contents of the data memory location at 0x2000 into r1, and then increments Y by 1 (Y holds 0x2001). The instruction sequence ldi ldi ld r30,0x10 r31,0x10 r0,2Z ; place 0x10 in ZL ; place 0x10 in ZH ; Z d 0x100F; r0 d [0x100F] initializes the Z pointer with the value of 0x1010, decrements Z by 1, and then loads the contents of the memory location at 0x100F into r0. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 2.7 ■ 33 A Sample of AVR Instructions The instruction sequence ldi ldi ldd r30,0x00 r31,0x20 r0,Z15 ; place 0x00 in ZL ; place 0x20 in ZH ; r0 d [0x2005] initializes the Z pointer with the value of 0x2000 and then loads the contents of the data memory location at 0x2005 into r0. Instruction Description Operation Ids Rd, K Load direct from data memory Rd d [k] Id Rd, X Load indirect Rd d [[X]] Id Rd, X1 Load indirect and post-increment Rd d [[X]]; X d [X] 1 1 Id Rd, 2X Load indirect and pre-decrement X d [X]21; Rd d [[X]] Id Rd, Y Load indirect Rd d [[Y]] Id Rd, Y1 Load indirect and post-increment Rd d [[Y]]; Y d [Y] 1 1 Id Rd, 2Y Load indirect and pre-decrement Y d [Y]21; Rd d [[Y]] Idd Rd, Y 1 q Load indirect with displacement Rd d [[Y] 1 q] Id Rd, Z Load indirect Rd d [[Z]] Id Rd, Z1 Load indirect and post-increment Rd d [[Z]]; Z d [Z] 1 1 Id Rd, 2Z Load indirect and pre-decrement Z d [Z]21; Rd d [[Z]] Idd Rd, Z 1 q Load indirect with displacement Rd d [[Z] 1 q] Source: Atmel Corporation, The Atmel AVR Microcontroller Table 2.1 INSTRUCTIONS TO ■ Instructions to transfer data from data memory to register T R A N S F E R D ATA FROM REGISTER TO D ATA M E M O R Y The AVR provides 12 instructions that can be used to save the contents of a register in a data memory location. These instructions are listed in Table 2.2. For example, sts 0x2000,r0 ; mem(0x2000) d [r0] stores the contents of r0 in the data memory location at 0x2000. The instruction sequence ldi ldi st XL,0x00 XH,0x10 X, r0 ; XL d 0x00 ; XH d 0x10 ; mem(0x1000) d r0 initializes X with the value of 0x1000 and then stores the contents of r0 in the data memory location at 0x1000. The instruction sequence ldi XL,0x00 ; XL d 0x00 ldi XH,0x10 ; XH d 0x10 st X1, r0 ; mem(0x1000) d r0; X d [X] 1 1 initializes X with the value of 0x1000, stores the contents of r0 at 0x1000, and then increments X by 1 (becomes 0x1001). Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 34 Chapter 2 ■ Introduction to the AVR Microcontroller The instruction sequence ldi ZL,0x10 ldi ZH,0x10 ; ZH d 0x10 ; ZL d 0x10 st 2Z, r0 ; Z d [Z] 2 1; mem(0x100F) d r0 initializes Z with the value of 0x1010, decrements Z by 1, and then stores r0 in the memory location (at 0x100F) pointed to by Z. The instruction sequence ldi ZL,0x00 ; ZL d 0x00 ldi ZH,0x10 ; ZH d 0x10 std Z15, r0 ; mem(0x1005) d r0 initializes Z with the value of 0x1000, and then stores r0 at the memory location at 0x1005. Instruction Description Operation sts K, Rr Store direct to data memory Mem (K) d [Rr] st X, Rr Store indirect Mem ([X]) d [Rr] st X1, Rr Store indirect and post-increment Mem ([X]) d [Rr]; X d [X] 1 1 st 2X, Rr Store indirect and pre-decrement X d [X]21; mem([X]) d [Rr] st Y, Rr Store indirect Mem([Y]) d [Rr] st Y1, Rr Store indirect and post-increment Mem([Y]) d [Rr]; Y d [Y] 1 1 st 2Y, Rr Store indirect and pre-decrement Y d [Y]21; mem([Y]) d [Rr] std Y 1 q, Rr Store indirect with displacement Mem([Y] + q) d [Rr] st Z, Rr Store indirect Mem([Z]) d [Rr] st Z1, Rr Store indirect and post-increment Mem([Z]) d [Rr]; Z d [Z] 1 1 st 2Z, Rr Store indirect and pre-decrement Z d [Z] - 1; mem([Z]) d [Rr] std Z 1 q, Rr Store indirect with displacement Mem([Z] + q) d [Rr] Source: Atmel Corporation, The Atmel AVR Microcontroller Table 2.2 ■ Instructions store the contents of a register in data memory I N S T R U C T I O N S T O T R A N S F E R D ATA AND A REGISTER BETWEEN PROGRAM MEMORY As shown in Table 2.3, the AVR provides six instructions for transferring data from program memory to a register and two instructions for storing the contents of a register to the program memory. For example, lpm loads the contents of the program memory location pointed to by Z to register r0. lpm r10,Z copies the contents of the program memory location pointed to by Z to r10. lpm r0,Z1 copies the contents of the program memory location pointed to by Z to r0 and then increments Z by 1. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 2.7 ■ 35 A Sample of AVR Instructions Instruction Description Operation Ipm Load program memory r0 d [[Z]] Ipm Rd, Z Load program memory Rd d [[Z]] Ipm Rd, Z1 Load program memory and post increment Rd d [[Z]]; Z d [Z] 1 1 elpm Extended load program memory r0 d [[RAMPD:Z]] elpm Rd, Z Extended load program memory Rd d [[RAMPD:Z]] elpm Rd,Z1 Extended load program memory and post-increment Rd d [[RAMPD:Z]]; Z d [Z] 1 1 spm Store program memory pmem([RAMPD:Z]) d r1:r0 spm Z1 Store program memory and post-increment by 2 pmem([RAMPD:Z]) d R1:r0; Z d [Z] 1 2 Source: Atmel Corporation, The Atmel AVR Microcontroller Table 2.3 ■ Instructions to transfer data between a register and the program memory The AVR provides one input instruction (in Rd, A) and one output instruction (out A, Rr) for transferring data between a CPU register and an I/O register. The value A is between 0 and 63. However, we often use the symbolic name to refer to an I/O register. For example, in r0, PORTD ; PORTD equals 0x0B (for Mega device) reads the PORTD register that holds the current parallel PORTD pin values and places them in r0. out PORTB, r1 ; PORTB equals 0x05 (for Mega device) writes the contents of r1 to the PORTB register and this value appears on the parallel PORTB pins. Example 2.1 ▼ Write an instruction sequence to copy the contents of the data memory location at 0x1000 to 0x1010. Solution: We use the load-indirect instruction to fetch the source location and then use the store-indirect-with-displacement instruction to place the fetched data in the destination. The following instruction sequence performs the desired operation: ldi YL,0x00 ; use Y to point to the source memory location ldi YH,0x10 ;" ld r0,Y ; fetch the source data memory location std Y10x10,r0 ; place the value at the destination data memory location ▲ 2.7.2 Addition Instruction The addition instructions supported by the AVR are listed in Table 2.4. ADD RD, RR This instruction adds the contents of registers Rd and Rr and places the sum in Rd. For example, add r0, r1 adds the values in r0 and r1 together and places the sum in r0. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 36 Chapter 2 ■ Introduction to the AVR Microcontroller RD, RR ADC This instruction adds the values in Rd and Rr and the C flag of the SREG register, and places the sum in Rd. For example, adc r1, r2 adds the values in r1 and r2 and the C flag of the SREG register, and then places the sum in r1. ADIW RD, K This instruction adds the constant k (0~63) to the register pair Rd+1:Rd and places the sum in the register pair Rd+1: Rd. Here, Rd can only be 24, 26, 28, and 30. For example, adiw r24, 55 adds 55 to the register pair r25:r24 and places the sum in r25:r24. Instruction Description Operation add Rd, Rr Add without carry Rd d [Rd] 1 [Rr] adc Rd, Rr Add with carry Rd d [Rd] 1 [Rr] 1 C adiw Rd, k Add immediate to word Rd 1 1:Rd d [Rd + 1]:[Rd] 1 k Source: Atmel Corporation, The Atmel AVR Microcontroller Table 2.4 ■ AVR addition Instructions Example 2.2 ▼ Write an instruction sequence to add the contents of the data memory location at 0x1000 and 0x2000 and store the sum at 0x2010. Solution: We need to use two pointers to point to two source operands. The following instruction sequence performs the desired operation: ldi ldi ldi ldi ld ld add std YL,0x00 YH,0x10 ZL,0x00 ZH,0x20 r0,Y r1,Z r1,r0 Y10x10,r1 ; let Y point to 0x1000 ;" ; let Z point to 0x2000 ;" ; load the contents of 0x1000 to r0 ; load the contents of 0x2000 to r1 ; add two source operands ; store the sum at 0x2010 ▲ Example 2.3 ▼ Write an instruction sequence to add the value of data memory location 0x1000 and program memory location 0x2000 and leave the sum in register r0. Solution: We need to use a register pointer (can be X or Y) to point to the data memory location 0x1000 and use the Z register to point to the program memory location 0x2000. The following instruction sequence performs the desired operation: Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 2.7 ■ A Sample of AVR Instructions ldi ldi ldi ldi ld lpm add YL,0x00 YH,0x10 ZL,0x00 ZH,0x20 r1,Y r0,Z r0,r1 ; let Y point to data memory location 0x1000 ;" ; let Z point to program memory location 0x2000 ;" ; fetch data memory location contents ; fetch program memory location contents ; perform addition 37 ▲ 2.7.3 Subtract Instructions The subtract instructions supported by the AVR are listed in Table 2.5. RD, RR SUB This instruction subtracts the value in Rr from Rd and places the difference back in Rd. For example, sub r1, r0 subtracts the value in r0 from that in r1 and places the difference in r1. SUBI RD, K This instruction subtracts the 8-bit constant k (0 # k # 255) from Rd and places the difference back in Rd. For example, subi r0, 10 subtracts 10 from r0 and places the result back to r0. RD, RR SBC This instruction subtracts the contents of Rr and the C flag of the SREG register from Rd and places the difference back in Rd. For example, sbc r0, r10 subtracts the value in r10 and the C flag of the SREG register from r0 and places the difference in r0. SBCI RD, K This instruction subtracts the constant k (0 # K # 255) and the C flag of the SREG register from Rd and places the result back to Rd. For example, sbci r0, 20 subtracts the value of 20 and the C flag of the SREG register from r0 and places the difference back to r0. SBIW RD, K This instruction subtracts the constant k (0 # k # 63) from the register pair Rd+1:Rd and places the difference in Rd+1:Rd. Rd can only be 24, 26, 28, or 30. For example, sbiw r24,30 subtracts the constant 30 from the register pair r25:r24 and places the difference in r25:r24. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 38 Chapter 2 ■ Introduction to the AVR Microcontroller Instruction Description Operation sub Rd, Rr Subtract without carry Rd d [Rd]2[Rr] subi Rd, k Subtract immediate Rd d [Rd] 2 k sbc Rd, Rr Subtract with carry Rd d [Rd]2[Rr] 2 C sbci Rd, k Subtract immediate with carry Rd d [Rd]2k 2 C sbiw Rd, k Subtract immediate from word Rd + 1:Rd d [Rd + 1]:[Rd] 2 k Source: Atmel Corporation, The Atmel AVR Microcontroller Table 2.5 ■ AVR addition Instructions Example 2.4 ▼ Write an instruction sequence to subtract 10 from the data memory location at 0x2000. Solution: We have to use a pointer register to access the data memory location. The following instruction sequence can perform the desired operation: ldi XL, 0x00 ; use X to point to 0x2000 ldi ld sbi st XH, 0x20 r0, X r0, 10 X, r0 ;" ; get a copy of the data memory location at 0x2000 ; subtract 10 from the copy ; store the result back to the data memory location at 0x2000 ▲ Example 2.5 ▼ Write a sequence of instructions to subtract 50 from data memory locations 0x2000~0x2001 and store the difference back to 0x2000˜0x2001. Solution: The following instruction sequence performs the desired operation: ldi YL,0x00 ; let Y point to data memory location 0x2000 ldi ld ldd sbiw st std YH,0x20 r24,Y r25,Y11 r24,50 Y,r24 Y11,r25 ;" ; fetch the low byte ; fetch the high byte ; perform the subtraction ; save the difference ;" ▲ 2.8 Summary The 8-bit AVR microcontroller has 32 CPU registers. These general-purpose registers can be used as the source or destination operands of instructions. However, not every one of these registers can be used as the source or destinations for some instructions. The AVR is not totally orthogonal. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 2.9 ■ Exercises 39 The AVR provides a rich instruction set to support high-level languages. The AVR addressing modes also simplify the access of complex data structures. The AVR has a version of the ADD instruction that includes the C flag as one of the source operands, which enables multipleprecision addition operation. The AVR also has a version of the SUB instruction that includes the C flag as one of source operands and hence is used to perform multiprecision subtraction operation. The arithmetic and logical operations can only be performed on operands in registers. Memory operands must be loaded into a register before these operations can be performed. 2.9 Exercises E2.1 Write an instruction sequence to swap the contents of registers r0 and r1. A third register such as r2 or another can be used to facilitate the swap operation. E2.2 Write an instruction sequence to swap the contents of data memory locations at 0x2000 and 0x2001. E2.3 Write an instruction sequence to copy three bytes from data memory location at 0x1000~0x1002 to data memory locations at 0x2000~0x2002, respectively. E2.4 Write an instruction sequence to store 1, 3, and 5 at data memory locations at 0x2000, 0x2005, and 0x200A, respectively. E2.5 Write a sequence of instructions to add 5 to data memory locations at 0x2000, 0x2001, and 0x2002, respectively. E2.6 Write a sequence of instructions to subtract 10 from data memory locations at 0x2000, 0x2005, and 0x200A, respectively. E2.7 Write a sequence of instructions to add the three numbers stored in data memory locations at 0x2000, 0x2001, and 0x2002 and store the sum at data memory location at 0x2010. E2.8 Write an instruction sequence to add 35 to the two-byte value stored at data memory locations 0x2000˜0x2001. E2.9 Write an instruction sequence to output the value 0xAA to PORTC. E2.10 Write a sequence of instructions to copy the three bytes from program memory locations 0x2000~0x2002 to data memory locations at 0x2000~0x2002, respectively. E2.11 Write an instruction sequence to add the two 8-bit numbers stored in program memory at 0x1000 and 0x1005 together and leave the sum in the data memory location at 0x2000. E2.12 Write an instruction sequence to swap the 16-bit value stored in data memory location at 0x2000~0x2001 with the 16-bit value stored in the data memory at 0x2020~0x2021. E2.13 Write an instruction sequence to subtract the value stored at data memory location 0x2000 from the sum of the values stored at data memory locations 0x2010 and 0x2011 and leave the difference in r0. E2.14 Write an instruction sequence to subtract the sum of data memory locations at 0x2000 and 0x2001 from the sum of the data memory locations at 0x2010 and 0x2011 and leave the difference at data memory location 0x2020. E2.15 Write an instruction sequence to add the 16-bit value stored at data memory locations 0x2000~0x2001 and the 16-bit value stored at program memory locations 0x2010~0x2011 and store the sum at data memory locations 0x2020~0x2021. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 3 AVR Assembly Language Programming 3.1 Objectives After completing this chapter, you will be able to • Use AVR assembler directives to define constants, reserve memory locations, define macros, set location counter, and so on. • Write assembly programs to perform arithmetic and logic operations. • Write program loops in assembly language. • Write an assembly program to perform block data transfer from program memory to data memory. • Write an assembly program to perform block data transfer from data memory to data memory. • Use logical instructions to manipulation a bit or bit field of a register or I/O pins. • Write program loops to create time delays. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 42 Chapter 3 ■ AVR Assembly Language Programming 3.2 AVR Assembly Language Program Structure An AVR assembly language program consists of statements that may be assembly instructions, assembler directives, or comments. A statement may have up to four fields. Therefore, an AVR assembly program statement may take one of the following four forms: 1. [label:] directive [arguments] [comment] 2. [label:] instruction [operands] [comment] 3. Comment 4. Empty line Items placed in braces ([]) are optional. There are no restrictions with respect to column placement of labels, directives, comments, or instructions. The AVR assembler is not case sensitive. 3.2.1 Label Field This field is optional and, when present, serves one of the following functions: • • To identify a location in program memory To identify a location in data memory A label must begin with a letter (a-z or A-Z), a question mark (?), or an underscore (_) and is followed by zero or more letters, digits, and special characters (including a dollar sign ($), question mark (?), and underscore (_)). A label must be terminated by a colon (:) character. Example 3.1 ▼ Give a few examples of valid and invalid labels. Solution: Labels in the following instructions and directives are valid: loop: true: _ibuf: lights: ldi mov .byte .db r10,100 r1,r0 20 0x7E,0x30,0x6D,0x79,0x33,0x5B,0x5F,0x70,0x7F,0x7B Labels in the following instructions are invalid: ,too 3 three f two: .byte add and 5 r3,r5 r10,r23 // , is an illegal character // label starts with 3 and not terminates with a column // label contains a space character ▲ 3.2.2 Operation Field This field may be an AVR instruction mnemonic or an assembler directive. Example 3.2 ▼ Give a few examples of operation fields. Solution: .def inc count = r10 r5 // .def is the operation field // inc is the operation field Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 3.3 ■ 43 Expressions cp ldi r1,r2 r2,0x40 // cp is the operation field // ldi is the operation field ▲ 3.2.3 Operand Field This field follows the operation field and is separated from the operation field by at least one space. An assembly instruction may have zero, one, or two operands. The data definition assembler directive, for example, DB and DW, can have any number of operands. An operand may be a constant, a register, or a memory location. A constant is formed by using an expression, whereas a memory location is specified using one of the AVR addressing modes. Example 3.3 ▼ Give a few examples of operand fields. Solution: .dseg .db ldi ldi first: 10,11,16,18 r27,first r28,first+2 // no operand // 10, 11, 16, and 18 are operand field // both r27 and first are operand field // both r28 and first+2 are operand field ▲ 3.2.4 Comment Field The programmer may use this field to explain the function or operation of an instruction (or assembler directive) or a block of instructions (or assembler directives). A comment may have one of the following forms: ; [Text] // this is a comment line /* this is also a comment and may span multiple lines */ 3.3 Expressions Expressions are needed to form the operand field of an instruction or assembler directive. An expression may consist of operands, operators, and functions. All expressions are internally 32 bits. 3.3.1 Operands The following operands may be used in forming expressions in an AVR assembly statement: • User defined labels that are given the value of the location counter at the place they appear • • • • User defined variables defined by the set directive User defined constants defined by the equ directive Integer constants, which can be given in binary, hexadecimal, or decimal format The current value of the program counter Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 44 ■ Chapter 3 AVR Assembly Language Programming 3.3.2 Functions The AVR assembler provides the following functions for forming constants: • Low(expression). This function returns the low byte (least significant byte) of the given expression. • • • • High(expression). This function returns the second byte of the given expression. • Lwrd(expression). This function returns the lower word (bit 0 to 15) of the given expression. • Hwrd(expression). This function returns the higher word (bit 16 to 31) of the given expression. • • • • • Page(expression). This function returns bit 16 to 21 of the given expression. • q7(expression). This function converts a fractional floating-point expression to a form suitable for the fmul/fmuls/fmulsu instructions. (sign + 7-bit fraction) • q15(expression). This function converts a fractional floating-point expression to the form returned by the fmul/fmuls/fmulsu instructions. (sign+15-bit fraction) • • abs(expression). This function returns the absolute value of the expression. • STRLEN(string) returns the length of a string constant, in bytes. Byte2(expression). This function is the same as high. Byte3(expression). This function returns the third byte of the given expression. Byte4(expression). This function returns the fourth byte (most significant byte) of the given expression. Exp2(expression). This function returns 2**expression. Log2(expression). This function returns the integer part of log2(expression). Int(expression). This function truncates a floating-point expression to an integer. Frac(expression). This function extracts the fractional part of a floating-point expression. DEFINED(symbol). Returns true if symbol is previously defined using .equ/.set/ .def directives. Normally used in conjunction with .if directives (.if defined(foo)), but may be used in any context. It differs from other functions in that parentheses around its argument are not required, and that it only makes sense to use a single symbol as argument. Example 3.4 ▼ Write a sequence of instructions that use AVR assembler functions to place the value represented by the label ibuf into the register pair r26 and r27. Solution: ldi ldi r 26,low(ibuf) r27,high(ibuf) ; r26 also can be written as XL ; r27 also can be written as XH ▲ 3.3.3 Operators The AVR assembler supports a number of operators. The user can use them to form expressions in their assembly programs. These operators are listed in Table 3.1. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 3.3 Symbol ■ 45 Expressions Operation Description Example ! Logical NOT This operator returns 1 if the expression is zero. !0xF0 ∼ Bitwise NOT This operator toggles every bit of the expression. ~0x0F - Unary minus This operator negates the given expression. -2 ∗ Multiplication This operator returns the product of two operands. label*2 / Division This operator returns the integral quotient. label/2 + Addition This operator returns the sum of operands. c1 + c2 - Subtraction This operator returns the difference of two operands. c1 - c2 V Shift left This operators returns the left expression shifted left a number of times given by the right expression. 1V4 W Shift right This operator returns the left expression shifted right a number of times given by the right expression. c1 W c2 6 Less than This operator returns 1 if the signed expression to the left is less than the signed expression to the right. bmask* (c1 6 c2) + 1 6= Less or equal This operator returns 1 if the signed expression to the left is less or equal to the signed expression to the right. bmask* (c16= c2) = 1 7 Greater than This operator returns 1 if the signed expression to the left is greater than the signed expression to the right. bmask* (c1 7 c2) + 1 7= Greater or equal This operator returns 1 if the signed expression to the left is greater than or equal to the signed expression to the right. bmask* (c1 7= c2) + 1 == Equal This operator returns 1 if the signed expression to the left is equal to the signed expression to the right. bmask* (c1 = = c2) + 1 != Not equal This operator returns 1 if the signed expression to the left is not equal to the signed expression to the right. .set flag = (c1 != c2) & Bitwise AND This operator returns the bitwise AND of two expressions. (c1 & c2) ∧ Bitwise XOR This operators returns the bitwise XOR of two expressions. c1 ^ c2 | Bitwise OR This operator returns the bitwise OR of two expressions. c1 | c2 || Logical OR This operator returns 1 if one or both expressions are nonzero. c1 || c2 && Logical AND This operator returns 1 if both expressions are nonzero. c1 && c2 Source: Atmel Corporation, The Atmel AVR Microcontroller Table 3.1 ■ Operators supported by the AVR assembler 3.3.4 Formats of Constants The AVR assembler accepts numbers represented in binary, octal, decimal, and hexadecimal. Both the decimal and hexadecimal bases have been used in Chapter 2 and the previous sections of this chapter. B I N A R Y C O N S TA N T S There are four possible formats for representing a binary constant: 1. Adding a lowercase b as the suffix to a binary value. For example, 1010b, 10101011b, and so on. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 46 Chapter 3 ■ AVR Assembly Language Programming 2. Adding an uppercase B as the suffix to a binary value. For example, 1010B, 10101111B, and so on. 3. Adding a lowercase b as the prefix to a single-quoted binary number. For example, b'101011', b'01011101', and so on. 4. Adding an uppercase B as the prefix to a single-quoted binary number. For example, B'1110111', B'10110110', and so on. O C TA L C O N S TA N T S 1. Adding a lowercase q as the suffix to an octal value. For example, 1234q, 1234Q, and so on. 2. Adding an uppercase Q as the suffix to an octal value. For example, 1347Q, 4371Q, and so on. 3. Adding a lowercase q as the prefix to a single-quoted binary number. For example, q'1224', q'432105', and so on. 4. Adding an uppercase Q as the prefix to a single-quoted binary number. For example, Q'1177', Q'7654321', and so on. D E C I M A L C O N S TA N T S 1. Adding neither suffix nor prefix to the decimal value. For example, 1234, -1, and so on. This is the default format. 2. Adding a lowercase d as the prefix to a single-quoted decimal value. For example, d'2345', d'334456', and so on. 3. Adding an uppercase D as the prefix to a single-quoted decimal value. For example, D'2356', D'9843210', and so on. H E X A D E C I M A L C O N S TA N T S 1. Adding a lowercase h as the suffix to a hexadecimal value that is preceded by a 0. For example, 0ABCDEh, 023450h, and so on. 2. Adding an uppercase H as the suffix to a hexadecimal value that is preceded by a 0. For example, 0A8B30H, 0CDEF0031H, and so on. 3. Adding a 0x pair as the prefix to a hexadecimal value. For example, 0x1234, 0xFFFC, and so on. 4. Adding a lowercase h as the prefix to a single-quoted hexadecimal value. For example, h'3344', h'ABCDEF00', and so on. 5. Adding an uppercase H as the prefix to a single-quoted hexadecimal value. For example, H'6543', H'FFFC', and so on. 3.4 Memory Class The AVR microcontroller has separate program memory and data memory. In addition, some of the AVR devices also have on-chip EEPROM. To distinguish the type of memory space being accessed, the AVR assembler divides the memory into three classes: code memory, data memory, and EEPROM memory. A segment of space in one of these spaces is referred to as Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 3.5 ■ 47 Assembler Directives data segment, program segment, or EEPROM segment. The AVR assembler provides assembler directives for specifying the type of memory segment being accessed. A location counter is assigned to each segment during the assembly process so that the assembler knows where to place the next code or data byte. 3.5 Assembler Directives The Atmel AVR assembler supports a number of directives. The directives are not translated into machine code. Instead, they are used to adjust the location of the program in memory, define macros, initialize memory, and so on. The set of directives supported by the Atmel AVR assembler is listed in Table 3.2. All directives must be preceded by a period character. Directive Description byte Reserve byte cseg Code segment db Define constant byte(s) def Define a symbolic name to a register device Define the device to assemble for dseg Data segment dw Define constant word(s) endmacro End macro equ Set a symbol equal to an expression eseg EEPROM segment exit Exit from file include Read source from the specified file list Turn on listfile generation listmac Turn on macro expansion macro Begin macro nolist Turn off listfile generation org Set location counter set Set a symbol to an expression Source: Atmel Corporation, The Atmel AVR Microcontroller Table 3.2 ■ AVR assembler directives 3.5.1 The BYTE Directive This directive is used to reserve memory spaces in the SRAM. The user can add a label to the left of this directive so that he or she can use the label to refer to the reserved memory locations. This directive can only be used with the data segment. The syntax of this directive is as follows: [label:] .byte expression Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 48 Chapter 3 ■ AVR Assembly Language Programming Example 3.5 ▼ Use the byte directive to reserve 20 bytes in data memory space and write a sequence of instructions to load the first byte of this buffer into register r2. Solution: buf: .dseg .byte … .cseg ldi ldi ld 20 ; start a new data segment ; reserve 20 bytes XL,low(buf) XH,high(buf) r2,X ; start a new code segment ; load X register low ; load X register high ; load the byte pointed by X to r2 ▲ 3.5.2 The CSEG Directive This directive defines the start of a code segment. An assembly file may consist of several code segments, which are concatenated into one code segment when being assembled. The location counter associated with each code segment is a word counter. The org directive can then be used to place code and constants at specific locations in the program memory. This directive does not take any parameters. The syntax of this directive is .cseg 3.5.3 The DB Directive This directive initializes program memory or EEPROM with 8-bit values. The syntax of this directive is [label:] .db expressionlist Example 3.6 ▼ Use the db directive to define an array of 8-bit elements 1, 2, …, 10 and a string “Happy birthday!”. Solution: The array is defined as follows: array: .db 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 The string is defined as follows: string: .db “Happy birthday!”,0 ; terminate the string with a NULL (ASCII code is 0) character ▲ 3.5.4 The DEF Directive This directive allows the user to use a symbol to refer to a register. Using a symbol to refer to a register makes the program more readable. The syntax of this directive is .def symbol = register Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 3.5 ■ 49 Assembler Directives Example 3.7 ▼ Use the def directive to redefine register r4 as index. Solution: .def index = r4 ▲ 3.5.5 The DEVICE Directive The user uses this directive to tell the assembler which device the code is to be executed on. If this directive is used, a warning is issued if an instruction not supported by the specified device occurs in the code. If the size of the code segment or EEPROM segment is larger than that supported by the specified device, a warning is issued. If the device directive is not use, it is assumed that all instructions are supported and that there are no restrictions on memory sizes. The syntax of this directive is .device device_name For example, the following statement tells the assembler that the code is to be executed on the XMega128A1: .device ATXMega128A1 3.5.6 The DSEG Directive This directive defines the start of a new data segment. An assembler file may consist of several data segments, which are concatenated into one data segment when assembled. A data segment normally consists of byte directives (and labels). The syntax of this directive is .dseg The following two directives start a new data segment and reserve 20 bytes for an array: obuf: .dseg .byte 20 3.5.7 The DW Directive This directive initializes program memory or EEPROM with 16-bit values. The syntax of this directive is [label:] .dw expressionlist ; label is optional Example 3.8 ▼ Give an example of the use of the dw directive. Solution: An example of the use of the dw directive is as follows: constArr: .cseg .dw 0, 0xFFFF, 0x7FFF, 65536 ▲ 3.5.8 The MACRO and ENDMACRO Directives A macro is a name assigned to a group of instructions or directives. There are situations in which the same sequence of instructions must be included in several places. This sequence Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 50 Chapter 3 ■ AVR Assembly Language Programming of instructions may operate on different parameters. By placing this sequence of instructions in a macro, the instruction sequence need be typed only once. After defining the macro, the programmer can place the macro name in places where the same sequence of instructions has to be executed. The macro capability not only makes the programmer more productive but also makes the program more readable. The keyword macro starts a new macro definition, whereas the keyword endm terminates the macro definition. A macro may refer to as many parameters as needed. A parameter of the macro is referred to by using the @ character. The parameters of a macro are referred to as @0, @1, @2, and so on. The syntax of macro and endmacro is .macro … … .endmacro macroname The following macro subtracts a 16-bit immediate value from two registers: .macro subi sbci .endmacro sub16I @0,low(@2) @1,high(@2) ; @0 and @2 are the 0th and 2nd macro parameter ; @1 is the 1st macro parameter To subtract the 16-bit value 0x1234 from registers r17:r16, invoke the following statement (r16 holds lower byte): sub16I r16,r17, 0x1234 The following macro loads the address of a memory location into the X, Y, or Z register: .macro ldi ldi .endmacro setPointer @0,low(@2) @1,high(@2) For example, the following macro call loads the address of the data memory location represented by the label array into X: setPointer XL,XH,array ; XL and XH refer to register r26 and r27, respectively 3.5.9 The EQU Directive The equ directive assigns a value to a label. This label can then be used in later expressions. A label assigned to a value by the equ directive is a constant and cannot be changed or redefined. The syntax of the equ directive is .equ label = expression Example 3.9 ▼ Give a few examples of the use of the equ directive. Solution: .equ .equ .equ TRUE = 1 FALSE = 0 NN = 100 ▲ Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 3.5 ■ 51 Assembler Directives 3.5.10 The ESEG Directive This directive defines the start of an EEPROM segment. An assembly file may consist of several EEPROM segments, which are concatenated into one EEPROM segment when assembled. An EEPROM segment has its own location counter. The org directive is used to place constants at specific locations in the EEPROM. The syntax of this directive is .eseg 3.5.11 The EXIT Directive The exit directive tells the assembler to stop assembling the file. Normally, the assembler runs until the end of the assembly program file. If the exit directive appears in an assembly file, then the assembler skips the remaining statements of the file. The syntax of the directive is .exit 3.5.12 The INCLUDE Directive This directive tells the assembler to start reading from a specified file. The assembler processes the include file until the end of the file or the exit statement. The syntax of this directive is .include “filename” The following statement inserts the iodefs.asm file into the program: .include “iodefs.asm” 3.5.13 The LIST and NOLIST Directives The assembler generates a listfile which is a combination of assembly source code, addresses, and opcodes. Listfile generation is turned on by default. However, it can also be turned off by using the nolist directive. The list directive tells the assembler to turn on listfile generation. By using the list directive together with nolist directive, the programmer can generate listfile of selected parts of the assembly source code. The syntaxes of these two directives are .list .nolist The following statements illustrate this idea: .nolist .include “macro.inc” .include “const.def” .list ; disable listfile generation ; the included files are not shown ; in the listfile ; re-enable listfile generation 3.5.14 The LISTMAC Directive This directive tells the assembler that when a macro is called, the expansion of the macro is to be shown on the listfile generated by the assembler. By default, only the macro-call statement is shown in the listfile. The syntax of this directive is .listmac 3.5.15 The ORG Directive This directive sets the active location counter to an absolute value. The value to set is given as a parameter. When the org statement does not include an absolute value, the assembler sets the location counter to an appropriate default value. The default values of the code and Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 52 Chapter 3 ■ AVR Assembly Language Programming EEPROM location counters are zero, whereas the default value of the SRAM location counter is 32 (because CPU registers occupy addresses 0 to 31). Note that the EEPROM and SRAM location counters count bytes whereas the program memory location counter counts words. The syntax of this directive is .org expression Example 3.10 ▼ Use assembler directives to reserve 20 bytes in data memory starting from address 0x20. Solution: buffer: .dseg .org .byte 0x20 20 ▲ 3.5.16 The Set Directive This directive assigns a value to a label. This label can then be used in later expressions. A label assigned to a value by the set directive can be changed later in the program. The syntax of this directive is .set label = expression Example 3.11 ▼ Give a few examples of the use of the set directive. Solution: .set .set .cseg clr out io_offset = 0x23 PORTA = io_offset + 2 r2 PORTA,r2 ▲ 3.6 AVR Assembly Program Template The block of program memory starting from address 0 up to a certain location (device dependent) is reserved for handling resets and interrupts. The AVR device that has the most interrupt sources reserves 0xF6 words for this purpose. Other AVR devices with fewer interrupt sources reserve fewer words for reset and interrupt handling. Two words are allocated to the reset and each interrupt source. The user program should be stored after this block. After power on reset, the AVR microcontroller starts to execute the program from address 0. Because two words are not enough to handle reset, a common practice is to place a jmp instruction at the program memory location 0, to jump to the memory location for handling reset. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 3.7 ■ 53 Software Development Issue When writing an AVR assembly program, we need to add the include file of the target microcontroller. This file contains the definitions of peripheral registers (also called I/O registers) and bits of these registers. By including the MCU include file, we are able to use symbolic names to access I/O registers and their bits. After reserving space for handling reset and interrupts, an assembly program would look like (using the AVR assembler) .include .org jmp … org … start: 6xxx.inc7 0x00 start ; xxx is the AVR device name 0xF6 3.7 Software Development Issue Experience tells us that developers spent much more time on software development than hardware design during the development period of an embedded product. To become an effective software developer, we need to • • • • • Learn a systematic software development methodology. Learn to develop the algorithm for problem solving. Learn to develop reusable software. Learn to use software tools to perform software debugging. Follow a good programming style to make the program more readable and easier to debug. A complete discussion of issues involved in software development is beyond the scope of this text. However, we discuss them here whenever it is possible. Software development starts with problem definition. The problem presented by the application must be fully understood before any program can be written. At the problem definition stage, the most critical thing is to get the programmer and the end user to agree upon what needs to be done. To achieve this, asking questions is very important. For complex and expensive applications, a formal, written definition of the problem is formulated and agreed upon by all parties. Once the problem is known, the programmer can begin to lay out an overall plan for solving the problem. The plan is also called an algorithm. Informally, an algorithm is any welldefined computational procedure that takes some value or a set of values as input and produces some value or a set of values as output. An algorithm is thus a sequence of computational steps that transforms the input into the output. We can also view an algorithm as a tool for solving a well-specified computational problem. The statement of the problem specifies in general terms the desired input/output relationship. The algorithm describes a specific computational procedure for achieving that input/output relationship. An algorithm is expressed in pseudocode that is very much like C or PASCAL. What separates pseudocode from “real” code is that in pseudocode, we employ whatever expressive method is most clear and concise to specify a given algorithm. Sometimes, the clearest method is English, so do not be surprised if you come across an English phrase or sentence embedded within a section of “real” code. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 54 Chapter 3 ■ AVR Assembly Language Programming An algorithm provides not only the overall plan for solving the problem but also the documentation to the software to be developed. In the rest of this book, all algorithms are presented in the following format: Step 1 …. Step 2 …. An example of an algorithm that generates a 1 kHz waveform from the PORTE pin 0 is as follows: Step 1 Pull the pin 0 of PORTE to high. Step 2 Wait for 0.5 ms. Step 3 Pull the pin 0 of PORTE to low. Step 4 Wait for 0.5 ms. Step 5 Go to Step 1. An earlier alternative for providing the overall plan for solving software problems was the use of flowcharts. A flowchart shows the way a program operates. It illustrates the logic flow of the program. Therefore, flowcharts can be a valuable aid in visualizing programs. Flowcharts are used not only in computer programming but also in many other fields, such as business and construction planning. The flowchart symbols used in this book are shown in Figure 3.1. The start/stop symbol is used at the beginning and the end of each program. When it is used at the beginning of a program, the word Start is written inside it. When it is used at the end of a program, it contains the word Stop. The operation box indicates what must be done at this point in the program execution. The operation specified by the process box could be sending the contents of one general-purpose register to a peripheral register, setting a flag, and so on. The I/O operation box is used to specify what data are to be read or displayed by the microcontroller. The decision box has a question to which the answer could be yes or no. When the answer is yes, the computer takes one action. When the answer is no, the computer takes a different action. The subroutine box represents the start of a sequence of instructions that may be called from many places within a program. The place that calls a subroutine should use an arrow to specify the entrance connector of the subroutine, and the places to be returned from the subroutine should have a connector identical to the exit connector of the subroutine. The issues related to subroutine are discussed in Chapter 5. The on-page connector enables the flowchart to continue elsewhere on the same page. The place where it is continued has the same label as the on-page connector. The off-page connector allows the flowchart to continue on a different page. The place where the flowchart continues can be found by locating the matching off-page connector in the following pages. The normal flow of a flowchart is from top to bottom and from left to right. Any line that does not follow this normal flow should have an arrowhead on it. When the program gets Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. ■ 55 Writing Programs to Perform Arithmetic α Start/Stop Operation Subprogram Input or output β Off-page connector Decision making Yes α On-page connector No Figure 3.1 ■ Source: Atmel Corporation, The Atmel AVR Microcontroller 3.8 Flowchart symbols used in this book complicated, the flowchart that documents the logic flow of the program also becomes difficult to follow. This is the limitation of the flowchart. In this book, we mix the use of flowcharts and the algorithm procedures to describe the solution to a problem. After the programmer is satisfied with the algorithm or the flowchart, it is converted to source code in one of the assembly or high-level languages. Each statement in the algorithm (or each block of the flowchart) is converted to one or multiple assembly instructions or highlevel language statements. If an algorithmic step (or a block in the flowchart) requires many assembly instructions or high-level language statements to implement, then it might be beneficial to either (1) convert this step (or block) into a subroutine and just call the subroutine, or (2) further divide the algorithmic step (or flowchart block) into smaller steps (or blocks) so that it can be coded with just a few assembly instructions or high-level language statements. This process is referred to as top-down design with hierarchical refinement and is considered to be the most efficient software development methodology. The next major step is testing the program. Testing a program means testing for anomalies. The first test is for normal inputs that are always expected. If the result is what is expected, then the borderline inputs are tested. The maximum and minimum values of the input are tested. When the program passes this test, then illegal input values are tested. If the algorithm includes several branches, then enough values must be used to exercise all of the possible branches. This is to make sure that the program operates correctly under all possible circumstances. In the rest of this book, most of the problems are well defined. Therefore, our focus is on how to design the algorithm that solves the specified problem as well as how to convert the algorithm into source code. 3.8 Writing Programs to Perform Arithmetic In Chapter 2, we learned how to write instruction sequences to perform simple arithmetic. In this chapter, we now learn how to write complete programs that can be simulated using the software simulator or executed using a hardware demo board. In this section and the rest of the chapter, we use short programs that perform simple calculations to demonstrate how to write an assembly program. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 56 Chapter 3 ■ AVR Assembly Language Programming Example 3.12 ▼ Write a program to add the 8-bit numbers stored at data memory locations 0x20 and 0x21, and save the sum at data memory location 0x30. Solution: The procedure to add the 8-bit numbers stored at two data memory locations is as follows: Step 1 Load the contents of the data memory location at 0x20 to a register (for example, R1). Step 2 Load the contents of the data memory location 0x21 to another register (for example, R2). Step 3 Add the contents of R1 to R2. Step 4 Store the contents of R2 in the data memory location at 0x30. The program that implements this algorithm is as follows: start: .include .org jmp .org lds lds add sts 6xxxxxdef.inc7 0x00 start 0xF6 r1,0x20 r2,0x21 r2,r1 0x30,r2 ; xxxxx represents one of the Mega or XMega MCU ; copy the contents of the data memory location at 0x20 to R1 ; copy the contents of the data memory location at 0x21 to R2 ; add two numbers together ; store the sum at 0x30 The first line of the program inserts the register and bit definitions for an AVR MCU. Depending on the device being used, the user should include the appropriate include file (for example, m2560def.inc). ▲ Example 3.13 ▼ Write a program that adds 5 to data memory locations 0x21, 0x22, and 0x23, respectively. Solution: The procedure to add 5 to 0x21 is as follows: Step 1 Place 5 in register R16. Step 2 Copy the contents of the data memory location in 0x21 to R1. Step 3 Add R16 to R1. Step 4 Store the contents of R1 in data memory location 0x21. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 3.8 ■ Writing Programs to Perform Arithmetic 57 The assembly program that performs the specified operation is as follows: start: .include .org jmp .org ldi lds add sts lds add sts lds add sts 6m1280def.inc7 0x00 start 0xF6 r16,5 r1,0x21 r1,r16 0x21,r1 r1,0x22 r1,r16 0x22,r1 r1,0x23 r1,r16 0x23,r1 ; ; place 5 in R16 ; copy the contents of the data memory location 0x21 to R1 ; R1 6- R1 + 5 ; store the sum at the data memory location 0x21 ; load the contents of the data memory location 0x22 into R1 ; add 5 to this copy ; save the sum back to data memory location 0x22 ; load the contents of the data memory location 0x23 into R1 ; add 5 to this copy ; save the sum back to data memory location 0x23 ▲ 3.8.1 The Carry/Borrow Flag Bit 7 of the status register (SREG) register is the carry (C) flag. The C flag is affected by all of the AVR addition and subtraction instructions. The sum of two 8-bit numbers may or may not be held in an 8-bit register. For this reason, the AVR uses the C flag to hold the most significant bit of the sum of two 8-bit numbers. For example, the execution of the following three instructions yields the sum of 0x131, and the C flag is set to 1: ldi ldi add r16,0x98 r17,0x99 r16,r17 When the sum of two 8-bit numbers can be held in an 8-bit register, the C flag is cleared to 0. For example, the execution of the following three instructions sets the C flag to 0 because the sum of 0x35 and 0x42 is 0x77: ldi ldi add r16,0x35 r17,0x42 r16,r17 In summary, the C flag is set to 1 or 0 during an addition depending on whether there is a carry out. 3.8.2 Multiprecision Addition When two numbers longer than 8 bits are to be added, the user must program the AVR to add one byte at a time and proceed from the least significant byte (lsb) toward the most significant byte (msb) with carry out included in all except the least significant byte addition. Addition performed in this manner is referred to as multiprecision addition. Multiprecision addition makes use of the carry flag in the SREG. The next example illustrates the procedure of multiprecision addition. In this book, we store the lsb to msb of a multibyte number in memory locations from low to higher addresses. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 58 Chapter 3 ■ AVR Assembly Language Programming Example 3.14 ▼ Write a program to add two 4-byte numbers stored at num1~num1+3 and num2~num2+3, respectively, in program memory. Save the sum at sum~sum+3 in data memory. Solution: The addition should start from the lsb toward the msb. The carry bit must be included in the addition in all except the lsb. The assembly program that adds two 4-byte numbers is as follows: .include .dseg .org num1: .byte num2: .byte sum: .byte .cseg .org jmp .org start: lds lds add sts lds lds adc sts lds lds adc sts lds lds adc sts // end of the program 6m2560def.inc7 0x200 ; start from data memory location at 0x200 (set to 0x2000 for ; ATXMega MCUs) 4 4 4 0x00 start 0xF6 r0,num1 r1,num2 r0,r1 sum,r0 r0,num1+1 r1,num2+1 r0,r1 sum+1,r0 r0,num1+2 r1,num2+2 r0,r1 sum+2,r0 r0,num1+3 r1,num2+3 r0,r1 sum+3,r0 ; fetch the lsb of num1 ; fetch the lsb of num2 ; add the lsbs of two numbers ; save the lsb of sum ; fetch the second lsb of num1 ; fetch the second lsb of num2 ; add two bytes together ; save the sum of second lsbs ; fetch the second msb of num1 ; fetch the second msb of num2 ; add two bytes together ; save the sum of second msbs ; fetch the msb of num1 ; fetch the msb of num2 ; add the msbs of two numbers ; save the msb of sum ▲ 3.8.3 The C Flag and Subtraction The C flag enables the AVR to borrow from the high byte to the low byte during a multiprecision subtraction. The C flag operates as follows during a subtraction: • The C flag is set to 1 when the subtrahend is larger than the minuend during a subtraction. • The C flag is cleared to 0 when the subtrahend is equal to or smaller than the minuend during a subtraction. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 3.8 ■ 59 Writing Programs to Perform Arithmetic 3.8.4 Multiprecision Subtraction Multiprecision subtraction is the subtraction of numbers that are longer than one byte for an 8-bit microcontroller. For the AVR, multiprecision subtraction is performed one byte at a time from the lsb toward the msb with the C flag involved to take care of the required borrow. The next example illustrates the process. Example 3.15 ▼ Write a program to subtract the four-byte number stored at 0x200~0x203 from the fourbyte number stored at 0x204~0x207 and save the difference at 0x210~0x213. Solution: Subtraction proceeds from the lsb toward the msb. .include .dseg .org num1: num2: diff: .byte .byte .byte .cseg .org jmp .org start: lds lds sub sts lds lds sbc sts lds lds sbc sts lds lds sbc sts // end of the program 6m2560def.inc7 0x200 ; start from data memory location 200 (set to 0x2000 for ; ATXMega MCUs) 4 4 4 0x00 start 0xF6 r1,num1 r0,num2 r0,r1 diff,r0 r1,num1+1 r0,num2+1 r0,r1 diff+1,r0 r1,num1+2 r0,num2+2 r0,r1 diff+2,r0 r1,num1+3 r0,num2+3 r0,r1 diff+3,r0 ; fetch the lsb of num1 ; fetch the lsb of num2 ; subtract the lsbs of two numbers ; save the lsb of difference ; fetch the msb of num1 ; fetch the msb of num2 ; subtract the msbs of two numbers ; save the msb of difference ▲ 3.8.5 Multiplication and Division The AVR provides three instructions (mul, muls, and mulsu) that can multiply two 8-bit integers and three instructions (fmul, fmuls, and fmulsu) that can multiply two 8-bit fractions. The products of these instructions are stored in the register pair r1:r0. These instructions are listed in Table 3.3. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 60 ■ Chapter 3 AVR Assembly Language Programming Mnemonics Description Operation Multiply unsigned R1:R0 ← [Rd] 3 [Rr] (UU)(4) Multiply signed R1:R0 ← [Rd] 3 [Rr] (SS)(4) mulsu Rd, Rr Multiply signed with unsigned R1:R0 ← [Rd] 3 [Rr] (SU)(4) fmul Rd, Rr(3) Fractional multiply unsigned R1:R0 ← [Rd] 3 [Rr] 66 1 (UU)(4) fmuls Rd, Rr Fractional multiply signed R1:R0 ← [Rd] 3 [Rr] 66 1 (SS)(4) fmulsu Rd, Rr(3) Fractional multiply signed with unsigned R1:R0 ← [Rd] 3 [Rr] 66 1 (SU)(4) (1) mul Rd, Rr muls Rd, Rr(2) (3) (3) Note: 1. 0 # d # 31; 0 # r # 31 2. 16 # d # 31; 16 # r # 31 3. 16 # d # 23; 16 # r # 23 4. U: unsigned; S: signed Source: Atmel Corporation, The Atmel AVR Microcontroller Table 3.3 ■ AVR multiply instructions Example 3.16 ▼ Write an instruction sequence to multiply the 8-bit unsigned integers stored at data memory locations 0x200 and 0x201 and save the product at data memory locations 0x202~0x203. Place the lower and upper bytes in 0x202 and 0x203, respectively. Solution: We have to place these two integers in two registers before the multiplication. .include .cseg .org jmp .dseg .org num1: .byte num2: .byte prod: .byte .cseg .org start: lds lds mul sts sts // end of program 6m2560def.inc7 0x00 start 0x200 1 1 2 0xF6 r2,num1 r3,num2 r2,r3 prod,r0 prod+1,r1 ; load the first number into r2 ; load the second number into r3 ; save the low byte of product ; save the high byte of product ▲ The fractional multiplication is often used in digital signal processing. Let (N.Q) denote a fractional number with N binary digits to the left of the radix point, and Q binary digits to the right of the radix point. A multiplication between two numbers in the formats (N1. Q1) and (N2.Q2) results in the format ((N11N2).(Q11Q2)). For signal processing applications, Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 3.9 ■ Accessing Data in Data and Program Memory 61 the format (1.7) is widely used for the inputs, resulting in a (2.14) format for the product. A left shift is required for the high byte of the product to be in the same format as the inputs. The FMUL instruction (also true for FMULS and FMULSU) incorporates the shift operation in the same number of cycles as MUL. The (1.7) format is most commonly used with signed numbers, whereas FMUL performs an unsigned multiplication. This instruction is therefore most useful for calculating one of the partial products when performing a signed multiplication with 16-bit inputs in the (1.15) format, yielding a result in the (1.31) format. Note: The result of the FMUL operation may suffer from a 2’s complement overflow if interpreted as a number in the (1.15) format. The most significant bit of the multiplication before shifting must be taken into account, and is found in the carry bit. The AVR does not provide any divide instruction. The programmer must write a subroutine to implement this operation. We deal with this issue in Chapter 5. 3.9 Accessing Data in Data and Program Memory When developing a program, the programmer must provide test data to find out whether the program that he or she develops works correctly. The db and dw directives can be used to define test data for testing the programs under development. There are two steps for accessing data stored in the program memory: Step 1 Place the address of data in program memory in the Z register. Step 2 Execute an lpm or elpm instruction. To access data in program memory, we need to use the Z register as a pointer to the data. Because the location counter of program memory counts words instead of bytes, a label in program memory represents a word address (= byte address,2). We have to multiply a word address by 2 to translate it to a byte address. Multiplication by 2 can be performed by shifting a number to the left by one position (num 66 1). Example 3.17 ▼ Write an instruction sequence to load the contents of the program memory location with the label parray into register r1. Solution: ldi ldi lpm r30,low (parray661) ; load the address of the specified program memory r31,high (parray661) ; location into the register z r1, z ; load memory contents into r1 The AVR can access a data memory location by specifying its address directly or via a pointer. Using a pointer is more efficient when the program must access many memory locations or the whole array. ▲ Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 62 Chapter 3 ■ AVR Assembly Language Programming Example 3.18 ▼ Write an instruction sequence to load the contents of the program memory location with the label parray and store it in the data memory location with the label obuf. Solution: The following instruction sequence fetches the specified program memory contents and then stores it at the specified data memory location: ldi ldi lpm sts r30,low (parray661) r31,high (parray661) r0, z obuf, r0 If a pointer to the data memory is desired, then the following instruction sequence should be used: ldi ldi lpm ldi ldi st ZL,low (parray661) ZH, high (parray661) r0, z XL, low (obuf) XH, high (obuf) x, r0 ; set up register z to point to program memory location ; at parray ; set up register x to point to obuf ; set up register x to point to obuf ; store r0 in the data memory location pointed to by x ▲ 3.10 Writing Program Loops Microcontrollers are good at performing repetitive operations. To command a microcontroller to perform a repetitive operation, the user must write a program loop. There are two types of program loops: a finite loop and an infinite loop. A finite loop is a sequence of instructions that are executed only a finite number of times whereas an infinite loop is one in which the microcontroller stays forever. 3.10.1 The Infinite Loop The AVR provides four unconditional jump instructions (listed in Table 3.4) that can be used to implement infinite loop. The distance for the rjmp instruction is 2 kW (forward or backward). The jump distance for the jmp instruction is 4 MW. An infinite loop has the following format: forever: … … rjmp forever Mnemonics ; rjmp can be replaced by one of the other jump instructions Description Operation PC ← [PC] 1 k 1 1 rjmp k Relative jump ijmp Indirect jump to (Z) PC(15:0) ← [Z], PC(21:16) ← 0 eijmp Extended indirect jump to (Z) PC(15:0) ← [Z], PC(21:16) ← EIND jmp k Jump PC(15:0) ← k Source: Atmel Corporation, The Atmel AVR Microcontroller Table 3.4 ■ AVR unconditional jump instructions Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 3.10 ■ 63 Writing Program Loops The jump distance can be positive or negative depending on whether the jump direction is backward or forward. In practice, the programmer simply uses a label to specify the jump destination and let the assembler figure out the appropriate value to be placed in the machine instruction. A finite loop can be implemented by using one of the following three constructs: • • • For-loop While-loop Repeat-until loop 3.10.2 The For-Loop The syntax of a for-loop is For i = n1 to n2 do S or For i = n2 downto n1 do S i ← i1 i ≤ i2 Yes i←i+1 Figure 3.2a S ■ No For i = i1 to i2 Do S (b) i ← i2 i ≥ i1 Yes i←i–1 Figure 3.2b S ■ No Source: Atmel Corporation, The Atmel AVR Microcontroller (a) Source: Atmel Corporation, The Atmel AVR Microcontroller where i is the loop index, which runs from n1 to n2 or from n2 down to n1, depending on the format used (n2 $ n1). The two alternatives for implementing the for-loop are shown in Figure 3.2. For i = i2 to i1 Do S The implementation of a for-loop requires the use of a compare instruction to set up the branch condition, a conditional branch instruction to carry out the action of branch, and an arithmetic instruction (such as inc or dec) to update the loop index variable. The compare and conditional branch instructions provided by AVR are listed in Table 3.5 and Table 3.6. Among them, the breq instruction along with the cp (compare) and the inc (or dec) instruction can be used to implement the for-loop construct. A for-loop can be implemented in the following manner: floop: exitloop: .include .equ .equ .def … ldi cpi breq … … inc rjmp .. 6m2560def.inc7 n1=1 ; loop index lower bound n2=30 ; loop index upper bound ii = r16 ; use r16 for-loop index ii ii, n1 ii, n2+1 exitloop ii floop ; initialize ii to n1 ; set up loop exit condition ; branch if loop exit condition is met ; perform loop operation ; " ; update loop index Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 64 Chapter 3 ■ AVR Assembly Language Programming Mnemonics Description Operation cpse Rd, Rr Compare, skip if equal If ([Rd] = = [Rr]) PC ← [PC] 1 2 or 3 cp Rd, Rr Compare [Rd] 2 [Rr], and update Z, C, N, V, S, H cpc Rd, Rr Compare with carry [Rd] 2 [Rr]2 C, and update Z, C, N, V, S, H cpi Rd, k Compare with immediate [Rd] 2 k, and update Z, C, N, V, S, H; 0 # k # 255 Source: Atmel Corporation, The Atmel AVR Microcontroller Table 3.5 ■ Mnemonics AVR compare instructions Description Operation sbrc Rr, b Skip if bit in register cleared If (Rr(b) = = 0) PC ← [PC] 1 2 or 3 sbrs Rr, b Skip if bit in register set If (Rr(b) = = 1) PC ← [PC] 1 2 or 3 sbic A, b Skip if bit in I/O register cleared If (I/O(A, b) = = 0) PC ← [PC] 1 2 or 3 sbis A, b Skip if bit in I/O register set If (I/O(A, b) = = 1) PC ← [PC] 1 2 or 3 brbs s, k Branch if status flag set If (SREG(s) = = 1) then PC ← [PC] 1 k 1 1 brbc s, k Branch if status flag cleared If (SREG(s) = = 0) then PC ← [PC] 1 k 1 1 breq k Branch if equal If (Z = = 1) then PC ← [PC] 1 k 1 1 brne k Branch if not equal If (Z = = 0) then PC ← [PC] 1 k 1 1 brcs k Branch if carry set If (C = = 1) then PC ← [PC] 1 k 1 1 brcc k Branch if carry cleared If (C = = 0) then PC ← [PC] 1 k 1 1 brsh k Branch if same or higher If (C = = 0) then PC ← [PC] 1 k 1 1 brlo k Branch if lower If (C = = 1) then PC ← [PC] 1 k 1 1 brmi k Branch if minus If (N = = 1) then PC ← [PC] 1 k 1 1 brpl k Branch if plus If (N = = 0) then PC ← [PC] 1 k 1 1 brge k Branch if greater or equal, signed If (N { V = = 0) then PC ← [PC] 1 k 1 1 brlt k Branch if less than signed If (N { V = = 1) then PC ← [PC] 1 k 1 1 brhs k Branch if half carry set If (H = = 1) then PC ← [PC] 1 k 1 1 brhc k Branch if half carry cleared If (H = = 0) then PC ← [PC] 1 k 1 1 brts k Branch if T flag set If (T = = 1) then PC ← [PC] 1 k 1 1 brtc k Branch if T flag cleared If (T = = 0) then PC ← [PC] 1 k 1 1 brvs k Branch if V flag set If (V = = 1) then PC ← [PC] 1 k 1 1 brvc k Branch if V flag cleared If (V = = 0) then PC ← [PC] 1 k 1 1 brie k Branch if interrupt enabled If (I = = 1) then PC ← [PC] 1 k 1 1 brid k Branch if interrupt disabled If (I = = 0) then PC ← [PC] 1 k 1 1 Source: Atmel Corporation, The Atmel AVR Microcontroller Table 3.6 ■ AVR conditional branch instructions Example 3.19 ▼ Write a program that uses a for-loop to add all the integers from 1 to 100. Solution: Let i, sum, n1, and n2 refer to loop index, sum, the lower limit, and the upper limit, then the algorithm for adding all integers from 1 to 100 is as follows: Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 3.10 ■ 65 Writing Program Loops Step 1 i ← n1; sum ← 0 Step 2 if (i 7 n2) then stop; else sum ← sum + i. Step 3 i ← i + 1; go to Step 2. The program is as follows: .include .equ .equ .dseg .org sum: .byte .def .def .def .cseg .org jmp .org start: ldi ldi ldi ldi loop: cpi breq add adc inc rjmp done: sts sts rjmp // end of program 6m2560def.inc7 n1 = 1 n2 = 100 0x200 2 ii = r16 sumHi = r19 sumLo = r18 0x00 start 0xF6 ii,n1 sumHi,0 sumLo,0 r25,0 ii,n2+1 done sumLo,ii sumHi,r25 ii loop sum,sumLo sum+1,sumHi done ; initialize ii to n1 ; initialize sum to 0 ; " ; place 0 in r25 for use in the for-loop ; check for-loop index limit ; " ; add ii to the low byte of sum ; add carry to high byte (r25 holds 0) ; save the sum in data memory ; " As shown in this program, the loop-index test is done at the start of the loop. The last instruction of the loop is a rjmp instruction that causes the program flow to move to the start of the loop. ▲ 3.10.3 The While-Loop The syntax of a while-loop is as follows: WHILE C DO S Whenever a while-loop construct is executed, the logical expression C is evaluated first. If it yields a false value, statement S is not executed. The action of a while-loop construct is illustrated in Figure 3.3. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 66 Chapter 3 ■ AVR Assembly Language Programming Initialize C True Execute S and update C C False Exit Figure 3.3 ■ Source: Atmel Corporation, The Atmel AVR Microcontroller The flow-control part of a while-loop can be implemented by using one of the conditional branch instructions shown in Table 3.6. The branch decision may be based on the value of a flag bit in the status register, a bit in the CPU register, or a bit in an I/O register. The WHILE ... DO construct Example 3.20 ▼ Write a program to count the number of elements of an array of 8-bit integers that are a multiple of 4. Solution: The algorithm for finding the number of elements that are divisible by 4 is as follows: Use cnt to keep track of the number of elements that are divisible by 4 and use ptr as the pointer to the array element. A number with bit 1 and bit 0 equal to 00 is divisible by 4. Step 1 cnt ← 0; ptr ← array; lpcnt ← array count; use the Z register to point to the first element of the array. Step 2 If (lpcnt = = 0), then exit. Step 3 Fetch the array element pointed by ptr. Step 4 If bit 1 and bit 0 of the fetched element are 00, add 1 to cnt. Step 5 ptr ← ptr +1; lpcnt = lpcnt - 1. Step 6 Go to Step 2. The following program counts the number of array elements that are divisible by 4: .include .def .def .equ .cseg .org rjmp 6m2560def.inc7 count = r16 lpcnt = r17 NN = 30 ; array count 0x00 start Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 3.10 ■ 67 Writing Program Loops .org ldi ldi ldi ldi loop: cpi breq lpm andi brne inc next: dec rjmp done: rjmp array: .db .db .db // end of program start: 0xF6 ZL,low(array661) ; use Z to point to the array element ZH,high(array661) ; " count,0 ; initialize element count to 0 lpcnt,NN ; initialize loop count to NN lpcnt,0 done r18,z+ ; fetch one array element r18,0x03 ; check bit 1 and 0 next ; bit 1 and 0 are not 00, check next element count ; increment element count when bit 1,0 = 00 lpcnt ; decrement loop count loop done 11,12,13,14,15,16,17,18,19,20 21,22,23,24,25,26,27,28,29,30 31,32,33,34,35,36,37,38,39,40 The first four instructions in Table 3.6 are often used to wait for the I/O operations to complete before continuing other operations. For example, the following instruction sequence waits until the A/D conversion is completed before collecting the A/D result: wADC: lds sbrs rjmp … r16,ADCSRS r16,ADIF wADC ; make a copy of the A/D control and status register ; skip the next instruction if ADIF bit (bit 4) is set ; ADIF bit is not set, so jump back to check again ; collect A/D conversion result ▲ 3.10.4 The Repeat-Until Loop The repeat-S-until-C looping construct is used more often to perform some operation for a certain number of times. The following instruction sequence performs a certain operation N times: loop: .equ .def … ldi … … inc cpi brne N = 20 lpcnt = r16 lpcnt,0 lpcnt lpcnt,N loop ; increment loop count ; compare loop count with N ; loop count not equal to N, continue The same loop can also be implemented using the following template: loop: .equ .def … ldi … … dec brne N = 20 lpcnt = r16 lpcnt,N lpcnt,N loop ; perform the desired operation ; " ; decrement loop count ; loop count not zero, continue Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 68 Chapter 3 ■ AVR Assembly Language Programming Example 3.21 ▼ Write a program to find the maximum element of an array of N 8-bit elements using the repeat-S-until-C looping construct. Solution: We use the variable j as the array index and also as the loop count and use the variable maxVal to hold the array maximum. The logic flow of the program is shown in Figure 3.4. The assembly program that finds the maximum element of an array of N 8-bit elements is as follows: Start maxVal ← array[0] j←1 No Yes maxVal ← array[j] j←j+1 No j = N? Yes Stop Figure 3.4 start: loop: .include .equ .def .def .def .cseg .org rjmp .org ldi ldi ldi lpm lpm ■ Source: Atmel Corporation, The Atmel AVR Microcontroller maxVal < array[j] ? Logic flow of Example 3.21 6m2560def.inc7 NN = 30 j = r16 maxVal = r17 tmp = r18 0x00 start 0xF6 ZL,low(array661) ZH,high(array661) j,0 maxVal,z+ tmp,z+ ; total array count ; array index ; maximum array element ; temporary buffer ; set up array pointer ; " ; set array[0] as maximum ; fetch the next array element and move ; pointer Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 3.10 ■ 69 Writing Program Loops cp brlt mov next: inc cpi brne here: rjmp array: .db .db .db // end of program tmp,maxVal next ; branch if next array element is smaller maxVal,tmp ; update the array max j j,NN-1 ; check loop index loop here ; forever loop 11,12,13,14,15,16,17,18,19,20 21,22,23,24,25,26,27,28,29,30 31,92,33,34,35,67,40,50,52,80 ▲ Example 3.22 ▼ Given an array of N 8-bit elements, write a program to swap the first element with the last element, swap the second element with the second-to-last element, and so on. Solution: The major steps for swapping the array are as follows: Step 1 Copy the array from program memory to data memory. Step 2 Let the variable ptr1 (X register) point to the start of the array and let the variable ptr2 (Y register) point to the end of the array. Use lpcnt as the loop count, and set it to half of the array count. Step 3 Fetch the element (call it da) pointed by ptr1, and fetch the element (call it de) pointed to by ptr2. Step 4 Store da to the location pointed to by ptr2, and store de to the location pointed to by ptr1. Increment ptr1 by 1, and decrement ptr2 by 1. Step 5 Decrement lpcnt by 1. Step 6 If (lpcnt = = 0) then stop; else go to Step 3. The following program implements the algorithm described previously: buf1: .include .equ .dseg .org .byte .def .cseg .org rjmp .org 6m2560def.inc7 NN=30 0x200 NN lpcnt = r17 ; buffer to hold the array 0x00 start 0xF6 Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 70 Chapter 3 ■ AVR Assembly Language Programming start: ldi XL,low(buf1) ldi XH,high(buf1) ldi ZL,low(array661) ldi ZH,high(array661) ldi lpcnt,NN cloop: lpm r0,z+ st x+,r0 dec lpcnt brne cloop // swap operation start from here ldi XL,low(buf1) ldi XH,high(buf1) ldi YL,low(buf1+NN) ldi ldi ld ld swloop: YH,high(buf1+NN) lpcnt,NN/2 r0,x r1,-y st st dec brne here: rjmp array: .db .db .db // end of program ; set up pointer to buf1 ; " ; set up pointer to array ; " ; set up loop count to copy array ; loop to copy array to data memory ; " ; X points to the start of the array ; " ; Y points to the byte after the end of the ; array ; " ; loop count for swapping the array ; fetch an element from one side of the array ; fetch an element from other side of the ; array ; store at the other side of the array ; " ; decrement loop count x+,r1 y,r0 lpcnt swloop here 11,12,13,14,15,16,17,18,19,20 21,22,23,24,25,26,27,28,29,30 31,32,33,34,35,36,37,38,39,40 ▲ 3.11 Shift and Rotate Instructions The user may need to manipulate a bit field of a register. To perform this type of operation, the user can use the group of instructions shown in Table 3.7. Any one of the 32 CPU registers can be the operand of these instructions. All rotate and shift instructions involve the C flag in the operation. Mnemonics Description Operation lsl Rd Logical shift left Rd(n 1 1) ← Rd(n), Rd(0) ← 0, C ← Rd(7), n = 0..6 lsr Rd Logical shift right Rd(n) ← Rd(n 1 1), Rd(7) ← 0, C ← Rd(0), n = 0..6 rol Rd Rotate left through carry Rd(n 1 1) ← Rd(n), Rd(0) ← C, C ← Rd(7), n = 0..6 ror Rd Rotate right through carry Rd(n) ← Rd(n 1 1), Rd(7) ← C, C ← Rd(0), n = 0..6 asr Rd Arithmetic shift right Rd(n) ← Rd(n 1 1), n = 0..6; Rd(7) ← Rd(7) swap Rd Swap nibbles Rd(3..0) ↔ Rd(7..4) Source: Atmel Corporation, The Atmel AVR Microcontroller Table 3.7 ■ AVR shift and rotate instructions Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 3.11 ■ 71 Shift and Rotate Instructions Example 3.23 ▼ Assume that the contents of register r1 and carry flag are 0x5D and 1, respectively. What are the new values for r1 and C after the execution of each of the instructions listed in Table 3.7? Solution: The new values of r1 and C after the execution of each instruction in Table 3.7 are as follows: (a) After executing the lsl r1 instruction, the contents of r1 and C are 0xBA and 0, respectively (shown in Figure 3.5a). C Register r1 1 0 Before 1 1 0 1 1 1 0 0 After 0 1 0 1 1 1 0 1 0 Source: Atmel Corporation, The Atmel AVR Microcontroller Figure 3.5a ■ Execution result of lsl r1 (b) After executing the lsr r1 instruction, the contents of r1 and C are 0x2E and 1, respectively (shown in Figure 3.5b). C Register r1 Before 0 1 0 1 1 1 0 1 1 0 0 1 0 1 1 1 0 1 0 After Source: Atmel Corporation, The Atmel AVR Microcontroller Figure 3.5b ■ Execution result of lsl r1 (c) After executing the rol r1 instruction, the contents of r1 and C become 0xBB and 0, respectively (shown in Figure 3.5c). C Before After 0 Register r1 C 0 1 0 1 1 1 0 1 1 0 1 1 1 0 1 1 1 Source: Atmel Corporation, The Atmel AVR Microcontroller Figure 3.5c ■ Execution result of lsl r1 (d) After executing the ror r1 instruction, the contents of r1 and C become 0xAE and 1, respectively (shown in Figure 3.5d). Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 72 Chapter 3 ■ AVR Assembly Language Programming C Register r1 Before 1 0 1 0 1 1 1 0 1 After 1 0 1 0 1 1 1 0 C 1 Source: Atmel Corporation, The Atmel AVR Microcontroller Figure 3.5d ■ Execution result of lsl r1 (e) After executing the swap r1 instruction, the contents of r1 become 0xD5 and the value of C does not change. ▲ A shift-right instruction can be used to divide a number by a power of 2 and a shift-left instruction can be used to multiply a number by a power of 2. When a multibyte number is to be multiplied or divided by a power of 2, we need to shift multiple bytes either to the left or to the right. However, the AVR does not have an instruction that does this. Suppose the number has k bytes and the least significant byte is stored at loc. The remaining bytes are located at loc 1 1, loc 1 2, …, loc 1 k 2 1, respectively, as shown in Figure 3.6. loc loc+1 loc+k–1 ... lsb msb Source: Atmel Corporation, The Atmel AVR Microcontroller Figure 3.6 ■ k bytes to be shifted The logical shift-one-bit-to-the-right operation to this multiple-byte number is performed in the following manner: • Bit 7 of each byte receives bit 0 of its adjacent more significant byte (on its immediate right) with the exception of the most significant byte, which receives a 0. • Each byte is shifted to the right by one bit. Bit 0 of the least significant byte is shifted out and lost. The operation can therefore be implemented as follows: Step 1 Shift the byte at loc + k - 1 to the right one place (using the lsr Rd instruction). Step 2 Rotate the byte at loc + k - 2 to the right one place (using the ror Rd instruction). Step 3 Repeat step 2 for the remaining bytes. By repeating this procedure, the given k-byte number can be shifted to the right as many bits as desired. Because we store the most significant byte in the location with the highest address, Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 3.11 ■ 73 Shift and Rotate Instructions this right-shift operation is in the logical sense rather than in the spatial sense. The operation to shift a multibyte number to the left should start from the lsb (leftmost byte) and rotate the remaining bytes to the msb (rightmost byte). Example 3.24 ▼ Write a program to shift the 32-bit number stored at 0x200~0x203 in data memory to the right four places. Solution: The least significant to the most significant bytes are stored at 0x200~0x203. The logical shift-right operation is performed from 0x203 to 0x200. The assembly program that performs the desired operation is as follows: .include .equ .equ .equ .equ .def .dseg .org buf: .byte .cseg .org rjmp .org start: ldi ldi ldi ldi sts sts sts sts ldi srloop: lsr ror ror ror dec brne sts sts sts sts nop // end of program 6m2560def.inc7 bt3 = 0x79 bt2 = 0x86 bt1 = 0x53 bt0 = 0x42 lpcnt = r16 ; msb of test data ; ; ; lsb of test data 0x200 4 ; set to 0x2000 for XMega devices ; buffer to hold right-shift result 0x00 start 0xF6 r17,bt3 r18,bt2 r19,bt1 r20,bt0 buf+3,r17 buf+2,r18 buf+1,r19 buf,r20 lpcnt,4 r17 r18 r19 r20 lpcnt srloop buf+3,r17 buf+2,r18 buf+1,r19 buf,r20 ; msb ; second to msb ; second to lsb ; lsb ; initialize msb in data memory ; initialize second to msb in data memory ; initialize second to lsb in data memory ; initialize lsb in data memory ; set up loop count ; shift the msb to the right one place ; rotate the second to msb to the right one place ; rotate the second to lsb to the right one place ; rotate the lsb to the right one place ; decrement loop count ; save the msb in data memory ; save the second to msb in data memory ; save the second to lsb in data memory ; save the lsb in data memory ▲ Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 74 Chapter 3 ■ AVR Assembly Language Programming 3.12 Boolean Instructions Boolean instructions can be used to change a few bits of output PORT pins. A summary of the AVR Boolean instructions is given in Table 3.8. Mnemonics Description Operation and Rd, Rr Logical AND Rd ← [Rd] • [Rr] andi Rd, k Logical AND with immediate Rd ← [Rd] • k or Rd, Rr Logical OR Rd ← [Rd] ~ [Rr] ori Rd, k Logical OR with immediate Rd ← [Rd] ~ k eor Rd, Rr Exclusive OR Rd ← [Rd] { [Rr] com Rd One’s complement Rd ← 0xFF - [Rd] neg Rd Two’s complement Rd ← 0x00 - [Rd] sbr Rd, k Set bit (s) in register Rd ← [Rd] ~ k cbr Rd, k Clear bit (s) in register Rd ← [Rd] • (0xFF - k) tst Rd Test for zero or minus Rd ← [Rd] • [Rd] clr Rd Clear register Rd ← [Rd] { [Rd] set Rd Set register Rd ← 0xFF Source: Atmel Corporation, The Atmel AVR Microcontroller Table 3.8 ■ A summary of AVR Boolean instructions The and instruction can be used to clear one or a few bits, and the or instruction can be used to set one or a few bits within a byte. The exclusive or instruction can be used to toggle (change from 0 to 1 and from 1 to 0) one or a few bits within a byte. For example, the instruction sequence in andi out r16, PORTB r16, 0x0F PORTB,r16 ; read PORTB (located at 0x05) ; clear the upper four bits ; store back to PORTB clears the upper four bits of PORTB. This operation can also be performed by the following instruction sequence: in cbr out r16,PORTB r16,0xF0 PORTB,r16 ; read PORTB ; clear the upper 4 bits ; store back to PORTB The instruction sequence in ori out r16, PORTB r16, 0x02 PORTB, r16 ; read PORTB ; set bit 1 to 1 ; store back to PORTB sets the bit 1 of PORTB to 1. This operation can also be performed using the following instruction sequence: in sbr out r16,PORTB r16,0x02 PORTB,r16 ; read PORTB ; set bit 1 to 1 ; store back to PORTB Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 3.13 ■ 75 Bit Manipulating Instructions The instruction sequence in ldi eor out r16, PORTB r17, 0x0F r16, r17 PORTB,r16 toggles the lower 4 bits of PORTB. The com instruction can be used if all the PORT pins have to be toggled. 3.13 Bit Manipulating Instructions The AVR also provides a group of bit manipulating instructions (listed in Table 3.9) that allow the user to change the value of a bit or copy a bit from one register to another. These instructions can be useful in performing control operations. The constants s and b in Table 3.9 specify the bit position to be manipulated. Mnemonics Description Operation bset s Flag set SREG(s) ← 1 bclr s Flag clear SREG(s) ← 0 sbi A, b Set bit in I/O register I/O(A, b) ← 1 cbi A, b Clear bit in I/O register I/O(A, b) ← 0 bst Rr, b Bit store from register to T T ← Rr(b) bld Rr, b Bit load from T to register Rd(b) ← T sec Set carry C←1 clc Clear carry C←0 sen Set negative flag N←1 cln Clear negative flag N←0 sez Set zero flag Z←1 clz Clear zero flag Z←0 sei Enable global interrupt I←1 cli Disable global interrupt I←0 ses Set signed test flag S←1 cls Clear signed test flag S←0 sev Set 2’s complement overflow V←1 clv Clear 2’s complement overflow V←0 set Set T in SREG T←1 clt Clear T in SREG T←0 seh Set half carry flag in SREG H←1 clh Clear half carry flag in SREG H←0 Source: Atmel Corporation, The Atmel AVR Microcontroller Table 3.9 ■ A summary of the AVR bit manipulation instructions Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 76 Chapter 3 ■ AVR Assembly Language Programming The instruction sbi SPCR,SPE ; SPE is bit 6 of the SPCR register sets the bit 6 of the SPCR register and enables the serial peripheral interface (SPI). The instruction cbi SPCR,SPIE ; SPIE is the bit 7 of the SPCR register clears the bit 7 (SPIE bit is the bit 7 of the SPCR register) and disables the SPI interrupt to the MCU. The sbi and cbi instructions may also be used to set or clear a bit in an I/O PORT data register, which can then pull the associated pin voltage to high or low. This capability is often used to enable and disable the functioning of a peripheral chip. 3.14 Create Time Delay Using Program Loops The AVR instruction execution is controlled by the CPU clock. This clock signal is often generated by using an external crystal oscillator. One AVR instruction may take from one to five CPU clock cycles to complete. The execution time of each AVR instruction can be found in Appendix A. There are many applications that require the generation of time delays. Program loops are often used to create a certain amount of delay unless the time delay needs to be very accurate. The creation of a time delay involves two steps: Step 1 Select a sequence of instructions that take a certain number of CPU clock cycles to execute. Step 2 Repeat the instruction sequence for an appropriate number of times. For example, the following instruction sequence takes 32 CPU clock cycles to execute: loop0: push pop push pop push pop push pop push pop push pop push pop nop dec brne r0 r0 r0 r0 r0 r0 r0 r0 r0 r0 r0 r0 r0 r0 r21 loop0 ; 2 CPU clock cycles ; 2 CPU clock cycles ; 1 CPU clock cycle ; 1 CPU clock cycle ; take 2 (1) CPU clock cycles when branch is taken (not taken) Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 3.15 ■ 77 Summary This instruction sequence can be shortened by using a program loop as follows: loop0: loopi: ldi push pop dec brne dec brne r20,4 r0 r0 r20 loopi r21 loop0 ; 1 cycle ; 2 clock cycles ; 2 clock cycles ; 1 CPU clock cycle ; 2 (1) cycle when branch is taken (not taken) ; 1 cycle ; 2 (1) cycle when branch is taken (not taken) The created time delay is set by the CPU clock frequency. Suppose the CPU clock frequency is 16 MHz; then the previous instruction sequence takes 2 µs to execute. To create a time delay of 0.5 ms, we need to load 250 into the r21 register. The following instruction sequence creates a time delay of 0.5 ms when the CPU clock frequency is 16 MHz: loop0: loopi: ldi ldi push pop dec brne dec brne r21,250 r20,4 r0 r0 r20 loopi r21 loop0 ; set loop count to 250 ; 1 cycle ; 2 clock cycles ; 2 clock cycles ; 1 CPU clock cycle ; 2 (1) cycle when branch is taken (not taken) ; 1 cycle ; 2 (1) cycle when branch is taken (not taken) A longer time delay can be created by using a multilayer loop. For example, the following instruction sequence can create a time delay of 100 ms: loop1: loop0: loopi: ldi ldi ldi push pop dec brne dec brne dec brne r16,200 r21,250 r20,4 r0 r0 r20 loopi r21 loop0 r16 loop1 ; set external loop count to 200 ; set loop count to 250 ; 1 cycle ; 2 clock cycles ; 2 clock cycles ; 1 CPU clock cycle ; 2 (1) cycle when branch is taken (not taken) ; 1 cycle ; 2 (1) cycle when branch is taken (not taken) The time delay created by using program loops is not accurate. Some overhead is required to set up the loop count. For example, the one-layer loop has one clock cycle overhead, whereas the two-layer loop has much more overhead. Overhead = 1 CPU cycle + 200 * (1 + 1 + 2) = 801 CPU cycles = 50 µs (at 16 MHz CPU clock frequency) 3.15 Summary An assembly language program consists of three types of statements: assembler directives, assembly language instructions, and comments. An assembler directive tells the assembler how to process subsequent assembly language instructions. Directives also provide a way for defining constants and reserving space for dynamic variables. A statement of an assembly program consists of four fields: label, operation code, operands, and comment. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 78 Chapter 3 ■ AVR Assembly Language Programming Although the AVR can perform only 8-bit arithmetic operations, numbers that are longer than 8 bits can still be added, subtracted, or multiplied by performing multiprecision arithmetic. The multiprecision addition can be implemented by using the add-with-carry (adc) instruction, and multiprecision subtraction can be performed by using the subtract-with-carry (sbc) instruction. To perform multiprecision multiplication, both the multiplicand and the multiplier must be divided into 8-bit chunks. The next step is to generate partial products and align them properly before adding them together. A subroutine that performs multiprecision multiplication is described in Chapter 5. Multiprecision division is performed by repeated shifting and subtraction method and also is detailed in Chapter 5. Performing repetitive operations is the strength of a microcontroller and microprocessor. For a computer to perform repetitive operations, we have to write program loops to tell the computer what instruction sequence to repeat and how many times to repeat. Two components are required in implementing a finite loop: one is the test of loop termination condition, and the second is the change of program flow. The AVR and all microcontrollers provide instructions for both operations. The AVR also provides instructions for initializing and updating variables and loop indices. The AVR instruction set includes many logical instructions, which may be useful for implementing control and I/O applications. Shift and rotate instructions are useful for bit field operations. They can also be used to implement multiplication and division by a power of 2. All shift and rotate instructions can operate on any of the 32 CPU registers. When required, we can write a sequence of instructions to shift a number longer than 8 bits. It is important to provide test data for the program being developed. A common method is by using assembler directives such as db or dw to define numbers or strings to be tested in program memory. If the program has to modify the test data, then you need to copy the test data from program memory to data memory. Time delays are useful in many applications. A time delay can be created by repeating a sequence of instructions for a certain number of times. Depending on the length of the delay, the programmer may need to use a multiple-layer program loop to create a time delay. 3.16 Exercises E3.1 Write assembler directives to define the ASCII codes of letters a to z in program memory. E3.2 Write assembler directives to define the ASCII codes of digits 0 to 9 in program memory starting from address 0x1000. E3.3 Invoke the setPointer macro defined in Section 3.5.8 to load the address 0x3000 into Y register. E3.4 Write a program to add the 16-bit numbers stored at data memory locations 0x210~0x211 and 0x220~0x221, respectively, and store the sum at 0x230~0x231. E3.5 Write a program to add the 24-bit numbers stored at data memory locations 0x200~0x202 and 0x203~0x205, respectively, and store the sum at 0x206~0x208. E3.6 Write a program to add the 32-bit numbers stored at data memory locations 0x200~0x203 and 0x204~0x207, respectively, and store the sum at 0x208~0x20B. E3.7 Write a program to subtract the 16-bit number stored at 0x200~0x201 from the 16-bit number stored at 0x202~0x203, and store the difference at 0x204~0x205. E3.8 Write a program to subtract the 24-bit number stored at 0x200~0x202 from the 24-bit number stored at 0x203~0x205 and store the difference at 0x206~0x208. E3.9 Write a program to subtract the 32-bit number stored at 0x200~0x203 from the 32-bit number stored at 0x204~0xx207 and store the difference at 0x208~0x20B. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 3.16 ■ Exercises 79 E3.10 Write a program to find the total elements of an array of 8-bit integers that have bit 2, 3, and 4 set to 1. Use the repeat-until looping construct. Assume the array is in the program memory. E3.11 Write a program to swap the upper 4 bits with the lower 4 bits of every element of an array of 8-bit integers. The initial array is stored in the program memory and you must copy this array to the data memory for testing purpose. E3.12 Write a program to find the total number of elements in an array of 8-bit integers that are larger than 20. Use the for-loop looping construct. E3.13 Write a program to find the total number of elements in an array of 8-bit integers that are greater than 30 and less than 100. Use the for-loop looping construct. E3.14 Write a program to find the total number of elements in an array of 8-bit integers that are greater than 100 or less than 30. Use the repeat-until looping construct to implement the loop. E3.15 Write a program to set the bit 7 and bit 0 of all the elements of an array to 1. E3.16 Assume that the contents of register r0 and carry flag are 0x79 and 0, respectively. What are the new values for r0 and C after the execution of each of the instructions listed in Table 3.7? E3.17 Assume that the contents of the register r16 and carry flag are 0xA6 and 1, respectively. What are the new values for r16 and C after the execution of each of the instructions listed in Table 3.7? E3.18 Write an instruction sequence to create a time delay of 1 second. E3.19 Write a program to copy a block of memory locations from one area to another area in data memory. E3.20 Write a program to find the largest element, the smallest element, and their average of an array of 8-bit elements. Store these three numbers in data memory starting from 0x200. E3.21 What are the values stored in registers r1 and r0 after the execution of the instruction mul r16, r17 if r16 and r17 originally contain the following values? (a) 0x58 and 0x37 (b) 0x29 and 0x49 E3.22 Write a program to shift the 32-bit number stored at 0x200~0x203 in data memory to the left four places. The msb to lsb are stored from 0x203 toward 0x200, respectively. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 4 Hardware and Software Development Tools for the AVR 4.1 Objectives After completing this chapter, you will be able to • Understand the type of hardware development tools available for learning AVR microcontroller. • Understand the type of software development tools available for learning AVR microcontroller programming. • Use the AVR Studio IDE to enter, assemble, and download programs onto a demo board for execution. • Use the AVR Studio IDE to debug AVR assembly programs. • Learn the strategy for program debugging. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 82 Chapter 4 ■ Hardware and Software Development Tools for the AVR 4.2 Development Tools for the Atmel AVR Microcontroller development tools are divided into two categories: hardware tools and software tools. Hardware tools support device programming, program execution, and software debugging, whereas software tools allow programs to be entered, assembled/compiled, linked, and executed. 4.3 Hardware Development Tools The microcontroller demo board, programmer, and debug adapter are the most useful hardware tools for learning the AVR MCU. 4.3.1 Choosing a Demo Board for Learning the AVR What type of demo board is good for learning the AVR microcontroller? To answer this question, we need to think about the I/O functions and the peripheral chips that we have to deal with during the learning process. A semester-long course would be able to cover general I/O PORTs, interrupts, timer functions, universal asynchronous receiver transmitter (UART) PORT, serial peripheral interface (SPI), two-wire interface (TWI), A/D converter, and D/A converter. A demo board that provides one or two peripheral chips for learning each of these peripheral functions would be very desirable. • I/O PORT. The inexpensive dual-in-line package (DIP) switches are used to provide input to the user program. The light-emitting diodes (LEDs) are inexpensive output devices that are used to practice output function and validate the time delays created by program loops or the timer function. Liquid crystal displays (LCDs) are useful for displaying a large quantity of information. A demo board should at least provide these three types of I/O devices. • Interrupt input. A demo board should add one or two debounced switches for testing external interrupt sources. An interrupt pin is also used to perform interrupt-driven input. • Timer functions. I/O pins related to timer functions must be made available to the user. • UART PORT. By providing a 9-pin connector with the UART PORT, the demo board can communicate with a PC via the COM PORT. This PORT has been useful in providing users with keyboard input and terminal window output in the past. However, almost all PCs have eliminated the COM PORT and the HyperTerminal program. This feature will be harder to use in the future. • SPI interface. Semiconductor vendors have provided many peripheral chips with the SPI interface. For example, D/A converter, A/D converter, shift register, EEPROM, SRAM, real-time clock (RTC), digital temperature sensor, seven-segment display driver, and so on. Having one or two peripheral chips with the SPI interface on the demo board, to allow the user to practice SPI read and write operations, would be helpful for learning the SPI function. • TWI (or I2C interface) interface. This interface allows the AVR to use two pins to communicate with many peripheral chips. Like the SPI interface, semiconductor vendors have provided a wide variety of peripheral chips with the TWI (or I2C) interface. Examples include thermostat, A/D converter, D/A converter, real-time Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 4.3 ■ 83 Hardware Development Tools clock, EEPROM, SRAM, and so on. Having one or two peripheral chips with the TWI interface is very helpful for learning this function. • A/D converter. In order to test the on-chip A/D converter, the demo board should provide at least a potentiometer. An additional temperature sensor or other sensors such as humidity or barometric senor are very helpful for testing the A/D function. • D/A converter. Some AVR devices (XMega AVR MCUs) provide an on-chip D/A converter. The demo board has to make the D/A output pins available to the user. In addition to providing many peripheral chips and I/O devices to the user, the demo board should also make all signal pins available to the user so that he or she can experiment with other peripheral chips. Some people may argue that using a bare kit that only makes I/O signals available to the user forces the user to do more wiring and hence to learn more during the process. This argument may be true for those peripheral chips in the DIP package. However, many peripheral chips are using the surface-mount package (difficult to handle), which might frustrate the user during the learning process. The demo board must also have a connector to connect to a debug adapter or programmer so that the user can download the program onto the demo board for execution. A JTAG (joined test action group) and ISP (in-system programming) connectors are required for this purpose. 4.3.2 The EasyAVR M1280 Demo Boards © Cengage Learning 2014 This demo board is made by AVRVI (website at www.avrvi.com or www.enshop.avrvi.com). A photograph of this demo board is shown in Figure 4.1. Figure 4.1 ■ The EasyAVR M1280 M1280 Demo Boards Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 84 Chapter 4 ■ Hardware and Software Development Tools for the AVR The EasyAVR provides the following features: • • • • • • • • • • • • • • • • • • • Mega1280 MCU with 128 kB flash memory On-board AVRISP MKII USB interface for on-chip programming External ISP and JTAG interface debugging UART 9-pin communication connector 74HC4060 variable frequency square wave output Four 7-segment displays 8 LEDs I2C real-time clock chip DS1337 Analog temperature sensor TC1047A Digital temperature sensor TC72 with SPI interface I2C EEPROM AT24C01 12-bit resolution MCP4922 DAC with SPI interface Buzzer CAN bus circuit with MCP2515 CAN controller 2 3 16 character LCD 4 3 4 keypad PS/2 keyboard connector Potentiometer 4 buttons 4.3.3 Stingray XMega Demo Board The Stingray demo board is an XMega demo board from Xbit Inc. A photograph of the Stingray is shown in Figure 4.2. The Stingray XMega demo board provides the following features: • • • • • • • • • • • • • • • Atmel ATXMega128A1 MCU Onboard USB programmer All pins routed to external female headers Can be powered from USB, wall jack, or 9 V battery 2.048 V ADC reference voltage 16 MHz crystal capable of creating a 32 MHz system clock 8 slide switches 8 LEDs 4 debounced push buttons 16 3 2 character LCD 6-digit, 7-segment displays (driven by two 74HC595 shift registers) Potentiometer (connected to the A/D converter input) Analog temperature sensor MCP9700 (connected to the A/D converter) UART 9-pin connector JTAG and PDI connectors for program programming and debugging Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 4.3 ■ 85 Hardware Development Tools Buzzer Variable frequency outputs I2C 8-kbit EEPROM 24AA08 I2C temperature sensor TCN75A I2C real-time clock chip DS1337 CAN controller MCP2515 and CAN driver MCP2551 SPI EEPROM 25AA080D Digital temperature sensor TC72 © Cengage Learning 2014 • • • • • • • • Figure 4.2 ■ The Stingray XMega demo board from Xbit Inc. 4.3.4 Arduino Demo Kits Arduino is an open-source electronics prototyping platform consisting of hardware and software. Arduino provides several predesigned boards for the user to adapt to his or her applications. Examples are Uno, Nano, Mega2560 (shown in Figure 4.3), Arduino Ethernet, and so on. These boards are based on AVR MCUs. Arduino also has boards called shields that can be mounted on top of the Arduino board to extend the functionality of Arduino to control different devices, acquire data, and so forth. Motor shield and Ethernet shield are examples. The hardware reference designs (CAD files) are available under an open-source license; users are free to adapt them to their needs. These boards are bare kits and hence are inexpensive. The microcontroller on an Arduino board is programmed using the Arduino programming language and the Arduino development environment. The Arduino development environment provides a simple text editor for the user to enter the program (referred to as a sketch) in Arduino programming language. After the sketch is entered properly, the user can then upload it to the Arduino board for execution. The Arduino development environment also provides a library of functions to simplify the programming task for the user. The Arduino environment does not have the debugging capabilities available in the AVR Studio IDE. More information about Arduino can be found at www.arduino.cc. Books on how to use and program the Arduino kits are available [5,6,7,8]. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. Chapter 4 ■ Hardware and Software Development Tools for the AVR © Cengage Learning 2014 86 Figure 4.3 ■ Arduino Mega2560 demo kit 4.3.5 Debug Adapters from Atmel Atmel produces several debug adapters to support the software debugging of AVR applications: AVR Dragon, JTAGICE3, JTAGICE mkII, and AVR ONE!. AV R D R A G O N © Cengage Learning 2014 The AVR Dragon is an inexpensive debug adapter that programs and supports software debugging for all AVR devices. A photograph of the AVR Dragon is shown in Figure 4.4. The AVR Dragon allows the user to use four different interfaces (including JTAG, high-Voltage, Parallel, and in-system programming (ISP)) to program the target AVR device and also supports two debug interfaces (JTAG and debug Wire (dW)). Figure 4.4 ■ Atmel Dragon debug adapter J TA G I C E 3 Shown in Figure 4.5, the JTAGICE3 is the newest debug adapter (introduced in June 2011) from Atmel. This debug adapter supports the debugging of software for all 8-bit and 32-bit AVR devices using the JTAG, aWire, SPI and PDI interfaces. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. ■ 87 Hardware Development Tools © Cengage Learning 2014 4.3 Figure 4.5 J TA G I C E ■ Atmel JTAGICE 3 debug adapter MKII © Cengage Learning 2014 A photograph of JTAGICE mkII is shown in Figure 4.6. The JTAGICE mkII supports programming and software debugging for all 8-bit and 32-bit AVR devices using five interfaces, including the JTAG, PDI, debugWIRE, SPI, and aWire. Figure 4.6 ■ Atmel JTAGICE mkII debug adapter AV R O N E ! AVR ONE! is the most expensive debug adapter from Atmel. It supports the device programming using the SPI, JTAG, PDI, and a Wire programming modes and debugging using the debugWIRE, JTAG, PDI, and aWire interfaces for all 8-bit and 32-bit AVR devices. It also supports LiveDebug, which makes it possible to attach to a running target nonintrusively, and the Nexus auxiliary interface for high-speed program, data, or ownership trace at up to 200 MHz in either buffered or streaming mode. A photograph of AVR ONE! is shown in Figure 4.7. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. Chapter 4 ■ Hardware and Software Development Tools for the AVR © Cengage Learning 2014 88 Figure 4.7 ■ Atmel AVR ONE! debug adapter 4.4 Software Development Tools To develop software to be run on an AVR demo board, we need a text editor to enter the program, an assembler and compiler to assemble and compile the program, a linker to resolve variables and subroutines cross-referencing and memory assignment, a simulator and a debugger to debug the software being developed. A project manager is also needed to coordinate the overall debug activities. These pieces of software are often integrated into a single package called integrated development environment (IDE). For example, the IAR Embedded Workbench IDE provides an AVR assembler, a C compiler, a linker, a librarian, a simulator, a project manager, and debugging support for the Atmel JTAGICE mkII debug adapter. Atmel provides a freeware AVR Studio IDE to support its customers in developing AVR application software. The AVR Studio version 5 and later contain a project manager; an AVR assembler; a C compiler; a linker; an AVR simulator; support for several debug adapters, including Dragon, JTAGICE3, JTAGICE mkII, and AVR One!; and support for many starter kits from Atmel. With the AVR Studio, the user has an IDE that allows the user to use both the assembly and C languages to develop application software. This text uses the AVR Studio version 5 to enter and test all of the AVR assembly and C programs. The AVR Studio IDE version 4 and WINAVR C compiler are also included in the complimentary CD for those who preferred not to migrate to version 5. 4.5 Using the AVR Studio IDE The procedure for developing a program includes the following major steps: Step 1 Create a project. Step 2 Enter the program. Step 3 Assemble or compile (also called build) the project and eliminate syntax errors. Step 4 Debug the program. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 4.5 ■ 89 Using the AVR Studio IDE 4.5.1 Create a Project Source: Atmel Corporation, The Atmel AVR Microcontroller The AVR Studio is started by selecting StartãAll ProgramsãAtmel AVR toolsãAVR Studio 5.0 or clicking on its icon. The startup screen is shown in Figure 4.8. The startup screen displays a few recent projects. The user can choose to work on a recent project by selecting it and clicking on Open Project… or start a new project by clicking on New Project… on the startup screen in Figure 4.8. If the user clicks on New Project…, the screen changes to that in Figure 4.9. Figure 4.8 ■ AVR Studio startup screen The user should click on AVR Assembler if he or she wants to develop a program in assembly language. The user should also enter the project name and specify the project location (directory). The Solution name is forced to be identical to the project name. The screen changes to that in Figure 4.10 after AVR Assembler is selected (the project name is set to tutor1). After the user is satisfied with the project name and location, he or she should click on OK; a pop up dialog appears for the user to select the target device, as shown in Figure 4.11. After selecting the target device and clicking on OK, the screen changes to that seen in Figure 4.12. The window with the title “tutor1.asm” in Figure 4.12 is where the new program is entered. The sizes of these windows may not be appropriate to work with. The user can resize the windows before entering the program. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. Chapter 4 ■ Hardware and Software Development Tools for the AVR Source: Atmel Corporation, The Atmel AVR Microcontroller 90 ■ AVR Studio screen after clicking on New Project in Figure 4.8 Source: Atmel Corporation, The Atmel AVR Microcontroller Figure 4.9 Figure 4.10 ■ AVR IDE screen after creating a new assembler project 4.5.2 Enter the Program In the following, we use a program that finds the total number of elements in an array of 8-bit numbers that are greater than 30 but smaller than 100 as an example to illustrate the program debug process. The screen after entering the program is shown in Figure 4.13. 4.5.3 Assemble (or build) the Project To assemble (or build) the program, press Build menu and select Build Solution, as shown in Figure 4.14. The user can also press the function key F7 to build the project. There might be syntax or semantic errors during the assembling process. The AVR Studio outputs error messages corresponding to the errors. An example of two semantic errors is shown in Figure 4.15. The error list indicates the error causes and the lines that contain Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. ■ 91 Using the AVR Studio IDE Source: Atmel Corporation, The Atmel AVR Microcontroller 4.5 ■ AVR Studio pop up dialog for device selection Figure 4.12 ■ AVR Studio screen after device is selected Source: Atmel Corporation, The Atmel AVR Microcontroller Figure 4.11 Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. Chapter 4 ■ Hardware and Software Development Tools for the AVR Source: Atmel Corporation, The Atmel AVR Microcontroller 92 ■ AVR Studio screen after entering an assembly program Figure 4.14 ■ Build project dialog Source: Atmel Corporation, The Atmel AVR Microcontroller Figure 4.13 the error. When the user clicks on the error message, the AVR Studio moves the cursor to the program line that contains the error. The two lines in error use an invalid register as their destination. By changing the line .def lpcnt = r15 to .def lpcnt = r19 and changing .def count = r13 to .def count = r20, the errors are fixed. The ldi Rd, k instruction requires Rd to be from r16 to r31. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. ■ 93 Using the AVR Studio IDE Source: Atmel Corporation, The Atmel AVR Microcontroller 4.5 Figure 4.15 ■ Project build with semantic errors 4.5.5 Program Execution and Debugging The user can choose to use either the simulator (simulation) or the target hardware (emulation; a debug adapter is needed). There are three methods to start program execution and debugging in the AVR Studio, as shown in Figure 4.16. 1. Start debugging. In this method, the AVR Studio launches the debugging/emulation tool, which immediately starts an emulation session. Your program is executed immediately in this method. This method also can be selected by pressing the function key F5. 2. Start debugging and break. The AVR Studio launches the debugging tool and starts the simulation/emulation with a breakpoint set at the entry point of the produced executable file. On encountering the breakpoint, the simulator suspends the program run. This method is also selected by pressing the function key F10. 3. Start without debugging. AVR Studio launches the debugging tool, but not the emulation session, which means that you can set up a breakpoint with ease before the launch. Pressing the function key F5 and the CTRL key also starts this method. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 94 Chapter 4 ■ Hardware and Software Development Tools for the AVR Source: Atmel Corporation, The Atmel AVR Microcontroller Figure 4.16 ■ Methods for starting debugging and program execution Source: Atmel Corporation, The Atmel AVR Microcontroller The screen after the second method used is shown in Figure 4.17. A yellow arrow at the left-hand side of the program window points to the instruction (jmp start) located at address x, where instruction execution is to be started. Figure 4.17 ■ AVR Studio screen after the second debugging method is chosen S E T U P W AT C H L I S T The Watch window is used to watch the value changes of program variables during the program execution process. The Watch window has the word Watch on its upper-left corner. The Watch window is available only when the debug session has been started. A variable can be added to the Watch window by pressing the right mouse button on the variable (lpcnt) and selecting Add Watch, as shown in Figure 4.18. After this, the variable is added into the Watch window, as shown in Figure 4.19. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. ■ 95 Using the AVR Studio IDE Source: Atmel Corporation, The Atmel AVR Microcontroller 4.5 ■ Screen for adding a variable (lpcnt) to the watch window Figure 4.19 ■ AVR Studio Watch window with two variables added Source: Atmel Corporation, The Atmel AVR Microcontroller Figure 4.18 RESETTING THE MCU Make sure that the target MCU is reset before running the program. The program counter of the target MCU is forced to 0 after a reset. There are three methods to reset the MCU: • • • Press Debug and select Reset. Press the Reset button, as shown in Figure 4.20. Press the key combination of Shift+F5. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 96 Chapter 4 ■ Hardware and Software Development Tools for the AVR Source: Atmel Corporation, The Atmel AVR Microcontroller Figure 4.20 SETTING A ■ Press Reset button to reset the MCU BREAKPOINT Source: Atmel Corporation, The Atmel AVR Microcontroller A breakpoint is the address of an instruction where program execution stops. After we select Start without debugging from the Debug menu, AVR Studio builds the project but does not start the debug session. The user can set breakpoints in this mode and the start-debuggingand-break mode. A breakpoint is set by pressing the right mouse button on the instruction to be set as a breakpoint and selecting BreakpointãInsert Breakpoint. After an instruction is set as a breakpoint, a red circle is placed to the left side of the instruction. Multiple breakpoints can be set during a debugging process. A screen with a breakpoint set is shown in Figure 4.21. When a breakpoint is not desired, it can be disabled (by selecting BreakpointãDisable Breakpoint). A disabled breakpoint (with a white circle) has no effect on program execution. When a disabled breakpoint is needed again, it can be reenabled. When a breakpoint is not needed, it can be deleted (by selecting BreakpointãDelete Breakpoint). Figure 4.21 ■ A breakpoint has a red circle at its lefthand side AVR Studio 5 allows the user to modify the behavior of a breakpoint by setting its properties: • Hit count. By setting the hit count, the user can force the program to stop when the breakpoint is encountered for hit count times. Hit count is set by pressing the right mouse button on the breakpoint and selecting BreakpointãHit count. • Condition. Condition is an expression that determines whether the breakpoint is hit or skipped. When the debugger reaches the breakpoint, it evaluates the condition. The breakpoint is hit only if the condition is satisfied. You can use a condition with a location breakpoint to stop at a specified location only when a certain condition is true. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 4.5 ■ • RUN 97 Using the AVR Studio IDE TO Action. Action specifies something that should occur when the breakpoint is hit. By default, the debugger breaks execution, but you can choose to print a message or run a Visual Studio macro instead. CURSOR Source: Atmel Corporation, The Atmel AVR Microcontroller The Run-to-Cursor option is a quick way for running the program up to the instruction at the mouse cursor and then stopping. When the program stops, the AVR Studio IDE updates the values of all the CPU registers and the variables in the Watch Window. We use this method to quickly find out if the program executes correctly up to the cursor position. This method is much more efficient than using program breakpoints. This option can be exercised by pressing the right mouse button on the instruction where the program is expected to stop. Press the cursor at the here: rjmp here instruction, as shown in Figure 4.22. When the program stops, the value of count is 10 (shown in Figure 4.23) and is correct. This example program finds the total number of elements that are between 30 and 100. Figure 4.22 ■ Execute “Run to Cursor” command STEPPING OVER INSTRUCTIONS Sometimes the programmer has to find out the effect of one or two instructions in order to identify the source of errors. This option makes it possible. The AVR studio has three options for stepping through the program: • Step into. This option causes the MCU to execute one instruction at a time. If the instruction being stepped is a call instruction, then the MCU stops at the first instruction of the subroutine. • Step over. If the instruction being stepped is not a call instruction, the MCU only executes one instruction and stops. However, if the instruction being stepped is a call instruction, then the MCU completes the execution of the whole subroutine and stops at the instruction after the call instruction. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. Chapter 4 ■ Hardware and Software Development Tools for the AVR Source: Atmel Corporation, The Atmel AVR Microcontroller 98 Figure 4.23 • ■ AVR Studio screen after executing “Run To Cursor” command Step out. If the MCU is executing a subroutine, this command causes the MCU to complete the execution of the current subroutine and return to the caller of this subroutine. This command should not be executed if the user did not perform the command Step into on a call instruction before. 4.6 Tips for Assembly Program Debugging Assembly program errors can be classified into two categories: • Syntax and semantic errors • Logical errors 4.6.1 Syntax and Semantic Errors Syntax and semantic errors are common for beginners. These errors can be divided into the following categories: • Misspelling of instruction mnemonics. This type of error is highlighted by the assembler (with a red dot) in the build window. For example, the build window would look like Figure 4.24 if we change the brlo next instruction to drlo next. The line number at which the error occurred is displayed in the Error List. The user double clicks on the error message to be brought to the statement that contains the error (shown in Figure 4.25). • Symbol not terminated with a colon character when it is defined. When a symbol is not terminated with a colon character, it is treated as an error. By double-clicking on the error message, the line that contains the symbol not terminated with a colon is highlighted. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 4.6 ■ Tips for Assembly Program Debugging 99 Source: Atmel Corporation, The Atmel AVR Microcontroller ■ Error list window contains error messages Source: Atmel Corporation, The Atmel AVR Microcontroller Figure 4.24 ■ The line with error is highlighted Figure 4.26 ■ An error caused by a missing operand Source: Atmel Corporation, The Atmel AVR Microcontroller Figure 4.25 • Missing operands. When an instruction does not have enough number of operands, the assembler indicates it as “wrong number of operands.” Suppose we delete the first operand of the cpi r16, lowVal+1 instruction, and the instruction is changed to cpi lowVal+1. The AVR assembler generates the message, as shown in Figure 4.26. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. Chapter 4 ■ Hardware and Software Development Tools for the AVR Source: Atmel Corporation, The Atmel AVR Microcontroller 100 ■ Error caused by invalid register Figure 4.28 ■ A syntax error caused by undefined symbol “countx” Source: Atmel Corporation, The Atmel AVR Microcontroller Figure 4.27 • Invalid register. Not all 32 CPU registers can be the operand of every instruction. When the user specifies an illegal register for an instruction, the assembler outputs an error message indicating that the instruction uses an invalid register. An example is shown in Figure 4.27. Here, the user specified r10 as the destination register for the andi instruction. However, the andi instruction can only accept a register from r16 to r31 as its destination register. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 4.6 ■ Tips for Assembly Program Debugging • 101 Undefined Symbols. An undefined symbol is identified and displayed in the Build Window. One example is shown in Figure 4.28, in which the symbol countx is undefined. As time goes on, the user gains experience and also memorizes the instruction mnemonics; this type of error will reduce dramatically and even disappear. 4.6.2 Logical Errors There are an infinite number of possible logical errors. Anything that can go wrong will happen in assembly language programming; it is impossible to discuss all the possible errors. However, we must have a strategy to quickly determine whether the program runs correctly and locate any error quickly. 4.6.3 General Debug Strategy The general debug strategy consists of three steps: (a) Determine whether the program runs correctly, (2) locate any error, and (3) fix the error. D E T E R M I N E W H E T H E R P R O G R A M R U N S C O R R E C T LY The user can use the Run-to-Cursor feature to test the program. First, let the program run until the last instruction in the program under the AVR Studio IDE. During this process, the user must provide normal data, borderline data, and illegal data to test the program, as described in Section 3.7. L O C AT E THE ERROR OF THE PROGRAM The programmer can locate the error by using the Run-to-Cursor feature of the IDE. Sometimes, single-stepping a few instructions may also help. By letting the program execute to the suspected instruction using this feature and examining the value change in the Watch Window, the programmer can quickly locate the program error. This step may have to be repeated several times before the error is identified. FIX THE ERROR The programmer needs to know the type of error that occurred before he or she can fix the error. Although it is impossible to enumerate all possible errors, a few common ones are explained in the next section. 4.6.4 Common Program Logical Errors • Forgetting initializing program variables. Program loop indices or repetition counts and program variables must be initialized properly to obtain the correct result. • Using the same register for multiple variables at the same time. If we assign variables count and lpcnt to the same register in the previous tutor program example, the program loop never terminates. • Using the wrong instruction for a certain purpose. There are many possibilities for this error. For example, using an addition or subtraction instruction that does not involve carry would cause the result to be incorrect for multiple-byte addition and subtraction operations. • Operand size mismatch. There are several possibilities for this error. One is attempting to load a big number into a small variable. The other is attempting to increment or decrement a multiple-byte variable using an instruction that only operates on a single byte and hence leaves a part of the variable untouched. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 102 Chapter 4 ■ Hardware and Software Development Tools for the AVR • Missing a return instruction in a subroutine or interrupt service routine. The last instruction to be executed in a subroutine (to be discussed in Chapter 5) must be a ret instruction so that the program control can return to the caller after it finishes all the computation. Similarly, the last instruction to be executed in an interrupt service routine must be a reti instruction so that the program control can be returned to the interrupted program when the interrupt service routine finishes its execution. • Forgetting to pass parameters to the subroutine being called. It is obvious that a subroutine cannot run correctly without the caller passing appropriate parameters to it. This error did happen. • Incorrect program algorithm. An incorrect program algorithm rarely produces a correct result. 4.7 Project File Structure The AVR Studio IDE creates a directory of the project name under the selected directory. For example, the tutorial would cause a directory of the name tutor1 to be created under c:\books\avr\programs\ch04. Under the tutor1 directory, an AVR Studio Solution file of the name tutor1 and a directory of the name tutor1 are created. Under the directory c:\books\avr\ programs\ch04\tutor1\tutor1, you should see at least a Debug directory, the assembly program file tutor1.asm, and the tutor1 assembler project file. If you have other assembly program files to be included to this project, they should be stored in the c:\books\avr\prorgams\ch04\ tutor1\tutor1 directory. Assuming that you need to call the delay function delayby10ms in the delays.asm file, then this file should be included there. 4.8 Summary Development tools are indispensible for learning a microcontroller. Development tools can be divided into two categories: software tools and hardware tools. Software development tools include assembler, compiler, linker, librarian, simulator, and debugger. The assembler and compiler convert source code into machine instructions. The linker resolves variable cross-referencing and memory space assignment. The librarian allows the user to invoke the utility functions in the library provided by the compiler and put well-tested subroutines and functions (written by the user) into a library for future reuse. The simulator allows the user to execute a program of certain instruction set without the actual hardware by performing the intended operation for each instruction in the program and using the PC memory to hold the contents of each program variable. The debugger is a program written to test the correctness of another program. It may use either the simulator to execute the user program or execute the program directly using the target hardware via a debug adapter. The debugger has the capability to set breakpoints, single step, execute program until the cursor position, and then update the register and memory contents. Most debuggers also allow the user to place certain program variables of interest in a watch window (or watch list) so that the user can easily observe the program execution result. The assembler, compiler, linker, librarian, simulator, debugger, and project manager are often integrated into a single software package called integrated development environment (IDE). Atmel provides the AVR Studio IDE to its customers for free, to support program development for the AVR microcontroller. The AVR Studio IDE contains all of the software mentioned previously. The AVR Studio IDE can be downloaded from the Atmel website at www.atmel.com. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 4.9 ■ Lab Assignments 103 The most important hardware tools for learning microcontrollers are demo boards and the debug adapter. Demo boards allow the user to test the program under development. Demo boards are essential for testing experiments that involve peripheral chips and I/O devices. A feature-rich demo board is very helpful for learning the AVR. Atmel provides four debug adapters: the Dragon, JTAGICE3, JTAGICE mkII, and the AVR ONE!. The Dragon debug adapter is least expensive, and there is no program size limit (there was a 32 kB program size limit when the author started writing this text). 4.9 Lab Assignments L4.1 The following program finds the number of elements that are greater than 100 or less than 40, using the repeat-until looping construct to implement the loop: 6m2560def.inc7 ; or ATXMega128A1def.inc .include .equ NN = 40 .def lpcnt = r16 .def count = r17 .def tmp1 = r18 .def tmp2 = r19 .macro setPointer ldi @0,low(@2) ldi @1,high(@2) .endmacro .cseg .org 0x00 rjmp start .org 0xF6 start: ldi lpcnt,NN ; initialize ii to NN clr count ; initialize count to 0 ldi tmp1,40 ; values to be compared ldi tmp2,100 ;" setPointer ZL,ZH,(array<<1) ; use register Z as a pointer to the array rploop: lpm r0,z+ ; read the next array element cp r0,tmp1 ; is the element smaller than 40? brlt yes ; if yes, then branch to check upper bound cp tmp2,r0 ; is the number larger than 100? brlt yes rjmp next yes: inc count next: dec lpcnt brne rploop done: rjmp done array: .db 10,41,12,13,14,15,16,17,18,19 .db 50,21,52,23,24,25,26,27,28,29 .db 30,31,32,33,34,35,36,37,38,39 .db 60,162,56,99,132,103,104,89,78,59 // end of program Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 104 Chapter 4 ■ Hardware and Software Development Tools for the AVR Perform the following operations: (a) Create a new project and call it lab1. (b) Create a new file (call it lab1.asm), and enter the previous program into this file. This file is added into the project automatically. (c) Make the project. Eliminate syntax errors if there are any. (d) Connect the Dragon, JTAGICE 3, or JTAGICE mkII to the demo board and power up the demo board. (e) Download the program onto the demo board by selecting DebugãStart Debugging and Break. (f) Make sure the Watch window is open, and add count and lpcnt into the Watch window. (g) Reset the CPU. (h) Press the right mouse button on the setPointer macro call and select Run to Cursor. What are the contents of the Watch Window? (i) Press the right mouse button on the last instruction of the program and select Run to Cursor. What are the contents of the Watch Window? L4.2 Write a program to count the total even numbers in an array of 8-bit elements. Leave the count in the register r0. Use the AVR Studio IDE to enter, assemble, and execute the program. L4.3 Write a program to compute the average of the maximum and minimum numbers of an array of 8-bit numbers. Use AVR Studio to enter, assemble, and execute the program. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 5 Advanced Assembly Programming and Subroutine Calls 5.1 Objectives After completing this chapter, you will be able to • Understand the issues related to subroutine calls. • Initialize the stack pointer and perform stack operations. • Write subroutines to create time delays. • Explain and apply top-down-design with hierarchical refinement software development methodology. • Write subroutines to multiply and divide signed and unsigned 16-bit or larger numbers. • Write a subroutine to determine whether a number is a prime number. • Perform program debugging that involves subroutines. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 106 Chapter 5 ■ Advanced Assembly Programming and Subroutine Calls 5.2 Introduction It is not unusual that the same sequence of instructions has to be executed in several places of the same program. Macros have been used so far as the solution to this issue. However, using the macro call duplicates the same sequence of instructions in places where the macro is invoked and causes the program size to be bloated. Fortunately, all microprocessors and microcontrollers provide the subroutine mechanism that enables the program to invoke the same sequence of instructions in many different places of the program without duplicating it. A subroutine is often written to perform operations based on the inputs provided by the caller. The inputs provided by the caller are called incoming parameters. The caller of the subroutine often expects the subroutine to return certain results to it. Subroutine calls cause program flow to change. In general, the processor executes a subroutine-call instruction to change the program flow. When the subroutine-call instruction is being executed, the processor performs at least the following two operations: • Saves the return address in the stack. Return address is the address of the instruction that immediately follows the subroutine-call instruction. • Loads the starting address of the subroutine into the program counter. After that, the processor control is transferred to the subroutine. When the processor finishes execution of the subroutine, it returns to the instruction immediately after the subroutine-call instruction. This is achieved by executing a return-from-subroutine (RET) instruction. The subroutine-call and return-from-subroutine instructions work together to make the subroutine mechanism work. The subroutine-call instruction saves the return address in the stack data structure and at the same time changes program flow to the start of the subroutine. The return-from-subroutine instruction fetches the return address from the stack, places it in the program counter, and hence returns the program control to the instruction immediately after the subroutine-call instruction. It was mentioned in Section 3.7 that “top-down design with hierarchical refinement” is the most popular software development methodology. The subroutine mechanism makes this methodology possible. In addition, it is important for the software developers to reuse the working program pieces that they developed earlier in order to avoid duplicating the same work and improve productivity. Both the macro and subroutine mechanisms facilitate the reuse of software. Programmers can collect common macros and subroutines into files and selectively include them into their new programs to save the development time. 5.3 The Stack Data Structure A stack is a data structure from which elements can be accessed only from its top. The processor can add a new element to the stack by performing a push operation. To remove an element from the stack, the processor performs a pull (or pop) operation. Physically, a stack grows from a high address toward lower addresses or from a low address toward higher addresses. Depending upon the processor, the stack pointer points to the top element of the stack or to the byte immediately above the top element of the stack. The AVR stack grows from a high address toward lower addresses (shown in Figure 5.1) and has a 16-bit stack pointer (SP) that points to the byte immediately above the top byte of the stack. The memory space available for use by the stack is limited in a computer system. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 5.3 ■ 107 The Stack Data Structure SP Top byte Low address High address Figure 5.1 ■ Source: Atmel Corporation, The Atmel AVR Microcontroller There is always a danger of stack overflow and stack underflow. Stack overflow is a situation in which the processor pushes data into the stack too many times so that the SP points to a location outside the area allocated to the stack. Stack underflow is a situation in which the processor pulls data from the stack too many times so that the SP points to an area below the stack bottom. The diagram of AVR stack 5.3.1 Initializing the Stack Pointer The stack pointer must be initialized before the stack can be used. The stack data structure must be created inside the on-chip SRAM area. Different AVR devices may have different sizes of on-chip SRAM. In the AVR device include file of the AVR Studio assembler, the last byte of the on-chip SRAM is defined as RAMEND. This variable has a different value for different AVR devices. The user can load this value into the stack pointer and use it as its initial value. The stack pointer (SP) is implemented as two 8-bit registers (SPH and SPL) in the I/O space for Mega devices. For XMega devices, SPL and SPH are referred to as CPU_SPL and CPU_SPH, respectively. The user needs to use the IN and OUT instructions to access them. The initialization of the AVR Mega stack pointer is usually done immediately after reset as follows: ldi out ldi out temp,low(RAMEND) SPL,temp temp,high(RAMEND) SPH,temp ; temp is one of the registers from r16 to r31 ; initialize the SP ; " ; " The initialization of the XMega stack pointer is as follows: ldi out ldi out temp,low(RAMEND) CPU_SPL,temp temp,high(RAMEND) CPU_SPH,temp ; temp is one of the registers from r16 to r31 ; initialize the SP ; " ; " 5.3.2 Instructions for Stack Operation The AVR provides two instructions for stack operations. The push Rd instruction places the contents of the Rd register at the location pointed to by the SP and then decrements SP by 1. The pop Rd instruction increments SP by 1 and then copies the contents of the memory location pointed to by the SP to the Rd register. The push Rd instruction is mainly used to save the contents of a register in the stack, whereas the pop Rd instruction is mainly used to restore the contents of a register from the stack during the execution of a program. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 108 Chapter 5 ■ Advanced Assembly Programming and Subroutine Calls 5.4 An Example of Subroutine A subroutine is a sequence of instructions that can be called from many places of a program. At the end of the subroutine, the program control returns to the instruction immediately after the instruction that calls this subroutine. A sequence of instructions can be converted to a subroutine by: • • adding a label (name of the subroutine) to the first instruction of the sequence. adding a ret instruction as the last instruction of the sequence. For example, the following instruction sequence swaps the contents of register r16 and r17: push mov r16 r16,r17 ; save the contents of r16 in stack ; copy the contents of r17 to r16 pop r17 ; place the contents of r16 in r17 This instruction sequence can be converted into a subroutine as follows: swapRegs: push mov pop ret r16 r16,r17 r17 ; save the contents of r16 in stack ; copy the contents of r17 to r16 ; place the contents of r16 in r17 The instruction sequence that creates a 500 µs time delay (CPU clock is 16 MHz), described in Section 3.14, can be converted into a subroutine as follows: delay500us: loop0: loopi: ldi ldi push pop dec brne dec brne ret r21,250 r20,4 r0 r0 r20 loopi r21 loop0 ; adding a label to the first instruction ; set loop count to 250 ; 1 cycle ; 2 clock cycles ; 2 clock cycles ; 1 CPU clock cycle ; 2 (1) cycle when branch is taken (not taken) ; 1 cycle ; 2 (1) cycle when branch is taken (not taken) ; to return to the caller This subroutine is much more useful if it creates a time delay that is a multiple of 500 µs and allows the caller to specify the multiple. The following version of the subroutine achieves just that, and the multiple is passed in r16: delayby500us: ldi loop0: ldi loopi: push pop dec brne dec brne dec brne ret ; r21,250 ; set loop count to 250 r20,4 ; 1 cycle r0 ; 2 clock cycles r0 ; 2 clock cycles r20 ; 1 CPU clock cycle loopi ; 2 (1) cycle when branch is taken (not taken) r21 ; 1 cycle loop0 ; 2 (1) cycle when branch is taken (not taken) r16 ; decrement multiple count delayby500us ; to return to the caller Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 5.5 ■ Issues Related to Subroutine Calls 109 The caller needs to place the multiple in r16 before calling this subroutine. For example, the following instruction sequence calls delayby500us to create a delay of 100ms: ldi call r16,200 delayby500us 5.5 Issues Related to Subroutine Calls There are three major issues related to subroutine calls: parameter passing, result returning, and local variable allocation. 5.5.1 Parameter Passing The caller of the subroutine may pass parameters, using registers, stack, or global memory. For the AVR, the programmer can use registers r0 to r31 to pass parameters to the subroutine. Because most of the AVR instructions only operate on these registers, they are preferred for passing parameters. The stack and on-chip data memory (global memory) also can be used to pass parameters to the subroutine. 5.5.2 Local Variable Allocation and Deallocation In addition to parameters passed to it, a subroutine may also need memory space (or additional CPU registers) to hold temporary variables and results. These variables are useful only during the execution of the subroutine and are called local variables because they are local to the subroutine. Theoretically, it is a perfect idea to allocate local variables in the stack, because local variables come into being when the subroutine is entered and disappear when the subroutine is exited as long as the subroutine allocates local variables at its entrance and deallocates local variables before it returns to the caller. This can avoid the interference among subroutines when a subroutine requires calling other subroutines. Allocating local variables in the stack has an additional benefit: It allows the creation of re-entrant subroutines. A re-entrant subroutine can call itself. However, the fact that no AVR instruction can perform arithmetic or logical operation on memory locations makes it a poor idea to assign local variables to data memory. Before an operation can be performed, local variables must be loaded into CPU registers. After the operation, the result must be written back to the stack. This procedure is inefficient. A better idea is to use CPU registers for local variables as much as possible. However, we must be careful not to overwrite the registers that have been assigned to variables of the caller. This problem can be avoided by saving registers used in the subroutine in the stack. When a subroutine needs more space for local variables than can be supported by the CPU registers, we must assign it to the stack. The programmer can use the following instruction sequence to allocate k bytes in the stack for local variables for Mega devices: in in sbiw out out r28,SPL r29,SPH r28,k SPL,r28 SPH,r29 ; use CPU_SPL for XMega devices ; use CPU_SPH for XMega devices ; allocate k bytes in the stack (0 < k < 64) Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 110 Chapter 5 ■ Advanced Assembly Programming and Subroutine Calls This instruction sequence can be converted to a macro as follows: .macro in in sbiw out out .endmacro allocStk r28,SPL r29,SPH r28,@0 SPL,r28 SPH,r29 ; use CPU_SPL for XMega devices ; use CPU_SPH for XMega devices ; allocate k bytes in the stack The subroutine should deallocate the stack space used by local variables before returning to the caller. The following instruction sequence deallocates k bytes of space from the stack for Mega devices: in in adiw out out r28,SPL r29,SPH r28,k SPL,r28 SPH,r29 ; use CPU_SPL for XMega devices ; use CPU_SPH for XMega devices ; deallocate k bytes from the stack This instruction sequence can be converted to a macro as follows: .macro in in adiw out out .endmacro deallocStk r28,SPL r29,SPH r28,@0 SPL,r28 SPH,r29 ; use CPU_SPL for XMega devices ; use CPU_SPH for XMega devices ; deallocate k bytes in the stack When the caller of a subroutine has many parameters to be passed, it may also pass them in the stack. The subroutine may save registers and allocate local variables in the stack. The region in the stack that holds incoming parameters, return address, saved registers, and local variables is referred to as the stack frame. A stack frame may look like the one shown in Figure 5.2. Local variables Saved registers Return address Incoming parameters Figure 5.2 ■ Source: Atmel Corporation, The Atmel AVR Microcontroller SP Structure of the AVR stack frame 5.5.3 Result Returning A subroutine may return its computation result in registers, stack, or global memory. For the AVR, a subroutine can return its computation results using registers r0~r31, the space in stack, or the on-chip data memory. The programmer can use the allocStk macro to reserve space in stack for returning the result. This operation can be done by the caller or the callee (subroutine being called). However, it takes the caller less effort to do (Why?). Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 5.5 ■ 111 Issues Related to Subroutine Calls 5.5.4 Accessing Local Variables in the Stack The local variables allocated in the stack are accessed by using the data-indirect-withdisplacement addressing mode. Because the base address must be in Y or Z, we must transfer the contents of SP to Y or Z. For example, the local variable locVark in Figure 5.3 is loaded into register r0, using the following instruction sequence: in in ldd YL,SPL YH,SPH r0,Y1k ; use CPU_SPL for XMega devices ; use CPU_SPH for XMega devices To store the contents of the r0 register in locVark in Figure 5.3, we use the following instruction sequence: in in std YL,SPL YH,SPH Y1k,r0 ; use CPU_SPL for XMega devices ; use CPU_SPH for XMega devices n k 3 2 1 locVar1 locVar2 locVar3 locVark locVarn Figure 5.3 ■ SP Source: Atmel Corporation, The Atmel AVR Microcontroller If we need to access local variables in the stack many times in a subroutine, we use either the Y or Z register to point to the top of the stack. Accessing local variables in the stack 5.5.5 Register Usage Issue Because both the subroutine and the caller of the subroutine need to use CPU registers, there might be interference. The interference must be avoided in order for programs to execute correctly. Atmel does not have recommendation to the usage of AVR registers even though many 32-bit microcontroller vendors do. The recommendations of register usage, parameter passing, and result returning are part of the embedded-application binary interface (EABI) for 32-bit microcontrollers. In the EABI of a 32-bit MCU, certain registers are reserved for parameter passing, certain registers are reserved for returning results, certain registers (referred to as caller-saved registers) are specified to be saved by the caller, and other registers (referred to as callee-saved registers) are specified to be saved by the callee. Caller-saved registers are saved by the caller before it calls a subroutine and it has the concern that these registers may be modified by the subroutine. Callee-saved registers are saved by the subroutine whenever it needs to modify these registers. In this text, we follow the recommendation of the register usage shown in Table 5.1 for assembly language programming. 5.5.6 Instructions for Subroutine Call The AVR provides four subroutine-call instructions and one return instruction (listed in Table 5.2) to support the subroutine-call mechanism. All of the subroutine-call instructions Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 112 Chapter 5 ■ Advanced Assembly Programming and Subroutine Calls Name ∼ ∼ r4 r7, r12 r15, r28, r29 r0∼r3, r8∼r11, r20, r21 r16∼r19, r30, r31 r22∼r27 Usage Callee saved Caller saved Parameter passing Result returning Source: Atmel Corporation, The Atmel AVR Microcontroller Table 5.1 ■ Recommendation for register usage push the return address onto the stack before transferring the program control to the subroutine. Depending upon the devices, the return address may be 2 or 3 bytes. CALL k This instruction calls a subroutine within the entire program memory. When this instruction is executed, the AVR processor places the constant k in the program counter (PC) and also pushes the address of the next instruction onto the stack. After this, the program control is transferred to the subroutine at address k. The constant k is a value between 0 and 216 2 1 for devices with a 16-bit PC and up to 128 kB of program memory. The constant k would be a value between 0 and 222 2 1 for devices with a 22-bit PC and 8 MB program memory maximum. The following instruction sequence illustrates the use of this instruction: chkVal: error: ldi call … … cpi breq … ret … … ret r16,0x40 chkVal ; call a subroutine r16,0x35 error EICALL This instruction calls a subroutine pointed to by the Z pointer register in the register file and the EIND register in the I/O space. When this instruction is executed, the AVR processor places the value held in Z into the lower 16 bits of the PC and places the value held in the EIND register into the upper 6 bits of the PC, and transfers program control to that address. The AVR also saves the return address in the stack. The following instruction sequence calls the subroutine located at 0x201000: ldi out ldi ldi eicall r16,0x20 EIND,r16 r30,0x00 r31,0x10 ; place 0x20 in EIND ; " ; place 0x1000 in Z ; " ; call the subroutine at 0x201000 Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 5.5 ■ 113 Issues Related to Subroutine Calls ICALL This instruction calls the subroutine specified by the Z pointer register. For devices with 22-bit PC, the highest 6 bits of the PC (PC(21:16)) are forced to 0. The return address is pushed onto the stack after the execution of this instruction. The following instruction sequence illustrates the use of this instruction: ldi ldi icall ZL,low(subx) ZH,high(subx) ; set up subroutine address in Z ; " RCALL k The range of constant k (an 11-bit value) is between 22048 and 2048. This instruction allows a program to call a subroutine that is k words away from the rcall instruction. When using this instruction, the programmer specifies the name of the subroutine to be called, and the assembler figures out the actual distance of the subroutine to be called. The following instruction sequence illustrates the use of this instruction: bubble: rcall … push … pop ret bubble r12 r12 RET This instruction returns from subroutine. Depending upon the device, the AVR processor pops up the top two or three bytes from the stack and places the value onto the program counter, and the program control transfers to the new PC value. This instruction should be the last instruction to be executed in a subroutine. Instruction Operation call k PC ← k; stack ← PC 1 2; SP ← SP 2 2 (devices with 16-bit PC) SP ← SP 2 3 (devices with 22-bit PC) eicall PC(15:0) ← Z(15:0); PC(21:16) ← EIND; stack ← PC 1 1; SP ← SP 2 3 icall PC(15:0) ← Z(15:0); PC(21:16) ← 0; (devices with 22-bit PC); stack ← PC 1 1; SP ← SP22 (devices with 16-bit PC); SP ← SP 2 3 (devices with 22-bit PC) rcall k PC ← PC 1 K 1 1; stack ← PC 1 1; SP ← SP 2 2 (devices with 16-bit PC); SP ← SP 2 3 (devices with 22-bit PC) ret PC(15:0) ← stack (devices with 16-bit PC); SP ← SP 1 2 PC(21:0) ← stack (devices with 22-bit PC); SP ← SP 1 3 Source: Atmel Corporation, The Atmel AVR Microcontroller Table 5.2 Subroutine call instructions Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 114 Chapter 5 ■ Advanced Assembly Programming and Subroutine Calls 5.6 Writing Subroutines to Perform Multiprecision Arithmetic The AVR provides no instructions for performing arithmetic on 16-bit or larger numbers. In this section, we write subroutines that can perform 16-bit unsigned and signed multiplication and division. An unsigned number is nonnegative, whereas a signed number may be positive, zero, or negative. The most significant bit of a signed number is the signed bit. When the signed bit is 1, the number is negative. Otherwise, it is either 0 or positive. 5.6.1 Writing Subroutines to Perform 16-Bit Unsigned Multiplication To multiply two 16-bit unsigned numbers, the multiplier and the multiplicand must be broken down into 8-bit chunks, and four 8-bit by 8-bit multiplications are performed. Suppose that P and Q are two 16-bit unsigned numbers to be multiplied; they are broken down as follows: P 5 PHPL 5 PH 3 28 1 PL Q 5 QHQL 5 QH 3 28 1 QL where PH, PL, QH, and QL are the upper and lower bytes of P and Q, respectively. Four byte-tobyte multiplications are performed, and then the partial products are aligned and added together, as shown in Figure 5.4. The procedure for adding these four partial products is as follows: Step 1 Allocate four bytes to hold the product. Refer to these four bytes using the symbols PR, PR 1 1, PR 1 2, and PR 1 3, respectively. Step 2 Compute the partial product PLQL and save it at locations (or registers) PR and PR 1 1. Store the high byte of the product at PR 1 1 and low byte of the product at PR, respectively. Step 3 Compute the partial product PHQH and save it at locations PR 1 2 and PR 1 3. Store the high byte of the product at PR 1 3 and the low byte of the product at PR 1 2, respectively. Step 4 Compute the partial product PHQL and add it to the memory locations PR 1 1 and PR 1 2. Add the carry flag to the memory location PR 1 3. lsb Partial product PLQL Partial product PHQL Partial product PLQH + Partial product PHQH Address PR + 3 PR + 2 PR + 1 Figure 5.4 ■ PR Final product P × Q Source: Atmel Corporation, The Atmel AVR Microcontroller msb 16-bit by 16-bit multiplication Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 5.6 ■ Writing Subroutines to Perform Multiprecision Arithmetic 115 Step 5 Compute the partial product PLQH and add it to the memory locations PR 1 1 and PR 1 2. Add the carry flag to the memory location PR 1 3. Example 5.1 ▼ Write a subroutine to multiply two unsigned 16-bit integers passed in r16:r17 and r18:r19, and return the product in r22, r23, r24, and r25. r17 and r19 hold the upper bytes of two numbers to be multiplied, and r25 down to r22 hold the most significant to the least significant bytes of the product. Solution: The assembly subroutine that implements the previous algorithm and its test program are as follows: start: forever: .include .equ .equ .equ .equ .def .cseg .org rjmp .org ldi out ldi out ldi ldi ldi ldi call rjmp <ATXMega128A1def.inc> num1H 5 0x37 ; high byte of the first test data num1L 5 0x32 ; low byte of the first test data num2H 5 0x41 ; high byte of the second test data num2L 5 0x48 ; low byte of the second test data temp 5 r16 0x00 start 0xF6 temp,low(RAMEND) CPU_SPL,temp temp,high(RAMEND) CPU_SPH,temp r16,num1L r17,num1H r18,num2L r19,num2H mul16U forever ; temp is one of the registers from r16 to r25 ; initialize the SP (use SPL for Mega devices) ; " ; (use SPH for Mega devices) ; pass the first number in r16~r17 ; " ; pass the second number in r18~r19 ; " ; ------------------------------------------------------------------------------------------------------------------; The next subroutine multiplies the 16-bit unsigned number contained in r16~r17 ; and r18~r19 and returns the product in r25~r22. ; ------------------------------------------------------------------------------------------------------------------.def p1 5 r22 .def p2 5 r23 .def p3 5 r24 .def p4 5 r25 .def pH 5 r17 .def pL 5 r16 .def qH 5 r19 .def qL 5 r18 mul16U: mul pL,qL ; generate partial product PL * QL mov p1,r0 mov p2,r1 Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 116 Chapter 5 ■ Advanced Assembly Programming and Subroutine Calls mul mov mov mul add adc ldi adc mul add adc ldi adc ret pH,qH p3,r0 p4,r1 pL,qH p2,r0 p3,r1 r20,0 p4,r20 pH,qL p2,r0 p3,r1 r20,0 p4,r20 ; generate partial product PH * QH ; generate partial product PL * QH ; generate partial product PH * QL The multiplication of two numbers longer than 16 bits or two numbers of different lengths can be performed using the same method. ▲ 5.6.2 Writing a Subroutine to Perform 16-bit Signed Multiplication Because the computer’s word length is limited, it is essentially performing modulus arithmetic when performing an arithmetic operation. For example, an 8-bit MCU drops (discards) the part of the result that is equal to or larger than 28. A 16-bit MCU drops the part of the result that is equal to or larger than 216. Adding 28 to the result of the arithmetic operation performed by an 8-bit MCU has no effect on the result, because this value (28) cannot be kept in the arithmetic hardware of an 8-bit MCU. In summary, in an n-bit MCU, the result of any arithmetic operation is equal to the remainder of the initial result divided by 2n (i.e., it is performing a modulo-2n operation). The multiplication of signed numbers requires the programmer to consider the signs of the multiplier and the multiplicand. Let P and Q represent the magnitudes of two numbers. There are four possible situations. Case 1 Both operands are positive (op1 5 P, op2 5 Q). The product of these two operands can be computed by using either the mul Rd,Rs instruction for 8-bit operands or the procedure described in Section 5.6.1 for 16-bit and longer operands. Case 2 The first operand is negative (op1 5 2P), whereas the second operand is positive (op2 5 Q). The first operand op1 is represented in two’s complement of P (28 – P if P is 8-bit, 216 – P if P is 16-bit, etc.). The product of two n-bit operands 2P and Q can be rewritten as follows: 2P 3 Q 5 (2n 2 P) 3 Q 5 (2n 3 Q) 2 P 3 Q 5 22n 2 P 3 Q 1 2n 3 Q 3 3 ➀ ➁ The value 22n is added to the above expression. Because the MCU is performing a modulo2 arithmetic in this case, adding the value of 22n makes no difference to the result. Item 1 is the two’s complement of the number 2P 3 Q and is the correct product. Part 2 is an extra term and should be eliminated from the product. This extra term can be eliminated by subtracting op2 from the upper half of the product of 2P and Q. 2n Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 5.6 ■ 117 Writing Subroutines to Perform Multiprecision Arithmetic Case 3 The first operand is positive (op1 5 P), but the second operand is negative (op2 5 2Q). Similar to Case 2, the product of two n-bit operands P and 2Q can be rewritten as follows: P 3 (2 Q) 5 P 3 (2n 2 Q) 5 (2n 3 P) 2 P 3 Q 5 22n 2 P 3 Q 1 2n 3 P 3 3 ➀ ➁ The value of 22n is added to the expression, and it makes no difference to the result for the same reason as in Case 2. Again, the first term is the correct product, which is represented as the two’s complement of 2P 3 Q. The second term of the product is an extra term and can be eliminated by subtracting op1 from the upper half of the product of P and 2Q. Case 4 Both operands are negative (op1 5 2P, op2 5 2Q). The product of two n-bit operands 2P and 2Q can be rewritten as follows: (2P) 3 (2Q) 5 (2n 2 P) 3 (2n 2 Q) 5 22n 2 2n 3 P 2 2n 3 Q 1 P 3 Q 5 P 3 Q 1 22n 2 2n 3 P 1 22n 2 2n 3 Q 5 P 3 Q 1 2n 3 (2n 2 P) 1 2n 3 (2n 2 Q) 3 3 3 ➀ ➁ ➂ 2n The value of 2 is added to the expression. It makes no difference to the result for the same reason as in Case 2. The first term is the product of –P and –Q. The second term and the third term are extra terms and must be eliminated. The second term is eliminated by subtracting op1 from the upper half of the product, whereas the third term is eliminated by subtracting op2 from the upper half of the product. By combining these four situations, we conclude that the signed n-bit multiplication can be implemented by the following algorithm: Step 1 Multiply two operands (that is, compute op1 3 op2) disregarding their signs. Step 2 If op1 is negative, then subtract op2 from the upper half of the product. Step 3 If op2 is negative, then subtract op1 from the upper half of the product. Example 5.2 ▼ Write a subroutine that can multiply two 16-bit signed integers. The multiplier and multiplicand are passed to this subroutine in r16:r17 and r18:r19, respectively. The product is returned in registers r22~r25, with the most significant byte stored in r25 and the least significant byte restored in r22, respectively. Solution: This subroutine may call the mul16u subroutine to perform unsigned 16-bit multiplication. The subroutine and its test program are as follows: .include <ATXMega128A1def.inc> .equ num1H 5 0x97 .equ num1L 5 0x76 .equ num2H 5 0x41 .equ num2L 5 0x48 .def temp5r16 ; high byte of the first test data ; low byte of the first test data ; high byte of the second test data ; low byte of the second test data Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 118 Chapter 5 ■ Advanced Assembly Programming and Subroutine Calls .cseg .org 0x00 rjmp start .org 0xF6 start: ldi temp,low(RAMEND) ; temp is one of the registers from r16 to r25 out CPU_SPL,temp ; initialize the SP ldi temp,high(RAMEND) ; " out CPU_SPH,temp ldi r16,num1L ; pass the first number in r16~r17 ldi r17,num1H ; " ldi r18,num2L ; pass the second number in r18~r19 ldi r19,num2H ; " call mul16s forever: rjmp forever ;--------------------------------------------------------------------------------------------------------------------; The next subroutine multiplies the 16-bit signed numbers held in r16~r17 and ; r18~r19 and returns the product in r25~r22. ; -------------------------------------------------------------------------------------------------------------------mul16s: call mul16U ; multiply two numbers disregarding their signs sbrs r17,7 ; check the sign bit of the first number rjmp chk2 sub r24,r18 sbc r25,r19 chk2: sbrs r19,7 ; check the sign bit of the second number rjmp doneMs sub r24,r16 sbc r25,r17 doneMs: ret ; ------------------------------------------------------------------------------------------------------------------; Include MUL16U here ; ------------------------------------------------------------------------------------------------------------------- ▲ 5.6.3 Writing Subroutines to Perform Unsigned Multiprecision Division The AVR does not provide any divide instruction. The division operation must be implemented in macros or subroutines. One of the most widely used division methods is the repeated-shift-and-subtract method. This method assumes the use of three n-bit registers, R, Q, and S. The repeated-shift-and-subtract algorithm consists of two phases. I N I T I A L I Z AT I O N P H A S E Place 0, dividend, and divisor in registers R, Q, and S, respectively SHIFT-AND-SUBTRACT PHASE Repeat: Step 1 Shift the register pair R and Q to the left one place. Step 2 Subtract S from R, and place the difference back to R if the difference is non-negative. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 5.6 ■ Writing Subroutines to Perform Multiprecision Arithmetic 119 Step 3 Set the least significant bit of Q to 1 if the result in Step 2 is non-negative. Otherwise, set the least significant bit of Q to 0 for n times. Example 5.3 ▼ Write a subroutine that can divide an unsigned 16-bit integer into another 16-bit unsigned integer. The dividend and divisor are passed in r16:r17 and r18:r19, respectively. Remainder and quotient are to be returned in register pairs r22:r23 and r24:r25, respectively. Solution: The assembly subroutine that implements the 16-bit unsigned division and its test program are as follows: .include <ATXMega128A1def.inc> .equ num1H 5 0xFA ; high byte of the first test data .equ num1L 5 0x00 ; low byte of the first test data .equ num2H 5 0x00 ; high byte of the second test data .equ num2L 5 0x50 ; low byte of the second test data .def temp 5 r16 .cseg .org 0x00 rjmp start .org 0xF6 start: ldi temp,low(RAMEND) ; initialize the SP out CPU_SPL,temp ; " ldi temp,high(RAMEND) ; " out CPU_SPH,temp ; " ldi r16,num1L ; pass the dividend in r16~r17 ldi r17,num1H ; " ldi r18,num2L ; pass the divisor in r18~r19 ldi r19,num2H ; " call div16U forever: nop rjmp forever ;----------------------------------------------------------------------------------------------------------------------------; The next subroutine divides the 16-bit unsigned numbers contained in r18~r19 into the 16-bit ; unsigned number contained in r16~r17 and returns the quotient in r25~r24 and ; the remainder in r23~r22. ; ----------------------------------------------------------------------------------------------------------------------------.def lpcnt 5 r20 .def tmpL 5 r0 .def tmpH 5 r1 div16U: ldi lpcnt,16 ; set up divide iteration count movw r24,r16 ; place dividend in Q register clr r23 ; load 0 in R register clr r22 ; " dvloop: lsl r24 ; shift R:Q to the left one place rol r25 ; " rol r22 ; " rol r23 ; " Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 120 Chapter 5 ■ Advanced Assembly Programming and Subroutine Calls movw sub sbc brmi movw ori rjmp less: andi nxtb: dec brne ret // end of program tmpL,r22 tmpL,r18 tmpH,r19 less r22,tmpL r24,0x01 nxtb r24,0xFE lpcnt dvloop ; save R in temporary registers ; compute R 2 S ; " ; branch if divisor is larger ; save the difference in R ; set the lsb of Q to 1 ; set the lsb of Q to 0 ▲ 5.6.4 Converting an Internal Binary Number into a BCD String A binary number in the computer memory cannot be directly output to an output device. It must be converted into a BCD string before being output. A BCD string uses the ASCII code to represent each decimal digit. For example, the binary number 110101102 is converted to a threebyte string 0x32 0x31 0x34 before being output. After being output to a monitor screen or an LCD, the string appears as the decimal value 214. For easy processing, a BCD string is usually terminated by a NULL character (ASCII code is 0). Example 5.4 ▼ Write a subroutine to convert a 16-bit signed integer into a string of BCD digits, and save the conversion result in a data memory buffer pointed to by the Z register. The string is terminated by a NULL character. The high and low bytes of the number to be converted are passed in r16 and r17, respectively. Solution: An unsigned binary number can be converted into a BCD string by executing an algorithm that performs repeated division by 10 until the quotient becomes zero. Adding 0x30 to the remainder converts the remainder to its ASCII code. This process generates a string that is reversed. It can be converted back to the right order by pushing it into the stack and then popping it out. Let xx, quo, rem, and ptr represent the number to be converted, quotient of the division process, remainder of the division process, and the pointer to the buffer to hold the resultant string, respectively. The procedure is as follows. Step 1 Push 0 into stack. Step 2 quo ← xx/10; rem ← xx mod 10 Step 3 Stack ← rem 1 0x30 Step 4 If quo ≠ 0, xx ← quo and go to Step 2; otherwise, go to Step 5. Step 5 Pop the string out of the stack and store it in the buffer. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 5.6 ■ Writing Subroutines to Perform Multiprecision Arithmetic 121 A negative number should be converted into its two’s complement representation before being processed by the previous algorithm. After conversion, a negative number is preceded by a minus sign. The assembly program that implements this algorithm is as follows: .include <ATXMega128A1def.inc> .equ numH 5 0xE6 ; high byte of the test data (-6601) .equ numL 5 0x37 ; low byte of the test data .dseg .org 0x2000 ; change to 0x200 for Mega devices buf: .byte 20 .cseg .org 0x00 rjmp start .org 0xF6 start: ldi r16,low(RAMEND) ; temp is one of the registers from r16 to r25 out CPU_SPL,r16 ; initialize the SP (use SPL for Mega devices) ldi r16,high(RAMEND) ; " out CPU_SPH,r16 ; "(use SPH for Mega devices) ldi r16,numL ; place the number in r16~r17 ldi r17,numH ; " ldi ZL,low(buf) ; place the buffer address in Z ldi ZH,high(buf) ; " call bin2bcd forever: nop rjmp forever ; -------------------------------------------------------------------------------------------------------------------------; The following subroutine converts the 16-bit binary number held in r17~r16 into an ; ASCII BCD string and stores the string in a buffer pointed to by the Z register. ; -------------------------------------------------------------------------------------------------------------------------.def sign 5 r12 ; initialize sign flag to positive .equ NULL 5 0 ; ASCII code of NULL character bin2bcd: clr r12 ; initialize the sign to positive push r12 ; push a NULL character in the stack sbrs r17,7 ; is the given number negative? rjmp normal inc sign ; change the sign to negative com r16 ; compute the magnitude of the number com r17 ; " movw r26,r16 ; " adiw r26,1 ; " movw r16,r26 ; " normal: ldi r18,10 ; prepare to divide the number by 10 ldi r19,0 ; " call div16U ldi r26,0x30 ; convert the remainder digit to ASCII add r22,r26 ; " push r22 ; save the character in the stack sbiw r24,0 ; is the quotient 0? breq popSt ; quotient is zero, pop string out and save Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 122 Chapter 5 ■ Advanced Assembly Programming and Subroutine Calls movw r16,r24 ; quotient not zero, continue the divide rjmp normal ; loop popSt: sbrs sign,0 ; check the sign of the given number rjmp toRev ; do nothing if positive ldi r17,’-’ ; push a minus sign character into stack if negative push r17 ; " toRev: clr r0 popLp: pop r1 cp r1,r0 ; is it a NULL character? breq exit st z1,r1 rjmp popLp exit: st z,r0 ; terminate the string with a NULL character ret ;--------------------------------------------------------------------------------------------------------------------; Include the div16U subroutine here. ; -------------------------------------------------------------------------------------------------------------------// end of program ▲ 5.6.5 Signed Division Operation The one complication for signed division is that we must also set the sign of the remainder. This equation must always hold for division: Dividend 5 Quotient 3 Divisor 1 Remainder Our common sense requires that the magnitude of the quotient to be the same as long as the magnitudes of the dividends are the same and the magnitudes of the divisors are the same. We can determine the sign of the remainder on the basis of this principle. To illustrate, let’s use (±41) ÷ (±7) as an example. The first situation is simple. 41 ÷ 7: Quotient 5 15, Remainder 5 16 If we change the sign of the dividend, the quotient must be changed as well. 241 ÷ 7: Quotient 5 25 Rewriting our basic formula to find the remainder; we have Remainder 5 Dividend 2 Quotient 3 Divisor 5 241 2 (25 3 7) 5 241 1 35 5 26 If we change the sign of the divisor and keep the sign of dividend unchanged, 41 ÷ (27): Quotient 5 25 Remainder 5 41 2 (25 3 27) 5 41 2 35 5 6 If we change the signs of both the dividend and the divisor, 241 ÷ 27: Quotient 5 5 Remainder 5 241 2 (5 3 27) 5 241 135 5 26 From this discussion, we conclude that the correctly signed division algorithm negates the quotient if the signs of the operands are opposite and makes the sign of the nonzero remainder match that of the dividend. The signed division subroutine is straightforward and hence is left as an exercise. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 5.6 ■ 123 Writing Subroutines to Perform Multiprecision Arithmetic 5.6.6 Finding the Square Root There are several methods available for finding the square root of a number q. One of the methods is based on successive approximation shown in Figure 5.5. The square root of a 2n-bit number is n bits long. The successive approximation method computes the square root of a 32-bit integer in the following manner: Step 1 sar ← 0; mask ← 0x8000; lpcnt ← 16; temp ← 0 Step 2 temp ← sar OR mask Step 3 If ((temp ** 2) ≤ num) sar ← temp; Step 4 mask ← mask srl 1 (shift right logically one place); Step 5 lpcnt ← lpcnt 2 1 Step 6 If (lpcnt 55 0) stop; else go to step 2. Start SAR[i] ← 1 i ← i–1 SAR * SAR > num? yes SAR[i] ← 0 no no i = 0? yes Stop Source: Atmel Corporation, The Atmel AVR Microcontroller SAR[n–1, ..., 0] ← 0 i ← n–1 Figure 5.5 ■ Successive-approximation method for finding square root Example 5.5 ▼ Write a subroutine to implement the square root algorithm. This subroutine must be able to find the square root of a 32-bit unsigned integer. The parameter q (for which we want to find the square root) is passed in r19~r16, and the square root is returned in r22~r23. Solution: Four local variables are needed for implementing the square root algorithm: • • mask: set a bit in the SAR register to be 1 sar: successive approximation register Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 124 Chapter 5 • • ■ Advanced Assembly Programming and Subroutine Calls temp: the value of (mask OR sar) lpcnt: number of loop iterations to be performed These local variables are assigned to the following CPU registers: • • • • mask: r12~r13 sar: r8~r9 temp: r10~r11 lpcnt: r20 SP q4 q3 q2 q1 r16 r17 r18 r19 r28 r29 r12 r13 Return address Figure 5.6 ■ Source: Atmel Corporation, The Atmel AVR Microcontroller Several registers are saved in the stack due to the need for computation; the resultant stack is shown in Figure 5.6. Stack frame for Example 5.5 The subroutine that computes the square root of a 32-bit integer and its test program is as follows: .include buf: start: .equ .equ .equ .equ .dseg .org .byte .cseg .org rjmp .org ldi out ldi out ldi ldi <ATXMega128A1def.inc> ; test data for findSqRoot32 num4 5 0x01 ; msb of the test data num3 5 0x3E ; 3nd byte of the test data num2 5 0x42 ; 2rd byte of the test data num1 5 0x91 ; lsb of the test data 0x2000 20 0x00 start 0xF6 r16,low(RAMEND) CPU_SPL,r16 r16,high(RAMEND) CPU_SPH,r16 r16,num1 r17,num2 ; initialize the SP ; " ; " ; " ; place the number in r16~r19 ; " Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 5.6 ■ Writing Subroutines to Perform Multiprecision Arithmetic forever: ldi ldi call nop rjmp r18,num3 r19,num4 SqRoot32 125 ; " ; " ; compute the square root forever ; -----------------------------------------------------------------------------------------------------------------; The following subroutine computes the square root of a 32-bit integer contained ; in r19~r16 and returns the result in r22~r23. ; ------------------------------------------------------------------------------------------------------------------ SqRoot32: sqLoop: .equ .equ .equ .equ .def .def .def .def .def .def .def push push push push push push push push ldi clr movw clr clr ldi in in movw or or movw movw push call pop ldd sub ldd sbc q1 51 q2 52 q3 53 q4 54 maskH 5 r13 maskL 5 r12 sarH 5 r9 sarL 5 r8 tmpH 5 r11 tmpL 5 r10 lpcnt 5 r20 r13 r12 r29 r28 r19 r18 r17 r16 r21,0x80 r20 maskL,r20 sarH sarL lpcnt,16 r28,CPU_SPL r29,CPU_SPH tmpL,sarL tmpL,maskL tmpH,maskH r16,tmpL r18,tmpL lpcnt mul16U lpcnt r0,Y1q1 r0,r22 r0,Y1q2 r0,r23 ; save Y register ; " ; save a copy of the number of which square root is to be ; computed in the stack ; " ; " ; initialize mask to 0x8000 ; " ; " ; initialize sar to 0 ; " ; initialize loop count to 16 ; use Y to point to the byte above the top ; of the stack ; ; guess the kth bit is 1 ; " ; compute the sar * sar ; " ; " ; compare sar*sar with q ; " ; " ; " Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 126 Chapter 5 ■ Advanced Assembly Programming and Subroutine Calls ldd r0,Y1q3 ; " sbc r0,r24 ; " ldd r0,Y1q4 ; " sbc r0,r25 ; " brsh yes ; branch if q >5 sar * sar rjmp nxtb yes: or sarL,maskL ; keep the guess when it is correct or sarH,maskH ; " nxtb: lsr maskH ror maskL dec lpcnt brne sqLoop movw r22,sarL ; transfer the square root to r22~r23 pop r16 pop r17 pop r18 pop r19 pop r28 pop r29 pop r12 pop r13 ret ; --------------------------------------------------------------------------------------------------------------; include mul16U subroutine here ; --------------------------------------------------------------------------------------------------------------// end of program ▲ If a given number has an exact square root, this subroutine finds it. If the given number does not have an exact integer square root, then the number returned by the subroutine may not be the closest approximation. The algorithm in Figure 5.5 computes a sar that satisfies the relationship sar * sar Ä q. This may have the undesirable effect that the computed sar value may not be as close to the real square root as is the value of sar 1 1. However, this can be fixed easily by comparing the following two expressions: 1. (sar + 1)2 – q 2. q – sar2 If the first expression is smaller, then (sar 1 1) is a better choice. Otherwise, we should choose sar as the approximation to the real square root. This is left as an exercise problem. The subroutine that finds the square root of a 16-bit unsigned integer can be written in the same way and is made into a file (SqRoot16.asm) so that it can be reused in the next example. 5.6.7 Prime Test Subroutine Testing whether a number is a prime number may not be very useful for embedded applications. However, it can serve as a good example for software reuse. The most efficient method for testing whether a number is a prime number is to divide the number by all the prime numbers from 2 to its integral square root. Because the prime numbers from 2 to the square root of the given number are not available, we are satisfied with dividing the given number by all the integers from 2 to its integral square root. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 5.6 ■ Writing Subroutines to Perform Multiprecision Arithmetic 127 The algorithm for testing whether a number is a prime number is as follows: Step 1 Let num, k, and isprime represent the number to be tested, the loop index, and the flag to indicate if num is a prime number. Step 2 isprime ← 0; tlimit ← square root of num; Step 3 for k 5 2 to tlimit do if ((num % k) 55 0) then return; isprime ← 1; return; The following example implements this algorithm. Example 5.6 ▼ Write a subroutine that can determine whether an unsigned 16-bit integer is a prime number. Solution: The subroutine that determines whether a number is a prime and its test program is as follows: .include <ATXMega128A1def.inc> start: cntLoop: again: .equ .equ .equ .cseg .org rjmp .org ldi out ldi out ldi ldi call nop rjmp SPL 5 CPU_SPL SPH 5 CPU_SPH tstDat 5 7919 ; comment this line for AVR Mega devices ; comment this line for AVR Mega devices 0x00 start 0xF6 r20,low(RAMEND) SPL,r20 r20,high(RAMEND) SPH,r20 r16,low(tstDat) r17,high(tstDat) prime16 again ; ----------------------------------------------------------------------------------------------------------------------; The next subroutine determines whether an unsigned 16-bit integer is a prime number. ; The 16-bit number is passed in r16~r17 and the result (0 or 1) is returned in r22. ; ----------------------------------------------------------------------------------------------------------------------.def .def tLimit 5 r3 tstDiv 5 r21 ; limit of test divide ; number to test divide r16~r17 Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 128 Chapter 5 ■ prime16: eq2or3: normal: tdLoop: notP: isP: Advanced Assembly Programming and Subroutine Calls cpi brne cpi brhs cpi brhs ldi ret ldi ret call mov ldi mov clr push push call pop pop cpi breq cp breq inc rjmp ldi ret ldi ret .include .include r17,0 normal r16,4 normal r16,2 eq2or3 r22,0 ; is upper byte 0? ; upper byte not 0, continue ; is the number greater than 3? ; yes, continue ; is the number less than 2? ; yes, 2 and 3 are prime numbers ; 1 or 0 are not prime numbers r22,1 ; 2 and 3 are prime numbers SqRoot16 tLimit,r22 tstDiv,2 r18,tstDiv r19 tLimit tstDiv div16U tstDiv tLimit r22,0 notP tstDiv,tLimit isP tstDiv tdLoop r22,0 ; derive the test divide limit ; save the test divide limit ; start the test divide number from 2 ; divide the number by tstDiv ; is the remainder 0? ; have we tested all numbers up to tLimit? ; if yes, then the number is a prime ; test divide the next higher number r22,1 "div16U.asm" "SqRoot16.asm" ; insert the subroutine that performs 16-bit division ; insert the subroutine that finds the square root of 16-bit ; unsigned integer //End of program ▲ 5.7 Subroutines with Local Variables in Stack Only subroutines that require many local variables need to utilize the stack to assign local variables. Subroutines that deal with multiple large numbers simultaneously (say, 32-bit numbers) are in this category and may take advantage of the stack to meet the need of computation. The two examples provided in this section do not need to assign local variables to the stack. They are written to demonstrate how to assign local variables in the stack and how to access them during the course of subroutine execution. 5.7.1 Subroutine to Convert a BCD String to a Binary Number Unlike numeric data, text data are encoded in ASCII code. Text data may also represent numbers. For example, the ASCII string 32333435363716 represents the decimal value 234567. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 5.7 ■ Subroutines with Local Variables in Stack 129 In order to allow the MCU to manipulate text data that represent numeric values, we need to convert them into binary values. The subroutine that performs the conversion also needs to perform error checking to make sure that the text data contains no invalid characters. The subroutine should use a flag to indicate whether the return value is valid or invalid. To get an idea how to convert a BCD string into binary value, let’s use a two-digit decimal value 36 as an example. The value of 36 is encoded as a two-byte ASCII string 0x3336. The ten’s digit can be extracted by subtracting 0x30 from the first byte of the string, whereas the one’s digit can be extracted by subtracting 0x30 from the second byte of the string as follows: Ten’s digit 5 0x33 2 0x30 5 3 One’s digit 5 0x36 2 0x30 5 6 These two bytes can be combined by multiplying the ten’s digit by 10 and then adding the ones to the product. The following code converts the ASCII string into binary value: string: ldi ldi lpm subi ldi mul lpm subi add ZL,low(string << 1) ZH,high(string << 1) r20,z1 r20,0x30 r21,10 r20,r21 r20,z r20,0x30 r0,r20 .db "36",0 ; use Z to point to the BCD string ; " ; fetch the first byte ; extract the ten’s digit ; multiply ten’s digit by 10 ; product is in r1:r0 ; fetch second byte ; extract one’s digit ; add to the product of ten’s digit x 10 ; the upper byte (r1) of the product is zero This idea can be extended to handle longer BCD strings. The subroutine that performs the conversion also needs to perform error checking to make sure that the text data contains no invalid characters. The subroutine should use a flag to indicate whether the return value is valid or invalid. Let in_ptr, sign, error, and value represent the pointer to the BCD string, sign flag, error flag, and the number (4 bytes) represented by the BCD string. The algorithm of the subroutine is as follows: Step 1 sign ← 0; error ← 0; value ← 0; Step 2 If the character pointed to by in_ptr is the minus sign, then sign ← 1; in_ptr ← in_ptr 1 1 Step 3 If the character pointed to by in_ptr is the NULL character, then go to step 4. else if the character is not a BCD digit (i.e., m[in_ptr] > 0x39 or m[in_ptr] < 0x30), then: error ← 1; go to step 4; else: value ← value 3 10 1 m[in_ptr] - 0x30; in_ptr ← in_ptr 1 1; go to step 3; Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 130 Chapter 5 ■ Advanced Assembly Programming and Subroutine Calls Step 4 If sign 5 1 and error 5 0, then number ← two’s complement of number; else stop; Example 5.7 Write a subroutine that can convert a BCD ASCII string to a binary number. The ASCII string represents a number in the range of 2231~231 2 1. A pointer to the string is passed to this subroutine in Z. The converted binary number is returned in registers r22~r25. 5 4 3 2 1 Figure 5.7 ■ SP sign t1 t2 t3 t4 r27 r28 r29 retAddr Source: Atmel Corporation, The Atmel AVR Microcontroller ▼ Stack frame for Example 5.7 Solution: In this example, the subroutine allocates local variables in the stack as shown in Figure 5.7. Registers r22~r25 are used to return the value represented by the BCD string. The expression of value 3 10 is evaluated by computing the partial products, aligning them properly, and accumulate them using local variables t4~t1 as illustrated in Figure 5.8. v1~v4 are the lsb~msb of value. Because the size limit of the number represented by the BCD string, the product of v4 and 10 is no larger than one byte. t3 t2 t1 v1 x 10 v2 x 10 v3 x 10 v4 x 10 + msb Isb Source: Atmel Corporation, The Atmel AVR Microcontroller t4 Figure 5.8 ■ Partial product accumulation used to convert from BCD string to binary value Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 5.7 ■ Subroutines with Local Variables in Stack start: againC: BCDStr: 131 .include <ATXMega128A1def.inc> .macro allocStk in r28,CPU_SPL in r29,CPU_SPH sbiw r28,@0 out CPU_SPL,r28 out CPU_SPH,r29 .endmacro .macro deallocStk in r28,CPU_SPL in r29,CPU_SPH adiw r28,@0 out CPU_SPL,r28 out CPU_SPH,r29 .endmacro .cseg .org 0x00 rjmp start .org 0xF6 ldi r20,low(RAMEND) out CPU_SPL,r20 ldi r20,high(RAMEND) out CPU_SPH,r20 ldi r30,low(BCDStr<<1) ldi r31,high(BCDStr<<1) call bcd2bin32 ; convert to binary rjmp againC .db "9367200",0,0 ; ------------------------------------------------------------------------------------------------------------------------------------; The next subroutine converts a BCD string to a 32-bit binary number that the BCD string represents. ; The string is pointed to by the Y register and the converted value is returned in r22~r25 (v1~v4). ; -------------------------------------------------------------------------------------------------------------------------------------- bcd2bin32: .equ .equ .equ .equ .equ .def .def .def .def .def .def push push push allocStk 5 in in sign 5 1 t1 5 2 t2 5 3 t3 5 4 t4 5 5 newC 5 r20 ten 5 r21 v1 5 r22 v2 5 r23 v3 5 r24 v4 5 r25 r29 r28 r27 YL,CPU_SPL YH,CPU_SPH ; distance from top of stack for temporary storage ; " ; " ; " ; used to hold the current character ; used to hold the value of 10 ; registers to hold the value to be returned ; " ; " ; " ; allocate 5 bytes for local variables ; let Y point to the byte above stack top ; " Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 132 Chapter 5 rloop: chkErr: ■ Advanced Assembly Programming and Subroutine Calls clr clr clr clr clr std ldi lpm cpi brne ldi std lpm lpm cpi brne rjmp cpi brlo cpi brsh ldi sub mul std std mul std std mul ldd add std ldd adc std ldd clr adc std mul ldd add std ldd add mov clr ldd v1 v2 v3 v4 r0 Y1sign,r0 ten,10 newC,z newC,'-' rloop newC,1 Y1sign,newC newC,z1 newC,z1 newC,0 chkErr doneBCD2B newC,0x30 illegal newC,0x3A illegal r27,0x30 newC,r27 v1,ten Y1t1,r0 Y1t2,r1 v3,ten Y1t3,r0 Y1t4,r1 v2,ten r2,Y1t2 r0,r2 Y1t2,r0 r2,Y1t3 r2,r1 Y1t3,r2 r2,Y1t4 r1 r2,r1 Y1t4,r2 v4,ten r2,Y1t4 r0,r2 Y1t4,r0 r0,Y1t1 r0,newC v1,r0 r1 r0,Y1t2 ; initialize the value to be returned to 0 ; " ; " ; " ; initialize the sign to positive ; place 10 in register r21 ; set sign to minus ; move pointer to the next character ; read one BCD character from string and move pointer ; reach the end of string? ; convert current character to its decimal value ; performed by generating partial products, ; aligned properly, added together ; " ; " ; " ; " ; " ; " ; " ; " ; " ; " ; " ; " ; " ; " ; " ; the product of 10 and v4 is only one byte ; " ; " ; " ; add the current character value to slots stack t1~t4 ; and then save the result in v1~v4 ; " ; " ; " Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 5.7 ■ 133 Subroutines with Local Variables in Stack adc mov ldd adc mov ldd adc mov rjmp doneBCD2B: ldi rjmp illegal: ldi toRet: ldd sbrs rjmp com com com com movw adiw movw ldi adc adc skip: deallocStk 5 pop pop pop ret // End of program r0,r1 v2,r0 r0,Y1t3 r0,r1 v3,r0 r0,Y1t4 r0,r1 v4,r0 rloopç r26,0 toRet r26,1 r28,Y1sign r28,0 skip v1 v2 v3 v4 r28,v1 r28,1 v1,r28 r28,0 v3,r28 v4,r28 ; ; ; ; ; ; ; ; " " " " " " " " ; set error flag to 0 (no error) ; set error flag to 1 (with error) ; skip if bit 0 (sign bit) of r28 is 1 ; no need to find 2’s complement if positive ; the given number is negative; so find its ; two’s complement ; " ; " ; add 1 to the 1’s complement of v4~v1 ; " ; " ; " ; " ; " r27 r28 r29 ▲ 5.7.2 Bubble Sort Sorting is among the most common ingredients of programming, and many sorting methods are being used. Sorting makes many efficient search methods possible. The bubble sort is a simple, widely known, but inefficient, sorting method. Many other more efficient sorting methods require the use of recursive subroutine calls, which fall outside the scope of this book. The basic idea underlying the bubble sort is to go through the array or file sequentially several times. Each iteration consists of comparing each element in the array or file with its successor (x[i] with x[i11]) and interchanging them if they are not in proper order (either ascending or descending). Consider the following array: 157 13 35 9 98 810 120 54 10 30 Suppose we want to sort this array in ascending order. The following comparisons are made in the first iteration: x[0] with x[1] (157 and 13) interchange x[1] with x[2] (157 with 35) interchange Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 134 Chapter 5 ■ Advanced Assembly Programming and Subroutine Calls x[2] with x[3] (157 with 9) interchange x[3] with x[4] (157 with 98) interchange x[4] with x[5] (157 with 810) no interchange x[5] with x[6] (810 with 120) interchange x[6] with x[7] (810 with 54) interchange x[7] with x[8] (810 with 10) interchange x[8] with x[9] (810 with 30) interchange Thus, after the first iteration, the array is in the order 13 35 9 98 157 120 54 10 30 810 Notice that after this first iteration, the largest element (in this case, 810) is in its proper position within the array. In general, x[n 2 i] is in its proper position after iteration i. The method is called the bubble sort because each number slowly bubbles up to its proper position. After the second iteration the array is in the order 13 9 35 98 120 54 10 30 157 810 Notice that 157 is now in the second-highest position. Because each iteration places a new element into its proper position, an array or a file of n elements requires no more than n – 1 iterations. The complete set of iterations is as follows: Iteration 0 (original array) 1 2 3 4 5 6 7 8 9 157 13 35 9 98 810 120 54 10 30 13 35 9 98 157 120 54 10 30 810 13 9 35 98 120 54 10 30 157 810 9 13 35 98 54 10 30 120 157 810 9 13 35 54 10 30 98 120 157 810 9 13 35 10 30 54 98 120 157 810 9 13 10 30 35 54 98 120 157 810 9 10 13 30 35 54 98 120 157 810 9 10 13 30 35 54 98 120 157 810 9 10 13 30 35 54 98 120 157 810 There are some obvious improvements to the foregoing method: • First, because all elements in positions greater than or equal to n 2 i are already in proper position after iteration i, they need not be considered in succeeding iterations. Thus, in the first iteration, n 2 1, comparisons are made; on the second iteration, n 2 2, comparisons are made; and on the (n 2 1)th iteration, only one comparison is made (between x[0] and x[1]). Therefore, the process is sped up as it proceeds through successive iterations. • Second, although we have shown that n 2 1 iterations are sufficient to sort an array or a file of size n, in the preceding sample array of 10 elements, the array was sorted after the seventh iteration, making the last two iterations unnecessary. To eliminate unnecessary iterations, we must be able to detect the fact that the array is already sorted. An array is sorted if no swaps are made in an iteration. By keeping a record of whether any swaps are made in a given iteration, it can be determined whether any further iteration is necessary. The logic flow of the bubble sort algorithm is illustrated in Figure 5.9. The following example implements the bubble sort as a subroutine: Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 5.7 ■ 135 Subroutines with Local Variables in Stack Start iteration ← N–1 sorted ← 1 inner ← iteration i←0 array[i] > array[i+1]? no yes swap array[i] & array[i+1] sorted ← 0 no inner = 0? yes sorted = 1? no Iteration ← iteration–1 no iteration = 0? yes Stop Figure 5.9 ■ yes Source: Atmel Corporation, The Atmel AVR Microcontroller inner ← inner–1 i←i+1 Logic flow of bubble sort Example 5.8 ▼ Write a subroutine to implement the bubble sort algorithm and a sequence of instructions along with a set of test data for testing this subroutine. Use an array that consists of n 8-bit unsigned integers for testing purposes. Solution: The bubble sort subroutine has several local variables: • • • Sorted: flag to indicate whether the array is in order after an iteration Inner: number of comparisons that remain to be performed in the current iteration Iteration: number of iterations that remain to be performed The stack frame of the bubble sort subroutine is shown in Figure 5.10. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. Chapter 5 ■ Advanced Assembly Programming and Subroutine Calls SP 3 2 1 Figure 5.10 sorted iCnt eCnt r28 r29 ret_addr ■ Source: Atmel Corporation, The Atmel AVR Microcontroller 136 Stack frame for bubble sort subroutine The bubble sort subroutine and its test program are as follows: array: start: cpLoop: .include .equ .equ .macro in in sbiw out out .endmacro .macro in in adiw out out .endmacro .equ .def .dseg .org .byte .cseg .org rjmp .org ldi out ldi out ldi ldi ldi ldi ldi lpm <ATXMega128A1def.inc> SPL 5 CPU_SPL ; commented for Mega devices SPH 5 CPU_SPH ; " allocSt k ; this macro allocate space for local variables r28,SPL r29,SPH r28,@0 SPL,r28 SPH,r29 deallocStk r28,SPL r29,SPH r28,@0 SPL,r28 SPH,r29 ; this macro deallocates space used by local variables NN 5 30 lpcnt 5 r21 0x2000 40 0x00 start 0xF6 r20,low(RAMEND) SPL,r20 r20,high(RAMEND) SPH,r20 ZL,low(xarr<<1) ZH,high(xarr<<1) XL,low(array) XH,high(array) lpcnt,NN r0,z1 ; initialize stack pointer ; " ; " ; " ; set up pointer to the array in program memory ; " ; set up pointer to the buffer array in data memory ; " ; set up loop count ; copy the array from program memory to data memory Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 5.7 ■ 137 Subroutines with Local Variables in Stack again: st dec brne ldi ldi ldi call nop rjmp x1,r0 lpcnt cpLoop r16,low(array) r17,high(array) r18,NN bubble ; so that it can be sorted ; " ; " ; pass array pointer ; " ; pass array count again ; -----------------------------------------------------------------------------------------------------------------; The next subroutine uses bubble sort algorithm to sort an array in data memory. ; The array count is passed in r18 and the pointer to the array is passed in r16~r17. ; All array elements are nonnegative. ; ------------------------------------------------------------------------------------------------------------------- bubble: eLoop: iloop: next: .equ .equ .equ .equ push push allocStk in in dec std ldd std movw ldi std ld ldd cp brlo st std ldi std adiw ldd dec std brne ldd cpi breq ldd dec eCnt 5 3 iCnt 5 2 sorted 5 1 true 5 1 YH YL 3 YL,SPL YH,SPH r18 Y1eCnt,r18 r18,Y1eCnt Y1iCnt,r18 ZL,r16 r20,1 Y1sorted,r20 r8,z r9,z11 r8,r9 next z,r9 z11,r8 r20,0 Y1sorted,r20 ZL,1 r20,Y1iCnt r20 Y1iCnt,r20 iloop r20,Y1sorted r20,true done r20,Y1eCnt r20 ; iteration count offset from TOS ; inner count offset from TOS ; array is already sorted flag offset from TOS ; allocate 3 bytes for local variables ; set Y point to the byte above the top of stack ; " ; initialize iteration count to NN - 1 ; " ; set up inner loop count ; " ; place array base address in Z ; set flag to indicate array is sorted ; " ; get array[i] ; get array[i11] ; compare array[i] with array[i11] ; swap array[i] with array[i11] ; " ; indicate array not sorted ; " ; increment array pointer by 1 ; decrement inner loop count ; " ; " ; continue if inner loop count is not 0 ; check array sorted flag ; " ; stop if sorted flag is true (1) ; decrement iteration loop count ; " Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 138 Chapter 5 ■ Advanced Assembly Programming and Subroutine Calls std brne done: deallocStk 3 pop pop ret xarr: .db .db .db // End of program Y1eCnt,r20 eLoop ; " YL YH 12,91,20,33,45,72,24,19,17,101 11,92,21,34,44,71,25,18,16,131 41,43,49,50,99,79,89,98,37,59 ▲ 5.8 Summary Often, the same sequence of instructions has to be executed in several places in a program. The programmer can place this sequence of instructions in a macro or a subroutine. Both the subroutine and macro can be invoked in many places within a program. The differences between a macro and a subroutine are as follows: Similarities • Both the macro and subroutine can be invoked from many different places within a program. • • Parameters may be passed when a macro or subroutine is invoked. • Both the macro and subroutine reduce the amount of typing necessary when they are invoked more than once in a program. Both create reusable code. A macro can be defined once and included in many programs that can use it; so can a subroutine. Differences: • A macro is invoked by entering the macro name and parameters, whereas a subroutine is invoked by executing a call instruction. • A macro call does not need the saving and restoring of return address and hence runs faster than its equivalent in the subroutine format. • Each time a macro is invoked, a copy of the instructions contained in the macro definition is inserted into the program. However, no such code duplication is made in a subroutine call. The subroutine mechanism makes the “top-down design with hierarchical refinement” methodology easy to implement. In addition to creating reusable code, the subroutine mechanism enables the user to breakdown a difficult problem into smaller and manageable program units. A complicated problem then becomes easier to solve. To implement the subroutine mechanism, the AVR provides subroutine-call instructions rcall, icall, eicall, and call, and return instruction ret. The subroutine mechanism also requires the return address to be saved and restored. This is achieved by providing the stack data structure. The AVR MCU allows the user to implement a stack using the on-chip data memory. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 5.9 ■ Exercises 139 The 16-bit stack pointer (SP) points to the byte above the top byte of this stack. The user can push data into the stack and pop data out of the stack. When making subroutine calls, the caller may need to pass certain values required by the subroutine for performing the intended operation. After the computation is completed, the subroutine returns the result back to the caller. Incoming parameters may be passed in registers, data memory (global memory), or the stack. The computation result may be returned in registers, data memory (global memory), or the stack. The subroutine also may need temporary variables for computation purpose. These temporary variables are called local variables and should be allocated in the stack to avoid interference among subroutines. However, for the following two reasons the programmer should assign local variables to registers as much as possible: • • The AVR instruction set can perform arithmetic and logic operations only on registers. The AVR has many CPU registers to be assigned to local variables. The programmer should follow certain rules in using registers to pass parameters to subroutine, assigning local variables to registers, and using registers to return computation results. This text follows the register usage recommendation specified in Table 5.1. The AVR provides only 8-bit by 8-bit multiplication instructions. However, the programmer can write subroutines to implement multiprecision multiplication and division operations, as demonstrated in this chapter. 5.9 Exercises E5.1 Write a subroutine that can create a time delay that is a multiple of 1 ms. The multiple is passed in register r16, assuming that the CPU clock is 16 MHz. E5.2 Write a subroutine that can create a time delay that is a multiple of 10 ms. The multiple is passed in r16, assuming that the CPU clock is 16 MHz. E5.3 Write a subroutine that can divide a 16-bit signed integer into another 16-bit signed integer. The dividend and divisor are passed in registers r16~r17 and r18~r19, respectively. The quotient and remainder are returned in r24~r25 and r22~r23, respectively. E5.4 Write a subroutine that can divide a 32-bit unsigned integer into another 32-bit unsigned integer. The dividend is passed in registers r16~r19, and the divisor is passed in the stack. The quotient is returned in registers r22~r25, and the remainder is returned in registers r16~r19. E5.5 Write a subroutine that can divide a 32-bit signed integer into another 32-bit signed integer. The dividend is passed in registers r16~r19, and the divisor is passed in the stack. The quotient is returned in registers r22~r25, and the remainder is returned in registers r16~r19. E5.6 Write a subroutine to find the number of elements in an array that are a multiple of 5. The pointer to the array is passed in r30~r31, whereas the array count is passed in r16. The array has no more than 255 16-bit unsigned integers. The subroutine returns the result in register r22. E5.7 Write a subroutine to find the greatest common divisor of two 16-bit unsigned integers. Two integers are passed in registers r16~r17 and r18~r19, respectively. The gcd is returned in registers r22~r23. E5.8 Write a subroutine to test whether a four-digit decimal number has the following property: The square of the sum of the upper half and the lower half of the given number is equal to the original number. The number to be tested is passed in r16~r17, and the result (0 or 1) is returned in register r22. E5.9 Write a program to find out all the four-digit decimal numbers (1000 to 9999) that have the property specified in problem E5.8. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 140 Chapter 5 ■ Advanced Assembly Programming and Subroutine Calls E5.10 Write a subroutine to test whether a four-digit decimal number has the following property: The sum of the square of the upper half and the square of the lower half of the given number is equal to the original number. The number to be tested is passed in r16~r17, and the result (0 or 1) is returned in register r22. E5.11 Write a program to find out all the four-digit decimal numbers (1000 to 9999) that have the property specified in problem E5.10. E5.12 Write a subroutine to test whether a 3-digit decimal integer has the property: Let d2, d1, and d0 be the hundreds, tens, and ones digit. d23 1 d13 1 d03 5 original number. Write a program to call this function and find out all the 3-digit numbers that have this property. E5.13 Write a subroutine to implement selection sort and write a main program to test it. The selection sort method works like this if the array is to be sorted in descending order: You are given an array of 8-bit integer values. Search through the array, find the largest value, and exchange it with the value stored in the first array location. Next, find the second largest value in the array, and exchange it with the value stored in second array location. Repeat the same process until the end of the array is reached. Assume that the array is stored in data memory. Write an instruction sequence to test this subroutine. This instruction sequence should copy a test array in program memory to the data memory and then call the subroutine to sort the array. The array count and starting address are passed in registers r16 and r30~r31, respectively. E5.14 Write a program to call the prime16 subroutine in Example 5.6 to find out all the prime numbers between 8000 and 9999, and store them in data memory. E5.15 Write a subroutine to convert an 8-bit binary number to two hexadecimal digits, with each digit encoded in ASCII code. Also write a main program to test this subroutine. 5.10 Lab Assignments L5.1 BINARY SEARCH SUBROUTINE Searching is a frequently performed operation. When an array is not sorted, the search program may need to compare every element of the array. When an array or a file is sorted, searching can be performed much faster. Several efficient searching algorithms have been invented for a sorted array. The binary search algorithm is one of the most efficient search algorithms in use. Suppose the sorted array (in ascending order) has N elements and is stored in memory locations starting at the label arr. Let max and min represent the highest and lowest range of array indices to be searched, and the variable mean represent the average of max and min. The idea of a binary search algorithm is to divide the sorted array into three parts. • • • The upper half: the portion of the array with indices ranging from mean 1 1 to max. The middle element: the element with index equal to mean. The lower half: the portion of the array with indices ranging from min to mean 2 1. The binary search algorithm compares the key with the middle element and takes one of the following actions on the basis of the comparison result: • • If the key equals the middle element, then stop. • If the key is smaller than the middle element, then the key can be found only in the lower half of the array. The search is continued in the lower half. If the key is larger than the middle element, then the key can be found only in the upper half of the array. The search is continued in the upper half. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 5.10 ■ Lab Assignments 141 Write a subroutine to implement the binary search algorithm and write a test program (including a sorted array as test data) to test the subroutine. The search result is returned in register r22. When the key is found, a 1 is returned. Otherwise, a 0 is returned. L5.2 BINARY TO HEX ASCII CONVERSION Write a subroutine to convert a 16-bit binary number into four hexadecimal digits. Each of these hexadecimal digits is represented in the ASCII code. The 16-bit number to be converted are passed in r17~r16 (r17 holds the upper 8 bits), and the result is returned in r25~r22 (from most significant digit to least significant digit). Also write a main program to test this subroutine. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 6 C Language Programming 6.1 Objectives After completing this chapter, you will be able to • Explain the overall structure of a C language program. • Use appropriate operators to perform desired operations in the C language. • Understand the basic data types and expressions of the C language. • Write program loops in the C language. • Write functions and make function calls in the C language. • Use arrays and pointers for data manipulation. • Perform basic I/O operations in the C language. • Use C statements to manipulate bit and bit fields of a variable. • Learn the naming convention of AVR registers and bits. • Use the AVR Studio IDE to enter, compile, and debug C programs. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 144 Chapter 6 ■ C Language Programming 6.2 Introduction to C The purpose of this chapter is to provide a review to the C language and also an introduction to using the C language to program the AVR peripheral functions. To benefit from this chapter readers are expected to have taken a course in C or another high-level language before reading it. This chapter provides a summary of the C language constructs that are commonly used in embedded system programming. In addition to summarizing the C language features, this chapter also illustrates the naming convention for registers and bits, the data structure used in describing the AVR peripheral registers, bit masks, bit group masks, and so on. A tutorial on using the AVR Studio IDE in developing and debugging C programs is also provided. The C language is quickly replacing the assembly language in every embedded application because it has several advantages over the assembly language. The most important one is that it allows the user to work on program logic at a level much higher than that of the assembly language, and thus programming productivity is greatly improved. A C program, whatever its size, consists of functions and variables. A function contains statements that specify the operations to be performed. The types of statements in a function could be a declaration, assignment, function call, control, or null. A variable stores a value to be used during the computation. The main() function is required in every C program and is the one to which control is passed when the program is executed. A simple C program is as follows. (1) #include ,avr\io.h. (2) void main (void) (3) { (4) char ax, bx, cx; (5) DDRA 5 0xFF; (6) ax 5 6; (7) bx 5 9; (8) cx 5 ax 1 bx; (9) PORTA 5 cx; (10) while(1); (11) } /* declare three variables */ // configure PORTA for output // assign 6 to variable ax // assign 9 to variable bx // assign the sum of ax and bx to cx // output cx to PORTA // stay in an infinite loop The first line of the program causes the specified file to be included in this program. This line appears at the beginning of every C program for the Atmel AVR MCU. When using the AVR Studio IDE to create a project, the user must specify the target MCU. After that, the header file that contains the definitions of all special function registers (peripheral control, data, and status registers) and bits will be inserted into the program so that the user can use symbolic names to refer to them. The second line main() is where program execution begins. The opening brace on the third line marks the start of the main() function’s code. Every C program must have one, and only one, main() function. Program execution is also ended with the main() function. The fourth line declares three variables (ax, bx, and cx) of character type. In C language, a variable must be declared before it can be used. The fifth line assigns 0xFF to the DDRA register that configures the PORTA pins for output. The sixth and seventh lines assign a value to a variable. The eighth line adds ax and bx together and assigns the sum to the variable cx. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 6.3 ■ Types, Operators, and Expressions 145 The ninth line assigns the value of cx to PORTA pins which might be driving LEDs or seven-segment displays, and so on. The tenth line is an infinite loop that causes the processor to stay at this statement forever. The closing brace in the last line ends the main() function. Comments can be added to the C statements to explain the purpose or the operations performed by the statements. A single line comment may start with /* (line 4) or // (line 5 to 10) and is terminated by */ (line 4) or a space character (line 5 to 10). A multiple line comment can only be started with the /* character pair and terminated with the */ character pair. 6.3 Types, Operators, and Expressions Variables and constants are the basic objects manipulated in a program. Variables must be declared before they can be used. A variable declaration must include the name and type of the variable and may optionally provide its initial value. A variable name may start with a letter (A through Z or a through z) or an underscore character followed by zero or more letters, digits, or underscore characters. Variable names cannot contain arithmetic signs, dots, apostrophes, C keywords, or special symbols such as @, #, ?, and so on. Adding the underscore character (_) may sometimes improve the readability of long variables. Don’t begin variable names with an underscore, however, because library routines often use such names. C language is case sensitive. Uppercase and lowercase letters are distinct. 6.3.1 Data Types There are only a few basic data types in C: void, char, int, float, and double. A variable of type void represents nothing. The type void is used most commonly with functions, which can indicate that the function does not return any value or does not have incoming parameters. A variable of type char can hold a single byte of data (signed). A variable of type int is an (signed) integer, which is normally the natural size (word length) for a particular machine. The type float refers to a 32-bit, single-precision, floating-point number. The type double represents a 64-bit, double-precision, floating-point number. In addition, there are a number of qualifiers that can be applied to these basic types. Short and long apply to integers. These two qualifiers will modify the lengths of integers. An integer variable is 16-bit by default for many C compilers for 8- or 16-bit microcontrollers. However, the int type is 32 bit for 32-bit or higher microcontrollers. The modifier short does not change the length of an integer for these compilers. The modifier long doubles a 16-bit integer to 32 bits. The keyword unsigned should be used if the variables are never negative, to improve the efficiency of the generated code. 6.3.2 Variable Declarations All variables must be declared before their use. A declaration specifies a type and contains a list of one or more variables of that type, as in int char i, j, k; cx, cy; A variable may also be initialized when it is declared, as in int i 5 0; char echo 5 ‘y’; // the ASCII code of letter y is assigned to variable echo. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 146 Chapter 6 ■ C Language Programming 6.3.3 Constants There are four kinds of constants: characters, integers, floating-point numbers, and strings. A character constant is an integer written as one character within single quotes, such as ‘x.’ A character constant is represented by the ASCII code of the character. A string constant is a sequence of zero or more characters surrounded by double quotes, as in “XMega128A1 is a microcontroller made by Atmel.” or “” /* an empty string */ Each individual character in the string is represented by its ASCII code. An integer constant such as 3241 is an int. A long constant is written with a terminal l (el) or L, as in 44332211L. The constant characters listed in Table 6.1 are predefined in C language (can be embedded in a string): Character Meaning Character Meaning \a Alert (bell) character \\ Backspace \b Backspace \? Question mark \f Formfeed \’ Single quote \n Newline \” Double quote \r Carriage return \ooo Octal number \t Horizontal tab \xhh Hexadecimal number \v Vertical tab Source: Atmel Corporation, The Atmel AVR Microcontroller Table 6.1 ■ Escaped characters in C As in assembly language, a number in C can be specified in different bases. The method to specify the base of a number is to add a prefix to the number. The prefixes for different bases are listed in Table 6.2. Base Prefix Decimal None Binary Example 1357 0b 0b10010010 Octal 0 04523 Hexadecimal 0x 0x345 Source: Atmel Corporation, The Atmel AVR Microcontroller Table 6.2 ■ Number base prefixes 6.3.4 Arithmetic Operators The arithmetic operators supported in C are listed in Table 6.3. The expression a%b produces the remainder when a is divided by b. The % operator cannot be applied to a float or double. The / operator performs a division and truncates the quotient to an integer when both Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 6.3 ■ 147 Types, Operators, and Expressions Symbol Operation Example 1 Add and unary plus 3 1 5; 14 2 Subtract and unary minus 60 2 13; 210 * Multiply a*b / Divide 100 / 13 Modulus 300 % 19 11 Increment 11y; y11 22 Decrement 22ptr; ptr22 % Source: Atmel Corporation, The Atmel AVR Microcontroller Table 6.3 ■ Arithmetic operators in C operands are integers. The 11 operator adds 1 to the operand, and the 22 operator subtracts 1 from the operand. Depending on whether the 11 (or 22) operator appears before or after the variable it applies to, the increment (decrement) operation is performed before or after it is used in the expression. For example, in the next statement xx 5 11yy; the variable yy is incremented before it is assigned to xx. In the expression abc 5 3 1 yy11; the sum of 3 and the variable yy is assigned to the variable abc, and then yy is incremented by 1. Example 6.1 ▼ What value will be assigned to ax for the following statement? ax 5 230 / 11; Solution: The integral part of 230/11 is 11. Therefore, ax receives 11 after the previous statement is executed. ▲ Example 6.2 ▼ What value will be assigned to bx for the following statement? bx 5 435 % 25; Solution: The remainder of 435/25 is 10. Therefore, bx receives 10 after the previous statement is executed. ▲ Example 6.3 ▼ Assume that ak is a four-digit (decimal) integer. Write a few C statements to separate ak into two parts, and assign the upper two digits to the variable ax and the lower two digits to the variable bx. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 148 Chapter 6 ■ C Language Programming Solution: A four-digit value d3d2d1d0 can be written as d3d2d1d0 5 d3d2 3 100 1 d1d0 where d 3, d 2, d 1, and d 0 are the thousands, hundreds, tens, and ones digit of the number, respectively. Therefore, we can divide a four-digit integer by dividing 100 into that number. The following two statements perform the desired operation: ax 5 ak /100; bx 5 ak % 100; ▲ 6.3.5 Bitwise Operators C provides six operators (listed in Table 6.4) for bit manipulations; these operators may be applied only to integral operands, which are char, short, int, and long, whether they are signed or unsigned. Symbol Operation Example & AND ax & bx | OR ax | 0x0F ^ XOR ax ^ 0xAA | NOT |ax .. Right shift ax .. 2 ,, Left shift bx ,, 4 Source: Atmel Corporation, The Atmel AVR Microcontroller Table 6.4 ■ Bitwise logic operators in C The & operator is often used to clear one or more bits to zero. For example, the statement P1 5 P1 & 0xBD; /* variable P1 is 8 bits */ clears bits 6 and 1 of P1 to 0. The | operator is often used to set one or more bits to 1. For example, the statement P2 5 P2 | 0x40; /* variable P2 is 8 bits */ sets the bit 6 of P2 to 1. The XOR operator can be used to toggle a bit. For example, the statement abc 5 abc ^ 0xF0; /* abc is of type char */ toggles the upper four bits of the variable abc. The .. operator shifts the involved operand to the right for the specified number of places. For example, xyz 5 abc .. 3; shifts the variable abc to the right three places and assigns the result to the variable xyz. The ,, operator shifts the involved operand to the left for the specified number of places. For example, xyz 5 xyz ,, 4; shifts the variable xyz to the left four places. The assignment operator 5 is often combined with the operator when the destination operand is the same as one of the source operand. For example, PTP 5 PTP & 0xBD; Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 6.3 ■ 149 Types, Operators, and Expressions can be rewritten as PTP &5 0xBD; The statement P2 5 P2 | 0x40; can be rewritten as P2 |5 0x40; 6.3.6 Relational and Logical Operators Relational operators are used in expressions to compare the values of two operands. If the result of the comparison is true, then the value of the expression is 1. Otherwise, the value of the expression is zero. The relational and logical operators are listed in Table 6.5. Symbol Operation equal to 55 Example ax 55 bx !5 not equal to ax !5 10 . greater than ax .60 greater than or equal to ax .5 20 less than ax ,40 less than or equal to ax ,5 80 .5 , ,5 && and (ax . 3) && (bx , 10) || or (ax 55 0) || (bx !5 3) ! not (one’s complement) !ax Source: Atmel Corporation, The Atmel AVR Microcontroller Table 6.5 ■ Relational and logical operators in C Some examples of relational and logical operators are if (!(PORTD & 0x80)) statement1; if (i . 0 && i , 10) statement2; if (a1 55 a2) statement3; /* if bit 7 is 0, then execute statement1 */ /* if 0 , i , 10 then execute statement2 */ /* if a1 equals a2 then execute statement3 */ 6.3.7 Precedence of Operators Precedence refers to the order in which operators are processed. The C language maintains a precedence for all operators, as shown in Table 6.6. Operators at the same level are evaluated from left to right. A few examples that illustrate the precedence of operators are listed in Table 6.7. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 150 Chapter 6 ■ C Language Programming Precedence Operator Highest Lowest Associativity () [] S . left to right ! | 11 22 2 * & (type) sizeof right to left */% left to right 12 left to right ,, .. left to right , ,5 . .5 left to right 55 !5 left to right & left to right ^ left to right | left to right && left to right || left to right ?: right to left 5 15 25 *5 /5 %5 &5 ^5 |5 ,,5 ..5 right to left ‘ left to right Source: Atmel Corporation, The Atmel AVR Microcontroller Table 6.6 ■ Table of precedence of operators Expression Result 15 2 2 * 7 1 (13 2 4) * 5 45 (0x20 | 0x01) !50x01 1 Note * has higher precedence than 2 0x20 | 0x01 !50x01 0x20 !5 has higher precedence than | 1 ,, 3 1 1 16 1 has higher precedence than ,, (1 ,, 3) 1 1 9 Source: Atmel Corporation, The Atmel AVR Microcontroller Table 6.7 ■ Examples of operator precedence 6.4 Control Flow The control-flow statements specify the order in which computations are performed. In the C language, the semicolon is a statement terminator. Braces, { and }, are used to group declarations and statements together into a compound statement or block, so that they are syntactically equivalent to a single statement. 6.4.1 If Statement The if statement is a conditional statement. The statement associated with the if statement is executed based upon the outcome of a condition. If the condition evaluates to nonzero, the statement is executed. Otherwise, it is skipped. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 6.4 ■ Control Flow 151 The syntax of the if statement is if (expression) statement; An example of an if-statement is if (a . b) sum 15 2; The value of sum will be incremented by 2 if the variable a is greater than the variable b. 6.4.2 If-Else Statement The if-else statement handles conditions where a program requires one statement to be executed if a condition is nonzero and a different statement if the condition is zero. The syntax of an if-else statement is if (expression) statement1 else statement2 The expression is evaluated. If it is true (nonzero), statement1 is executed. If it is false, statement2 is executed. Here is an example of the if-else statement: if (a !5 0) r 5 b; else r 5 c; The if-else statement can be replaced by the ?: operator. The statement r 5 (a !5 0)? b : c; is equivalent to the previous if-else statement. 6.4.3 Multiway Conditional Statement A multiway decision can be expressed as a cascaded series of if-else statements. Such a series looks like if (expression1) statement1 else if (expression2) statement2 else if (expression3) statement3 … else statementn An example of a three-way decision is if (abc . 0) return 5; else if (abc 55 0) return 0; else return 25; Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 152 Chapter 6 ■ C Language Programming 6.4.4 Switch Statement The switch statement is a multiway decision based on the value of a control expression. The syntax of the switch statement is switch (expression) { case const_expr1: statement1; break; case const_expr2: statement2; break; … default: statementn; } As an example, consider the following program fragment: switch (level) { case 1: pay 5 10; break; case 2: pay 5 20; break; case 3: pay 5 30; break; case 4: pay 5 40; break; case 5: pay 5 50; break; default: pay 5 0; } The variable pay receives a value that is equal to level 3 10. The keyword break forces the program flow to drop out of the switch statement so that only the statements under the corresponding case-labels are executed. If any break statement is missing, then all of the statements from that case-label until the next break statement within the same switch statement will be executed. 6.4.5 For-Loop Statement The syntax of a for-loop statement is for (expr1; expr2; expr3) statement; Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 6.4 ■ Control Flow 153 where expr1 and expr3 are assignments or function calls, and expr2 is a relational expression. For example, the following for loop computes the sum of the squares of integers from 1 to 9. sum 5 0; for (i 5 1; i , 10; i11) sum 5 sum 1 i * i; The following for loop prints out the first 10 odd integers. for (i 5 1; i , 20; i11) if (i % 2) printf(“%d “, i); 6.4.6 While Statement When an expression is nonzero, the while loop repeats a statement or block of code. The value of the expression is checked prior to each execution of the statement. The syntax of a while statement is while (expression) statement; The expression is evaluated. If it is nonzero (true), the statement is executed and expression is reevaluated. This cycle continues until the expression becomes zero (false), at which point execution resumes after the statement. The statement may be a NULL statement. A NULL statement does nothing and is represented by a semicolon. Consider the program fragment: intCnt 5 5; while (intCnt); The CPU will stay in the while-loop until the variable intCnt becomes zero. In microcontroller applications, the decrement of intCnt is often triggered by external events, such as interrupts. 6.4.7 Do-While Statement The while and for loops test the termination condition at the beginning of the statement. By contrast, the do-while statement tests the termination condition at the end of the statement; the body of the statement is executed at least once. The syntax of the statement is do statement while (expression); The following do-while statement initializes the array elements to its position in the array. int k 5 0; do array[k] 5 k; while (k , 20); 6.4.8 Goto Statement Execution of a goto statement causes control to be transferred directly to the labeled statement, which must be located in the same function as the goto statement. The use of the goto statement interrupts the normal sequential flow of a program and thus makes it harder to follow and decipher. For this reason, the use of goto is not considered good programming style, so it is recommended that you do not use it in your program. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 154 Chapter 6 ■ C Language Programming The syntax of the goto statement is goto label An example of the use of a goto statement is if (x . 100) goto fatal_error; … fatal_error: printf(“Variable x is out of bound!\n); 6.5 Input and Output Input and output facilities are not part of the C language itself. However, input and output are very important in applications. The ANSI standard defines a set of library functions that must be included so that they can exist in a compatible form on any system where C exists. Some of the functions deal with file input and output. Others deal with text input and output. In this section, we will look at four input and output functions. 1. int getchar ( ). This function returns a character when it is called. The following program fragment returns a character and assigns it to the variable xch. char xch; xch 5 getchar (); 2. int putchar (int). This function outputs a character on the standard output device. The following statement outputs the letter a from the standard output device. putchar (‘a’); 3. int puts (const char *s). This function outputs the string pointed to by s on the standard output device. The following statement outputs the string “Learning microcontroller is fun!” from the standard output device. puts (“Learning microcontroller is fun!\n”); 4. int printf (formatting string, arg1, arg2, …, argn). This function converts, formats, and prints its arguments on the standard output under the control of a formatting string. arg1, arg2, …, argn are arguments that represent the individual output data items. The arguments can be written as constants, single variable or array names, or more complex expressions. The formatting string is composed of individual groups of characters, with one character group associated with each output data item. The character group corresponding to a data item must start with %. In its simplest form, an individual character group consists of a percent sign followed by a conversion character, indicating the type of the corresponding data item. Multiple character groups can be contiguous or separated by other characters, including white-space characters. These “other” characters are simply transferred directly to the output device where they are displayed. A subset of the more frequently used conversion characters is listed in Table 6.8. Between the % character and the conversion character there may be, in order: • • A minus sign, which specifies left adjustment of the converted argument. • A period, which separates the field width from precision. A number that specifies the minimum field width. The converted argument will be printed in a field at least this wide. If necessary, it will be padded on the left (or right, if left adjustment is called for) to make up the field width. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 6.6 ■ 155 Functions and Program Structure • A number for the precision, which specifies the maximum number of characters to be printed from a string, the number of digits after the decimal point of a floatingpoint value, or the minimum number of digits for an integer. • An h if the integer is to be printed as short, or l (letter el) if as long. Several valid printf calls are given next. printf (“this is a challenging course! \n”); printf (“%d %d %d”, x1, x2, x3); printf (“Today’s temperature is %4.1d \n”, temp); Conversion character // outputs only a string /* outputs variables x1, x2, x3 using a minimal number of digits with one space separating each value */ /* display the string Today’s temperature is followed by the value of temp. Display one fractional digit and use at least four digits for the value. */ Meaning c Data item is displayed as a single character . d Data item is displayed as a signed decimal number . e Data item is displayed as a floating-point value with an exponent. f Data item is displayed as a floating-point value without an exponent. g Data item is displayed as a floating-point value using either e-type or f-type conversion, depending on value; trailing zeros, trailing decimal point will not be displayed. i Data item is displayed as a signed decimal integer. o Data item is displayed as an octal integer ,without a leading zero. s Data item is displayed as a string. u Data item is displayed as an unsigned decimal integer. x Data item is displayed as a hexadecimal integer, without the leading 0x. Source: Atmel Corporation, The Atmel AVR Microcontroller Table 6.8 ■ Commonly used conversion characters for data output By default, functions putchar, puts, and printf output data to the computer monitor via the UART PORT, whereas the getchar function receives data entered from the computer keyboard via the UART PORT. The UART PORT is discussed in Chapter 13. Most embedded systems are not connected to the PC, and hence users cannot use these functions to perform I/O. However, these functions can be very helpful during the program development stage because most developers are using PC as a development platform. 6.6 Functions and Program Structure Every C program consists of one or more functions. If a program consists of multiple functions, their definitions cannot be embedded within another. The same function can be called from several different places within a program. Generally, a function will process information passed to it from the calling portion of the program and return a single value. Information is passed to the function via special identifiers called arguments (also called parameters) and returned via the return statement. Some functions, however, accept information but do not return anything (for example, the library function printf). There are also functions that do not Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 156 Chapter 6 ■ C Language Programming receive or return any values. Their purpose is to modularize the program, that is, make it more readable and easier to develop. The syntax of a function definition is return_type function_name (declarations of arguments) { declarations and statements } The declaration of an argument in the function definition consists of two parts: the type and the name of the variable. The return type of a function is void if it does not return any value to the caller. An example of a function that converts a lowercase letter to an uppercase letter is char lower2upper (char cx) { if (cx .5 ‘a’ && cx ,5 ‘z’) return (cx 2 (‘a’ 2 ‘A’)); else return cx; } A character is represented by its ASCII code. A letter is in lowercase if its ASCII code is between 97 (0x61) and 122 (0x7A). To convert a letter from lowercase to uppercase, subtract its ASCII code by the difference of the ASCII codes of letters a and A. Example 6.4 ▼ Write a function to find the closest integral square root of a 16-bit unsigned integer. Solution: The successive approximation method is one of the methods for finding the closest integral square root of an integer. This method is also used in performing analog-to-digital conversion. The logic flow of this method is illustrated in Figure 5.5. The SAR register is used to accumulate the result. The square root found in Figure 5.5 tends to be smaller than the true square root. The integer closest to the true square root could be [SAR] (the contents of the SAR register) or [SAR] 1 1. To find the closest approximation to the true square root, we need to compare the values of (y 2 [SAR]2) and (([SAR] 1 1)2 2 y), where y is the integer for which the square root is to be found. The C function that finds the closest integral square root of a 16-bit integer is as follows: unsigned int sqroot (unsigned int y) { unsigned int i, k, mask, test; k 5 0; mask 5 0x80; for (i 5 0; i , 8; i11) { test 5 k | mask; if ((test * test) ,5 y) k 5 test; mask 5 mask .. 1; } if ((y 2 k * k) , ((k11) * (k11) 2 y)) return k; else return (k11); } ▲ Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 6.6 ■ Functions and Program Structure 157 6.6.1 Function Prototype A function cannot be called before it has been defined. This dilemma is solved by using the function prototype statement. The syntax for a function prototype statement is as follows. return_type function_name (declarations of arguments); For example, the statement char test_prime (int a); before main() is a function prototype statement. This statement indicates that the function test_prime has an integer incoming argument and returns a signed character value to the caller. 6.6.2 Writing a C Program with Multiple Functions To call a function, simply write the name of the function and replace the argument declarations by actual arguments or values and terminate it with a semicolon. Example 6.5 ▼ Write a program to find out the number of prime numbers between 100 and 1000. Solution: The most efficient method to find out whether a number is prime is to divide the given number by all the prime numbers between 2 and its square root. If none of them can divide the given number, then it is a prime number. However, we don’t have all the prime numbers at hand; we will be satisfied by dividing the given number by all the numbers from 2 to its square root. #include ,avr\io.h. char test_prime (unsigned int k); unsigned int sqroot (unsigned int y); void main (void) { unsigned int i, prime_count; prime_count 5 0; for (i 5 100; i ,5 1000; i11) { if (test_prime(i)) prime_count 11; } while(1); } // ---------------------------------------------------------------------------------------------------------------------------// The following function tests if k is a prime. It returns a 1 if it is; otherwise, it returns a 0 // ---------------------------------------------------------------------------------------------------------------------------char test_prime (unsigned int k) { unsigned int i; char limit; if (k 5 5 0 || k 5 5 1) return 0; // 0 and 1 are not prime numbers else if (k 5 5 2 || k 5 5 3) // 2 and 3 are prime numbers return 1; limit 5 sqroot(k); // use the square root as prime test limit Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 158 Chapter 6 ■ C Language Programming for (i 5 2; i ,5 limit; i11) if ((k % i) 5 5 0) return 0; // divisible? return 1; } // ---------------------------------------------------------------------------------------------------------------------------// include sqroot (unsigned int y) here // ---------------------------------------------------------------------------------------------------------------------------- ▲ 6.7 Pointers, Arrays, Structures, Unions, and Type Definition A pointer holds the address of a variable. It is closely related to arrays, structures, and unions. An array is a collection of data of the same type. A structure is a collection of data that may have the same or different data types. A union is a variable that may hold (at different times) objects of different types and sizes. A pointer can be used to access an array, a structure, and a union. 6.7.1 Pointers and Addresses A pointer is a variable that holds the address of another variable. Pointers are used frequently in C, as they have a number of useful applications. For example, pointers can be used to pass information back and forth between a function and its reference (calling) point. In particular, pointers provide a way to return multiple data items from a function via function arguments. Pointers also permit references to other functions to be specified as arguments to a given function. This has the effect of passing functions as arguments to the given function. Pointers are also closely associated with arrays and therefore provide an alternative way to access individual array elements. The syntax for declaring a pointer type is type_name *pointer_name; For example, int *ax; declares that the variable ax is a pointer to an integer, and char *cp; declares that the variable cp is a pointer to a character. To access the value pointed to by a pointer, use the dereferencing operator *. For example, int a, *b; … a 5 *b; // b is a pointer to int type assigns the value pointed to by b to variable a. We can assign the address of a variable to a pointer by using the unary operator &. The following example shows how to declare a pointer and how to use & and *: int int ip y x, y; *ip; 5 &x; 5 *ip; // ip is a pointer to an integer // assigns the address of the variable x to ip // y gets the value of x Arithmetic can be performed on pointer variables. If ptr is a pointer to some element of an array, then p++ increments p to point to the next element, and p += k increments it to point k elements beyond where it currently does. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 6.7 ■ Pointers, Arrays, Structures, Unions, and Type Definition 159 6.7.2 Arrays Many applications require the processing of multiple data items that have common characteristics (e.g., a set of numerical data, represented by x1, x2, …, xn). In such situations, it is more convenient to place data items into an array, where they will all share the same name. The individual data items can be characters, integers, floating-point numbers, and so on. They must all be of the same type and the same storage class. Each array element is referred to by specifying the array name followed by one or more subscripts, with each subscript enclosed in brackets. Each subscript must be expressed as a nonnegative integer. Thus, the elements of an n-element array x are x[0], x[1], …, x[n 2 1]. The number of subscripts determines the dimensionality of the array. For example, x[i] refers to an element of a one-dimensional array. Similarly, y[i][j] refers to an element of a two-dimensional array. Higher-dimensional arrays can be formed by adding additional subscripts in the same manner. However, higher-dimensional arrays are not used very often in 8- and 16-bit microcontroller applications. In general, a one-dimensional array can be expressed as data-type array_name[expression]; A two-dimensional array is defined as data-type array_name[expr1][expr2]; An array can be initialized when it is defined. This is a technique used in table lookup, which can speed up the computation process. Example 6.6 ▼ Write the bubble sort function to sort an array of integers. Solution: The basic idea of bubble sort is to go through several iterations of the array sequentially, with each iteration placing one element in its right position. An iteration consists of comparing each element in the array with its successor (x[i] with x[i11]) and interchanging them if they are not in proper order (either ascending or descending). For an array with N elements, N 2 1 comparisons are performed during the first iteration. As more and more iterations are performed, more and more elements would be moved to their right positions. Fewer comparisons are needed in the later iterations. In the worse case, N 2 1 iterations are needed, and only one comparison is made during the last iteration. The bubble sort program can be made more efficient by keeping track of whether swap operations have been performed. If no swap is made in an iteration, then the array is already sorted, and the process should be stopped. The function that implements this idea is as follows: void swap (char *px, char *py); void bubble (char a[ ], char n) // n is the array count { char i, j; char inorder; // array in order flag for (i 5 0; i < n 2 1; i11){ // up to n 2 1 iterations are performed inorder 5 1; // assume array is in order at the start of a new iteration for (j 5 0; j < n 2 i 2 1; j11) if (a[j] > a[j11]){ // are two adjacent elements not in order? swap (&a[j], &a[j11]); inorder = 0; // array not in order } Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 160 Chapter 6 ■ C Language Programming if (inorder) // array is in order, there is no need to continue. break; } } void swap (char *px, char *py) { char temp; temp 5 *px; *px 5 *py; *py 5 temp; } ▲ 6.7.3 Pointers and Arrays In C, there is a strong relationship between pointers and arrays. Any operation that can be achieved by array subscripting can also be done with pointers. The pointer version in general will be faster but somewhat harder to understand. For example, the statement int ax[20]; defines an array ax of 20 integral numbers. The notation ax[i] refers to the ith element of the array. If ip is a pointer to an integer, declared as int *ip; then the assignment ip 5 &ax[0]; makes ip contain the address of ax[0]. Now the statement x 5 *ip; will copy the contents of ax[0] into x. If ip points to ax[0], then ip11 points to ax[1], and ip1i points to ax[i], etc. 6.7.4 Passing Arrays to a Function An array name can be used as an argument to a function, thus permitting the entire array to be passed to the function. To pass an array to a function, the array name must appear by itself, without brackets or subscripts, as an actual argument within the function call. When declaring a one-dimensional array as a formal argument, the array name is written with a pair of empty square brackets. The size of the array is not specified within the formal argument declaration. If the array is two-dimensional, then there should be two pairs of brackets following the array name, with the first pair of brackets empty and the second pair of brackets containing the column size. The following program outline illustrates the passing of an array from the main portion of the program to a function. int average (int n, int arr[]); void main ( ) { int n, avg; // variable declaration int arr[50]; // array definition … avg 5 average(n, arr); // function call … } Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 6.7 ■ Pointers, Arrays, Structures, Unions, and Type Definition int average (int k, int brr[]) { … } 161 // function definition Within main, we see a call to the function average. This function call contains two actual arguments—the integer variable n and the one-dimensional integer array arr. Note that arr appears as an ordinary variable within the function call. In the first line of the function definition, we see two formal arguments, k and brr. The formal argument declarations establish k as an integer variable and brr as a one-dimensional integer array. Note that the size of brr is not defined in the function definition. As formal parameters in a function definition, int brr[]; and int *brr; are equivalent. 6.7.5 Initializing Arrays C allows initialization of arrays. Standard data-type arrays may be initialized in a straightforward manner. The syntax for initializing an array is array_declarator 5 { value-list }; The following statement shows a five-element integer array initialization: int i[5] 5 {10, 20, 30, 40, 50}; The element i[0] has the value of 10, and the element i[4] has the value of 50. The following statement shows a two-dimensional array initialization: dispTab[6][2] 5 {{0x30,0xDF},{0x6D,0xEF},{0x79,0xF7}, {0x33,0xFB},{0x5B,0xFD},{0x5F,0xFE}}; A string (character array) can be initialized in two ways. One method is to make a list of each individual character, such as char strgx[5] 5 {‘w’, ‘x’, ‘y’, ‘z’, 0}; The second method is to use a string constant char myname [6] 5 “huang”; A NULL character is automatically appended at the end of “huang.” When initializing an entire array, the array size (which is one more than the actual length) must be included, for example char prompt [24] 5 “Please enter an integer:”; Most C compilers allow the user to declare an initialized array without specifying the array size. The C compiler will figure out the array size when it compiles the program. For example, the following statement is legal: char myName[] 5 “John Adam”; Another way to declare this string is char *myName 5 “John Adam”; 6.7.6 Structures A structure is a group of related variables that can be accessed through a common name. Each item within a structure has its own data type, which can be different from the other data items. The syntax of a structure declaration is Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 162 Chapter 6 ■ C Language Programming struct struct_name { type1 member1; type2 member2; … }; /* struct_name is optional */ The struct_name is optional and, if it exists, defines a structure tag. A struct declaration defines a type. The right brace that terminates the list of members may be followed by a list of variables, just as for any basic type. The following example is for a card catalog in a library. struct catalog_tag { char author [40]; char title [40]; char pub [40]; unsigned int date; unsigned char rev; } card; Here, the variable card is of type catalog_tag. A structure definition that is not followed by a list of variables reserves no storage; it merely describes a template or the shape of a structure. If the declaration is tagged (i.e., has a name), however, the tag can be used later in definitions of instances of the structure. For example, suppose we have the following structure declaration. struct point { int x; int y; }; We can then define a variable pt of type point as follows: struct point pt; A member of a particular structure is referred to in an expression by a construction of the form structure-name.member or structure-pointer-.member The structure member operator “.” connects the structure name and the member name. As an example, the square of the distance of a point to the origin can be computed as follows. long integer sq_distance; … sq_distance 5 pt.x * pt.x 1 pt.y * pt.y; y Radius Center x Figure 6.1 ■ Source: Atmel Corporation, The Atmel AVR Microcontroller Structures can be nested. One representation of a circle consists of the center and radius, as shown in Figure 6.1. A circle Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 6.7 ■ Pointers, Arrays, Structures, Unions, and Type Definition 163 This circle can be defined as struct circle { struct unsigned }; point int center; radius; 6.7.7 Unions A union is a variable that may hold (at different times) objects of different types and sizes, with the compiler keeping track of size and alignment requirements. Unions provide a way to manipulate different kinds of data in a single area of storage without embedding any machinedependent information in the program. The syntax of the union is as follows: union union_name { type-name1 element1; type-name2 element2; … type-namen elementn; }; The field union_name is optional. When it exists, it is called a union-tag. One can declare a union variable at the same time one declares a union type. The union variable name should be placed after the right brace }. In order to represent the current temperature using both the integer and the string, we can use the following declaration: union u_tag { int i; char c[4]; } temp; Four characters must be allocated to accommodate the larger of the two types. Integer type is good for internal computation, whereas string type is suitable for output. Of course, some conversion may be needed before making a certain kind of interpretation. Using this method, the variable temp can be interpreted as an integer or a string, depending on the purpose. Syntactically, members of a union are accessed as union-name.member or union-pointer → member just as for structures. 6.7.8 The typedef Statement The C language provides a capability that enables you to assign an alternate name to a data type. This is done with a statement known as typedef. The statement typedef int Counter; defines the name Counter to be equivalent to the C data type int. Variables can subsequently be declared to be of type Counter, as in the following statement: Counter j, n; The C compiler treats the declaration of the variables j and n, shown in the preceding statement, as normal integer variables. The main advantage of the use of typedef in this case is the added readability it lends to the definition of the variables. It is clear from the definition of j and Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 164 Chapter 6 ■ C Language Programming n what the intended purpose of these variables is in the program. Declaring them to be of type int in the traditional fashion would not have made the intended use of these variables at all clear. Of course, choosing more meaningful variable names would have helped as well. The following typedef statement defines a type name StringPtr to be a character pointer: typedef char *StringPtr; Variables subsequently declared to be of type StringPtr, as in StringPtr buffer1, buffer2; are treated as character pointers by the C compiler. The statements typedef unsigned char uint8_t; typedef unsigned int uint16_t; typedef unsigned long int uint32_t; enable the user to use uint8_t, uint16_t, and uint32_t to declare unsigned 8-bit, 16-bit, and 32-bit integer variables. A typedef statement can reuse the previously defined type. For example, the following three statements reuse the previously defined types: typedef volatile uint8_t register8_t; typedef volatile uint16_t register16_t; typedef volatile uint32_t register32_t; Atmel uses these three statements to define 8-bit, 16-bit, and 32-bit I/O registers in the header file for the C language for the AVR microcontroller. To define a new type name with typedef, follow these steps: 1. Write the statement as if a variable of the desired type was being declared. 2. Where the name of the declared variable would normally appear, substitute the new type name. 3. In front of everything, place the keyword typedef. As an example of this procedure, to define a type called Date to be a structure containing three integer numbers called month, day, and year, write out the structure definition, substituting the name Date where the variable name would normally appear (before the last semicolon). Before everything, place the keyword typedef: typedef struct { int month; int day; int year; } Date; With this typedef in place, we can subsequently declare variables to be of type Date, as in Date birthdays[100]; This defines birthdays to be an array containing 100 Date structures. 6.7.9 Enumerated Data Types This data type allows the user to define a variable and specify the valid values that could be stored into that variable. An enumerated data type definition is initiated by the keyword enum. Immediately following this keyword is the name of the enumerated data type, followed by a list of identifiers Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 6.8 ■ Miscellaneous Items 165 (enclosed by a set of curly braces) that defines the permissible values that can be assigned to the type. For example, the statement enum primaryColor {red, yellow, blue}; defines a data type primaryColor. Variables declared to be of this data type can be assigned the value red, yellow, and blue inside the program, and no other values. To declare a variable to be of type enum primaryColor, you again use the keyword enum, followed by the enumerated type name, followed by the variable list. So the statement enum primaryColor myColor, gregsColor; defines two variables myColor and gregsColor to be of type primaryColor. The only permissible values that can be assigned to these variables are the names red, yellow, and blue. So the following statements are valid: myColor 5 red; if (gregsColor 5 5 yellow) … 6.8 Miscellaneous Items 6.8.1 Automatic/External/Static/Volatile A variable defined inside a function is an internal variable of that function. These variables are called automatic, because they come into existence when the function is entered and disappear when it is left. Internal variables are equivalent to local variables in assembly language. External variables are defined outside of any function and thus are available potentially to many functions. Because external variables are globally accessible, they provide an alternative to functional arguments and return values for communicating data between functions. Any function may access an external variable by referring to it by name (if the name has been declared somewhere). External variables are also useful when two functions must share some data, yet neither calls the other. The use of static with a local variable declaration inside a block or a function causes the variable to maintain its value between entrances to the block or function. Internal static variables are local to a particular function just as automatic variables are, but unlike automatic variables, they remain in existence rather than coming and going each time the function is activated. When a variable is declared static outside of all functions, its scope is limited to the file that contains the definition. A function can also be declared as static. When a function is declared as static, it becomes invisible outside of the file that defines the function. A volatile variable has a value that can be changed by something other than user code. A typical example is an input PORT or a timer register. These variables must be declared as volatile so the compiler makes no assumptions on their values while performing optimizations. The keyword volatile prevents the compiler from removing apparently redundant references through the pointer. For example, the PORTC data register may be defined as follows: #define PORTC (*(volatile PORT_t *) 0x0640) 6.8.2 Scope Rules The functions and external variables that make up a C program need not all be compiled at the same time; the source text of the program may be kept in several files, and previously compiled routines may be loaded from libraries. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 166 Chapter 6 ■ C Language Programming The scope of a name is the part of the program within which the name can be used. For a variable declared at the beginning of a function, the scope is the function in which the name is declared. Local (internal) variables of the same name in different functions are unrelated. The scope of an external variable or a function lasts from the point at which it is declared to the end of the file being compiled. Consider the following program segment: … void f1 (…) { … } int a, b, c; void f2 (…) { … } Variables a, b, and c are accessible to function f2 but not to f1. When a C program is split into several files, it is convenient to put all global variables into one file so that they can be accessed by functions in different files. Functions residing in different files that have to access global variables must declare them as external variables. In addition, the prototypes of certain functions can be placed in one file so that they can be called by functions in other files. The following example is a skeletal outline of a two-file C program that makes use of external variables: In file1: extern int xy; extern long arr[]; void main (void) { … } void foo (int abc) { … } long soo (void) { … } In file2: int xy; long arr[100]; 6.8.3 Type Casting Type casting causes the program to treat a variable of one type as though it contains data of another type. The format for type casting is (type) variable For example, the following expression converts the variable kk to a long integer. int kk; … (long) kk Type casting can avoid many errors caused by size mismatch among operands. For example, in the program segment Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 6.8 ■ Miscellaneous Items 167 long result; int y1, y2; … result 5 y1 * y2; the product of variables y1 and y2 will be truncated to 16 bits if it is larger than 216 2 1. Then the variable result will receive an incorrect value. To fix the error, use type casting to force y1 and y2 to long integer, as follows. result 5 ((long) y1) * ((long) y2); This technique is used in several examples in this text. Another example of the use of type casting is in the pointer type. Sometimes you must treat the contents of a structure-type variable as a string. The most convenient way to do it is to recast the pointer to a structure-type variable into a pointer to a string (character type). For the declarations struct personal { char name [10]; char addr [20]; char sub1[5]; char sub2[5]; char sub3[5]; char sub4[5]; } ptr1; char *cp; we can use the following statement to treat the variable ptr1 as a string: cp 5 (char *) &ptr1; 6.8.4 Pointer to Functions In C, a function itself is not a variable, but it is possible to define pointers to functions, which can be assigned, placed in arrays, passed to functions, returned by functions, and so on. When working with pointers to functions, the C compiler needs to know not only that the pointer variable points to a function, but also the type of value returned by that function, as well as the number and types of its arguments. To declare a variable funcPtr to be of type “pointer to function that returns an int and that takes one int argument,” the declaration int (*funcPtr) (int kx); can be written. The parentheses around *funcPtr are required because otherwise the C compiler treats the preceding statement as the declaration of a function called funcPtr that returns a pointer to an int (because the function call operator () has higher precedence than the pointer indirection operator *). To set a function pointer pointing to a specific function, we simply assign the name of the function to it. Let primeTest be a function that returns an int and that takes an int argument; the statement funcPtr 5 primeTest; stores a pointer to this function inside the function pointer variable funcPtr. Writing a function name without a subsequent set of parentheses is treated in an analogous way to writing an array name without a subscript. The C compiler automatically produces a pointer to the specifi ed function. An ampersand is permitted in front of the function name, but it’s not required. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 168 Chapter 6 ■ C Language Programming If the primeTest function has not been previously defined in the program, it is necessary to declare the function before the preceding assignment can be made. So, a statement such as int primeTest (int kx); is needed before a pointer to this function can be assigned to the variable funcPtr. We can call the function that is indirectly referenced through a pointer variable by applying the function call operator to the pointer, listing any arguments to the function inside the parentheses. For example, result 5 funcPtr (ax); calls the function pointed to by funcPtr, passing the argument ax and storing the returned value in the variable result. One common application for pointers to functions is in passing them as arguments to other functions. The standard C library uses this, for example, in the function qsort, which performs a “quicksort” on an array of data elements. This function takes as one of its arguments a pointer to a function that is called whenever qsort needs to compare two elements in the array being sorted. In this manner, qsort can be used to sort arrays of any type, as the actual comparison of any two elements in the array is made by a user-supplied function, and not by the qsort function itself. Another common application for function pointers is to create what is known as dispatch tables. We can’t store functions themselves inside the elements of an array. However, it is valid to store function pointers in an array. By doing this, we can create tables that contain pointers to functions to be called. For example, we may create a table for processing different commands that will be entered by a user. Each entry in the table could contain both command name and a pointer to a function, to call to process that particular command. Now, whenever the user enters a command, the program can look up the command inside the table and invoke the corresponding function to handle it. 6.9 The C Preprocessor The preprocessor is a part of the C compilation process that recognizes special statements that might be interspersed throughout a C program. As its name implies, the preprocessor actually analyzes these statements before analysis of the C program takes place. Preprocessor statements are identified by the presence of a pound sign, #, which must be the first nonspace character on the line. As you will see, preprocessor statements have a syntax that is slightly different from that of normal C statements. 6.9.1 The #define Statement One of the primary uses of the #define statement is to assign symbolic names to program constants. The preprocessor statement #define TENms 10000 defines the name TENms and makes it equivalent to the value of 10,000. The name TENms can subsequently be used anywhere in the program where the constant 10,000 could be used. Whenever this name appears, its defined value of 10,000 is automatically substituted into the program by the preprocessor. For example, you might have the following C statement that uses the defined name TENms: counter 5 counter 1 TENms; This statement adds the value of 10,000 to the variable counter. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 6.9 ■ The C Preprocessor 169 Suppose you have the following two #define statements: #define #define AND OR && || Then you can write expressions such as if (x . 0 AND x , 10) … and if (y 5 5 0 OR y 5 5 value) … You can even include a #define statement for the equality test: #define EQUAL 5 5 and then write the statement if (y EQUAL 0 OR y EQUAL value) … The #define statement can appear anywhere in the program, but the name must be defined before it is used. A definition for a name can include more than a simple constant value. It can include an expression, simple or complicated. A macro (from the Greek µάĸpo for “big” or “far”) in computer science is a rule or pattern that specifies how a certain input sequence (often a sequence of characters) should be mapped to an output sequence (also often a sequence of characters) according to a defined procedure. The mapping process that instantiates a macro into a specific output sequence is known as macro expansion. The #define statement can also be used to define macro definition, which would enable the user to make macro substitution in his or her program. For example, the statement #define SQUARE(x) x * x enables the user to subsequently write statements, such as yy 5 SQUARE(v); to assign the value of v2 to yy. The argument v can be of type int, type long, or type float, and the same macro can be used. However, this macro definition does have a pitfall. For example, the following statement yy 5 SQUARE(v 1 1) will be evaluated as yy 5 v 1 1 * v 1 1; which would not produce the expected result. This problem can be resolved by changing the macro definition to #define SQUARE (x) ((x) * (x)) With this modification, previous invocation of the SQUARE macro will become yy 5 ((v 1 1) * (v 1 1)); and is correct. 6.9.2 The ## Operator This operator is used in macro definitions to join two tokens (a token can be a character or a string) together. It is preceded (or followed) by the name or a parameter to the macro. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 170 Chapter 6 ■ C Language Programming The preprocessor takes the actual argument to the macro that is supplied when the macro is invoked and creates a single token out of that argument and whatever token follows (or precedes) the ##. For example, with the statements #define _WORDREGISTER(regname) \ union \ {\ register16_t regname; \ struct \ {\ register8_t regname ## L; \ register8_t regname ## H; \ }; \ } and _WORDREGISTER(CH0RES); the user can use CH0RES to access the 16-bit I/O register CH0RES as one unit or use CH0RESH and CH0RESL to access the high and low bytes of the same I/O register individually. With the statements #define _DWORDREGISTER(regname) \ union \ {\ register32_t regname; \ struct \ {\ register8_t regname ## 0; \ register8_t regname ## 1; \ register8_t regname ## 2; \ register8_t regname ## 3; \ }; \ } and _DWORDREGISTER(CAL); the user can use the name CAL to access the 32-bit register as one unit or use CAL0, CAL1, CAL2, and CAL3 to access its individual bytes (CAL0 is the least significant byte and CAL3 is the most significant byte). 6.9.3 The #include Statement After you have programmed in C for a while, you will find yourself developing your set of macros that you will want to use in each of your programs. But instead of having to type these macros into each new program you write, the preprocessor enables you to collect all your definitions into a separate file and then include them in your program, using the #include statement. These files normally end with the characters .h and are referred to as header or include files. Microcontroller programming deals with the registers and bits of peripheral modules. Each register is assigned with an address. It is desirable to refer to them using symbolic names rather than addresses. The association of addresses with register names is done with #define statements and is needed by all of the programs. Therefore, they are collected in one or multiple header files and then included by all of the programs. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 6.9 ■ 171 The C Preprocessor When dealing with a large programming project, the chief designer often breaks the project into multiple files and assigns each individual file or several files to one programmer. The main function is contained in one of the program files and needs to call functions in other files. In addition to writing the function definitions, each individual programmer has to provide a header file that contains the prototype definitions of all functions contained in the program file. The chief designer includes these header files in the main program file and also includes all the program files in the project. The IDE will then be able to combine all program files into one executable code by invoking the linker. Many C programs in later chapters follow this approach. 6.9.4 Conditional Compilation The C preprocessor offers a feature known as conditional compilation. Conditional compilation is often used to create one program that can be compiled to run on different computer systems. It is often used to switch on or off various statements in the program, such as debugging statements that print out the values of various variables or trace the flow of program execution. THE #IFDEF, #ENDIF, #ELSE, #IFNDEF, #IF, AND # E L I F S TAT E M E N T S The #ifdef statement causes the subsequent statements to be executed if the specified symbol is defined. The #ifndef statement causes the subsequent statements to be executed if the specified symbol is not defined. The #if preprocessor statement offers a more general way of controlling conditional compilation. The #if statement can be used to test whether a constant expression evaluates to nonzero. If the result of the expression is nonzero, subsequent lines up to a #else , #elif, or #endif are processed; otherwise, they are skipped. The following statements define the symbol _JBLEN to be 24 if the symbol _AVR_3_BYTE_PC_ is previously defined and is nonzero: #if defined(__AVR_3_BYTE_PC__) && __AVR_3_BYTE_PC__ #define _JBLEN 24 #else #define _JBLEN 23 #endif The following statements define a pointer to the void type if it has not been defined before: #ifndef __ptr_t #define __ptr_t void * #endif When using the Atmel AVR Studio IDE to develop C programs for the AVR devices, the user needs to add the #include <avr\io.h> statement at the start of his or her C program, and specifies the target device during the project creation process. After specifying an appropriate device, the corresponding symbol will be defined and known to the IDE, and it causes the appropriate header files to be included. This is achieved by having the following statements in the io.h header file: if defined (__AVR_ATMega2560__) #include ,avr/iom2560.h. … … #elif defined (__AVR_ATXMega128A1__) #include ,avr/iox128a1.h. … #endif The AVR Studio uses this method to allow the user to use symbolic names to refer to I/O registers and their individual bits. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 172 Chapter 6 ■ C Language Programming 6.10 Using the AVR Studio C Compiler Like any other microcontroller, the ATMEL AVR is composed of several basic building blocks: An AVR CPU core, SRAM, Flash, EEPROM, I/O PORTs, and a number of peripheral modules. These building blocks are called module types. An AVR device may have one or more instances of a given module type. All instances of a module type have the same features and functions. Some module types can be a subset of other module types. These inherit a subset of the features (and registers) of the super type; all inherited features are fully compatible. This applies to timers, I/O PORTs, and so on. For the timer type, the subset means that it simply has fewer compare and capture channels than a full timer module. Similarly, an I/O PORT may have less than eight pins. A module type can be a “PORT,” whereas the module instance is, for example, PORTA, where the suffix “A” indicates the instance label. For simplicity, module instance will be referred to as a module throughout this text, unless there is a need to differentiate. Each module has a number of registers that contain control or status bits. All modules of a given type contain the same set of registers, and all these registers contain the same set of control and status bits. The relationship among the module type, module, register, and bits is illustrated in Figure 6.2. Module type MODULE0 Register Bit 7 MODULEn Figure 6.2 ■ Register Source: Atmel Corporation, The Atmel AVR Microcontroller Bit 0 Module type, instances, registers, and bits Each module has a fixed base address in the I/O memory map, and all registers contained in the module have fixed offset addresses relative to the module base address. This way each register will not only have an absolute address in the I/O memory space, but also a relative address defined by its offset. The register offset addresses are equal for all instances of a module type, simplifying the task of writing drivers that can be used for all modules of a specific type. The description of this section is based on the practice of the gcc compiler. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 6.10 ■ 173 Using the AVR Studio C Compiler 6.10.1 AVR Peripheral Register Naming Convention The AVR peripheral registers can be divided into control, status, and data registers, and their naming reflects that. A general-purpose control register of the module is named CTRL. If a module has multiple control registers, then they are differentiated by using a suffix character. In this case, the control registers would be named CTRLA, CTRLB, CTRLC, and so on. This also applies to the STATUS register. For registers having a specific function, the register name would reflect this functionality. For example, a control register that controls the interrupt level of a module is named INTCTRL. Because the AVR data bus width is 8 bits, larger registers are implemented using several 8-bit registers. For a 16-bit register, the high and low bytes are accessed by appending H and L, respectively, to the register name. For example, the 16-bit Timer/Counter count register is named CNT. The two bytes are named CNTL and CNTH. For a register larger than 16 bits, the bytes are numbered from the least significant byte. For example, the 32-bit ADC calibration register is named CAL. The four bytes are named CAL0, CAL1, CAL2, and CAL3 (from the least to the most significant byte). Most C compilers offer automatic handling of access to multibyte registers. In that case, the name CNT, without an H or L suffix, could be used to perform a 16-bit access to the Timer/ Counter count register. This is also the case for 32-bit registers. 6.10.2 AVR Peripheral Register Bit Naming Convention Register bits can have an individual function or be part of a bit group that has a joint function. An individual bit could be a bit that enables a module, for example, the ADC enable bit. A bit group can consist of two or more bits that jointly select a specific configuration of the module that they belong to. An n-bit group offers up to 2n selections. The two bits that control the ADC resolution are an example of a bit group. These two bits offer the selections shown in Table 6.9. Resolution [1:0] Group configuration 00 Description 12BIT 12-bit result, right justified 01 Reserved 10 8BIT 8-bit result, right justified 11 LEFT12BIT 12-bit result, left justified Source: Atmel Corporation, The Atmel AVR Microcontroller Table 6.9 ■ ADC conversion result resolution Bits that are part of a group will always have a number suffix. Bits that are not part of a bit group will never have a number suffix. A Timer/Counter control register D has two groups, EVACT and EVSEL (shown in Table 6.10). The bits in these groups have a number suffix, whereas the EVDLY bit, which is not part of a bit group, has no number suffix. Bit group EVACT - EVSEL Bit name EVACT2 EVACT1 EVACT0 EVDLY EVSEL3 EVSEL2 EVSEL1 EVSEL0 Bit number 7 6 5 4 3 2 1 0 Source: Atmel Corporation, The Atmel AVR Microcontroller Table 6.10 ■ Bits groups and bit names for bits in Timer/Counter control register D—CTRLD Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 174 Chapter 6 ■ C Language Programming 6.10.3 Accessing AVR Mega Device Peripheral Registers in C For Mega devices, the gcc compiler uses the #define statement to associate every peripheral register with its I/O address or memory address. This approach allows the user to use a symbolic name to access the peripheral register. For example, SPCR 5 0x50; assigns 0x50 to the control register of the SPI module. The effect of this assignment is discussed in Chapter 14. PORTA 5 0x53; outputs the value 0x53 to the PORTA pins. temp 5 PINA; reads the values of PORTA pins and stores them in the variable temp. To facilitate the access of bits of peripheral registers, Atmel assigns the position number to the symbolic name of each implemented bit of the peripheral register. For example, the iomxx0_1.h file contains the following definitions for the SPCR register: #define #define #define #define #define #define #define #define SPIE SPE DORD MSTR CPOL CPH SPR1 SPR0 7 6 5 4 3 2 1 0 // bit position 7 // bit position 6 // bit position 5 // bit position 4 // bit position 3 // bit position 2 // bit position 1 // bit position 0 The user can enable the SPI module by setting the SPE bit, using the following statement: SPCR |5 1 ,, SPE; The user can disable SPI interrupt by clearing the SPIE bit, using the following statement: SPCR &5 ~(1 ,, SPIE); // AND the SPCR register with 0x7F 6.10.4 Accessing AVR XMega Device Peripheral Registers in C Gcc deals with the XMega devices differently from the Mega devices in the following manner: • Defining a structured data type for each type of module (ADC, UART, PMIC, etc). This data type contains all of the registers in the module • Declaring a variable of the defined data type for each instance of the module For example, Atmel defined the PMIC_t data type for the programmable multiple-level interrupt controller as follows: typedef struct PMIC_struct { unsigned char STATUS; unsigned char INTPRI; unsigned char CTRL; } PMIC_t; // status register // interrupt priority register // control register After this, the PMIC module is declared (in iox128a1.h) as follows: #define PMIC (*(PMIC_t *) 0x00A0) // Programmable Interrupt Controller Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 6.10 ■ 175 Using the AVR Studio C Compiler The STATUS register of the PMIC module is located at the address of 0x00A0. With this definition, the user can access the CTRL register by appending the period character ‘.’ and the string “CTRL” to the word PMIC. For example, PMIC.CTRL 5 0x85; enables the high-priority interrupts, disables medium-priority interrupts, and enables the lowpriority interrupts in the round-robin manner. temp 5 PMIC.STATUS; reads the STATUS register and saves it in the variable temp. The AVR Studio C compiler also allows the user to access any register without using the module struct. To refer to register directly, concatenate the module instance name, an underscore, and the register name. The same naming convention is used when programming in assembly language. For example, to use the STATUS register of the PMIC module, use the name PMIC_STATUS. This approach is referred to as the flattened approach. The AVR assembler uses the flattened approach to access peripheral registers. To deal with the bits of a peripheral register of an XMega device, the user has the choice of using either the bit position value or bit mask. Bit positions are not recommended for most tasks. The relationship between a bit position and its corresponding bit mask is shown in Table 6.11. The AVR Studio C compiler defines a symbolic name for each bit position and its corresponding bit mask of a peripheral register so that the user can use the symbolic names to refer to them, to perform the desired bit field manipulation operation. For example, the bit 7 of the PMIC control register is the round-robin scheduling enable (RREN) bit. The AVR Studio C compiler defines the bit mask and bit position for it as follows: Bit position 7 6 5 4 3 2 1 0 Bit mask 0x80 0x40 0x20 0x10 0x08 0x04 0x02 0x01 Source: Atmel Corporation, The Atmel AVR Microcontroller Table 6.11 ■ Bit positions and bit masks #define PMIC_RREN_bm #define PMIC_RREN_bp 0x80 7 // round-robin priority enable bit mask // round-robin priority enable bit position With this definition, the user can set and clear the RREN bit, using the following statements: PMIC.CTRL |5 PMIC_RREN_bm; PMIC.CTRL &5 ~PMIC_RREN_bm; // enable round-robin interrupt priority // disable round-robin interrupt priority Many peripheral functions are controlled by a group of bits. The control register D of a 16-bit timer (timer 0 and 1) and the bit group EVACT are shown in Figure 6.3. The AVR Studio C compiler defines three constants for each bit group: • Bit group position: This constant specifies the lowest bit position of the group. For example, the group position for the EVACT group is 5. • Bit group mask: This constant allows the user to clear the group so that further operation on the group can be performed easily. For example, the group mask for the EVACT group is 0xE0. • Bit group configurations: Because there are seven possible settings for the EVACT bit group, the AVR Studio C compiler defines seven constants corresponding to them. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. Chapter 6 ■ C Language Programming 7 6 5 EVACT[2:0] 4 3 2 1 0 EVSEL[3:0] EVDLY EVACT[2:0] Group configuration 000 001 010 011 100 101 110 111 OFF CAPT UPDOWN QDEC RESTART FRQ PW Event action None Input capture Externally controlled up/down count Quadrature decode Restart waveform period Frequency capture Pulse width capture Reserved Source: Atmel Corporation, The Atmel AVR Microcontroller 176 Figure 6.3 ■ Timer control register D and the group configuration of EVACT bit group The header file of an XMega device includes the following statements to define the EVACT bit group: #define #define TC0_EVACT_gm TC0_EVACT_gp 0xE0 5 /* Event Action group mask. */ /* Event Action group position. */ The AVR Studio C compiler uses enumeration type to define all the possible configurations for each bit group. The configuration definition for the EVACT group is as follows: /* Event Action */ typedef enum TC_EVACT_enum { TC_EVACT_OFF_gc TC_EVACT_CAPT_gc TC_EVACT_UPDOWN_gc TC_EVACT_QDEC_gc TC_EVACT_RESTART_gc TC_EVACT_FRW_gc TC_EVACT_PW_gc } TC_EVACT_t; 5 (0x00,,5), /* No Event Action */ 5 (0x01,,5), /* Input Capture */ 5 (0x02,,5), /* Externally Controlled Up/Down Count */ 5 (0x03,,5), /* Quadrature Decode */ 5 (0x04,,5), /* Restart */ 5 (0x05,,5), /* Frequency Capture */ 5 (0x06,,5), /* Pulse-width Capture */ The bit group mask is primarily intended to clear the old configuration of a bit group before writing a new value. To set a bit group to certain configuration, the user should take the following two steps: Step 1 Clear the bit group using the group mask. Step 2 Set the bit group to the desired configuration by ORing the control register with an appropriate configuration value. For example, the following statement configures the Timer/Counter C0 to input capture mode: TCC0.CTRLD 5 (TCC0.CTRLD & ~(TC_EVACT_gm)) | TC_EVACT_CAPT_gc; Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 6.11 ■ Using the AVR Studio IDE to Develop C Programs 177 6.11 Using the AVR Studio IDE to Develop C Programs The procedure for developing C programs, using the AVR Studio IDE, includes the following steps: Step 1 Create a new project to manage the programming task. Step 2 Enter C functions in one or multiple files. Step 3 Add C files into the project. Step 4 Compile (also called build) the project and eliminate syntax and semantic errors of all the C programs. Step 5 Execute and debug the project. 6.11.1 Create a New Project Source: Atmel Corporation, The Atmel AVR Microcontroller The AVR Studio IDE can be started by clicking on its icon on the PC monitor screen. The AVR Studio IDE can be started by clicking on its icon. The startup screen of AVR Studio is shown in Figure 6.4. Because we want to create a new project, click the New Project button (on the middle left in Figure 6.4). The screen will change to that in Figure 6.5. The next step is to select Installed Template, enter project name, and select project location. Click AVR GCC in the box under Installed Templates, set project location to an Figure 6.4 ■ AVR Studio startup screen Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. Chapter 6 ■ C Language Programming Source: Atmel Corporation, The Atmel AVR Microcontroller 178 Figure 6.5 ■ AVR Studio screen after clicking on New Project on the start page Source: Atmel Corporation, The Atmel AVR Microcontroller appropriate directory (c:\books\avr\programs\ch06 in this tutorial), and enter an appropriate project name (e.g., ctutor1). The screen will change to that in Figure 6.6. Check the box Create directory for solution if it is unchecked. Click OK when you are satisfied with the name. Click the C option under AVR GCC inside the Recent Templates window. If you deal with the user demo board, then you should select User Boards under AVR GCC. When you are satisfied with the names that you entered, click OK and a dialog box will appear to allow you to select the target device as shown in Figure 6.7. Figure 6.6 ■ AVR Studio screen for selecting installed templates, entering project name, and selecting project location Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. ■ Using the AVR Studio IDE to Develop C Programs 179 Source: Atmel Corporation, The Atmel AVR Microcontroller 6.11 Figure 6.7 ■ AVR Studio pop up dialog for device selection Source: Atmel Corporation, The Atmel AVR Microcontroller Select a device (ATXMega128A1 in this tutorial) and then click OK and the screen will change to that in Figure 6.8. Figure 6.8 ■ AVR Studio screen after a new project has been created Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 180 Chapter 6 ■ C Language Programming AVR Studio version 5 is based on Microsoft Visual Studio and hence the application development process is organized into projects and solutions. A solution is a logic folder that contains references to all the source files contained in your project, all the included libraries and all the built executables. A solution allows a seamless reuse of code and an easy automation of the build process for complex application. 6.11.2 Entering C Programs in AVR Studio IDE The AVRStudio IDE creates a default source file with the name of ctutor1.c under <project_ dir>\projectName\projectName as shown in Figure 6.8 (c:\books\avrFinal\programs\ch06\ctutor1\ctutor1 in this example). This C file contains the main function. Click ctutor1.c inside the Solution explorer window if the ctutor1.c file is not open (on the left) yet. Unless the project directory already has a file with the same name, the ctutor1.c file would be an empty file. The programmer should enter his or her main function using this file. The programmer should enter the following program to ctutor.c for this tutorial: #include ,avr\io.h. unsigned int prim_num[6]; // array to hold the prime numbers #define yes 1 #define no 0 char isprime(unsigned int x); unsigned char sqroot(unsigned int y); void main (void) { unsigned int i, count; unsigned int testnum; // number to be tested i 5 2; // index of array prim_num for holding the first found prime number testnum 5 9999; // first number to be tested for prime under 10000 count 5 3; // number of primes less than 10000 to be found while (count){ if(isprime(testnum)){ // if the number to be tested is prime, then save it prim_num[i] 5 testnum; i--; count--; } testnum -5 2; } testnum 5 10001; // first number to be tested for prime number above 10000 count 5 3; i 5 3; // index for array prim_num to hold the first prime number above 10000 while (count){ if(isprime(testnum)){ prim_num[i] 5 testnum; i11; count--; } testnum 15 2; } while(1); } Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 6.11 ■ Using the AVR Studio IDE to Develop C Programs 181 //------------------------------------------------------------------------------------------------------------------------------------// This function tests whether the unsigned integer k is a prime number. //------------------------------------------------------------------------------------------------------------------------------------char isprime (unsigned int k) { int i; char limit; if (k , 2) return 0; else if(k , 4) return 1; limit 5 sqroot(k); // use the square root as prime test limit for (i 5 2; i ,5 limit; i11) if ((k % i) 5 5 0) return 0; // divisible? return 1; } //------------------------------------------------------------------------------------------------------------------------------------// This function finds the closest integral square root of the unsigned integer y. //------------------------------------------------------------------------------------------------------------------------------------unsigned char sqroot (unsigned int y) { unsigned int i, sar, mask, test; sar 5 0; mask 5 0x80; for (i 5 0; i , 8; i11) { test 5 sar | mask; if ((test * test) ,5 y) sar 5 test; mask 5 mask .. 1; } if ((y 2 sar * sar) , ((sar11) * (sar11) 2 y)) return sar; else return (sar11); } This program finds the three prime numbers closest to 10,000 but smaller than 10,000 and the three prime numbers closest to 10,000 but greater than 10,000. The screen after entering the program is shown in Figure 6.9. 6.11.3 Add C Files into the Project The user can also add existing files to a project. To add a new or an existing file to the project, the user should press the right-mouse button on the string “ctutor1” on the Solution Explorer window and select the Add New item… or Add existing item… option as shown in Figure 6.10. After that, the user can use the file browser to select the appropriate files to be added to the project. If the user selects the Add New item… option, then the dialog as shown in Figure 6.11 will appear to allow the user to enter a new C file or header file. The user should enter the file name and click Add to add the new file. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. Chapter 6 ■ C Language Programming Source: Atmel Corporation, The Atmel AVR Microcontroller 182 ■ AVR screen after entering a C program Source: Atmel Corporation, The Atmel AVR Microcontroller Figure 6.9 Figure 6.10 ■ Screen for adding new item or existing item to the project 6.11.4 Compile (or Build) the Project To compile (or build) the project, press the Build menu and select Build Solution as shown in Figure 6.12. The user also can press the F7 function key instead. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. ■ Using the AVR Studio IDE to Develop C Programs 183 Source: Atmel Corporation, The Atmel AVR Microcontroller 6.11 ■ AVR Studio dialog for adding a new C file or Include file Figure 6.12 ■ AVR Studio screen for building the project Source: Atmel Corporation, The Atmel AVR Microcontroller Figure 6.11 If there are syntax errors, the AVR Studio C compiler will indicate them as shown in Figure 6.13. By clicking on the error message, the mouse cursor will be moved to the statement where the error is located. One example is shown in Figure 6.14 (tetnum undefined). The user can then fix the error and recompile the program. This process should be repeated until all of the errors have been removed. 6.11.5 Execute and Debug the Project The user can choose to use either the simulator (simulation) or the target hardware (emulation, a debug adapter is needed). There are three methods to start program execution and debugging in the AVR Studio as shown in Figure 6.15: 1. Start debugging. In this method, the AVR Studio launches the debugging/emulation tool, which immediately starts an emulation session. Your program is executed immediately in this method. Pressing the function key F5 also can start this method. This method can be used to find out whether a program works in certain hardware. When this option is selected, a pop up dialog will appear to allow the user to select debug tool as shown in Figure 6.16. After the user selects the debug tool, AVR Studio will immediately start the debugging session and execute the program. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. Chapter 6 ■ C Language Programming Source: Atmel Corporation, The Atmel AVR Microcontroller 184 ■ Example of AVR Studio error messages Source: Atmel Corporation, The Atmel AVR Microcontroller Figure 6.13 Source: Atmel Corporation, The Atmel AVR Microcontroller Figure 6.14 ■ The mouse cursor moved to the statement with error after clicking on error message Figure 6.15 ■ Start to debug the project Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 6.11 ■ Using the AVR Studio IDE to Develop C Programs 185 2. Start debugging and break. The AVR Studio launches the debugging tool and starts the simulation/emulation session with a breakpoint set at the entry point of the produced executable file. On encountering the breakpoint the simulator/debugger will suspend the program run. Pressing function key F10 also can start this method. This method provides many debugging options (for example, set breakpoints, run-to-cursor, add variables to the watch list) to the user. Like the first debug option, this option also will cause the AVR Studio to put out a pop up dialog for the user to select the debug tool (shown in Figure 6.16). After the user selects the debug tool, the screen will change to that in Figure 6.17. A yellow arrow points to the first executable statement of the main function. Source: Atmel Corporation, The Atmel AVR Microcontroller 3. Start without debugging. AVR Studio launches the debugging tool, but not the emulation session, which means that you can set up a breakpoint with ease before the launch. Pressing the function key F5 and the CTRL key also can start this method. ■ AVR Studio popup dialog for selecting debug tool Figure 6.17 ■ AVR Studio screen after Start Debugging and Break option is performed Source: Atmel Corporation, The Atmel AVR Microcontroller Figure 6.16 Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 186 Chapter 6 SET UP ■ C Language Programming W AT C H L I S T Source: Atmel Corporation, The Atmel AVR Microcontroller The Watch window is an AVR Studio IDE window in which the user can place program variables and watch their value changes during the course of program execution. This feature is a good help during the debugging process. The Watch window in Figure 6.17 is empty. Only global variables can be placed in the Watch window. The array variable prim_num[] is declared as a global variable. To place the variable prim_num in the Watch window, press the right-mouse button on the variable and select Add Watch as shown in Figure 6.18. After this, the variable prim_num will appear in the Watch window. Since prim_num is an array, there is a + sign to its left. The user can click the + sign and display every element of the array prim_num. The Watch window after expanding the prim_num array is shown in Figure 6.19. ■ Add prim_num into the Watch Window Figure 6.19 ■ Watch Window with expanded array prim_num [] Source: Atmel Corporation, The Atmel AVR Microcontroller Figure 6.18 RUN TO CURSOR A convenient feature for debugging is to let the program execute to a certain statement and watch the variable changes in the Watch window. In Figure 6.20, we let the program execute until the statement testnum 5 10001;. After releasing the mouse button, the AVR MCU starts Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 6.11 ■ Using the AVR Studio IDE to Develop C Programs 187 Source: Atmel Corporation, The Atmel AVR Microcontroller program execution, and the Watch window changes to that in Figure 6.21. The first three elements of the prim_num[] have been generated and displayed in the decimal format by default. You can change the display format to hexadecimal by pressing the right-mouse button on the variable name prim_num in the Watch window and selecting Hexadecimal Display, as shown in Figure 6.22. This will cause all values to be displayed in the hexadecimal format, as shown in Figure 6.23. ■ Use the “Run to Cursor” feature to watch program variables change Source: Atmel Corporation, The Atmel AVR Microcontroller Figure 6.20 Figure 6.21 ■ Watch window after program is executed until the statement “testnum 5 10001;” Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. Chapter 6 ■ C Language Programming Source: Atmel Corporation, The Atmel AVR Microcontroller 188 ■ Display all values in Watch Window in hexadecimal format Figure 6.23 ■ Display all values in Watch Window in hex format Source: Atmel Corporation, The Atmel AVR Microcontroller Figure 6.22 Source: Atmel Corporation, The Atmel AVR Microcontroller Next execute the Run to Cursor feature at the while (1); statement, and all the prime numbers will be generated, as shown in Figure 6.24. Figure 6.24 ■ Program execution result Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 6.11 ■ Using the AVR Studio IDE to Develop C Programs 189 OTHER COMMANDS There are other debug commands that are useful to program debugging. For example: 1. Reset.This command will force the AVR Studio to start program execution from the first statement of the main function. When this command is executed, the AVR Studio IDE places the mouse cursor at the first executable statement in the main function and waits for further commands. 2. Toggle Breakpoint. A breakpoint is a statement at which program execution is going to stop. After setting a breakpoint, the user can start program execution by pressing function key F5. When reaching the breakpoint, the AVR Studio will stop and update the contents of all windows of the AVR Studio. The programmer can figure out whether the program execution is correct up to the breakpoint. 3. Step into, Step over, and Step out. These commands allow the user to execute one statement at a time and examine the execution result, and hence are useful for checking whether a specific statement correctly performs the desired operation. This ends the tutorial. AVR Studio version 5 is still under active development at the time of this writing. Some of the features may not work properly yet. Example 6.7 ▼ Write a program to find all the four-digit decimal numbers that have the following property: The square of the sum of the upper and lower halves of the given number is equal to the original number. Solution: The upper and lower halves of a four-digit number can be separated by dividing the given number by 100. The following program finds all the four-digit decimal numbers that have the specified property and saves them in an array: #include <avr\io.h> unsigned int xarr[10]; char test(unsigned int k); void main (void) { unsigned int k; unsigned char i; i 5 0; // used as index of xarr[] for (k 5 1000; k , 10000; k11){ if (test(k) 5 5 1){ // Does the current array element has the specified property? xarr[i] 5 k; // Yes, save it. i11; // increment the index } } while(1); } char test(unsigned int k) { unsigned int xa, xb, xc; xa 5 k / 100; // calculate the upper two digits of the number xb 5 k % 100; // find the lower two digits of the number xc 5 xa 1 xb; // add the upper and lower two digits of the number if ((xc * xc) 5 5 k) // calculate the square of the sum Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 190 Chapter 6 ■ C Language Programming return 1; else return 0; } The three numbers having this feature are 2025, 3025, and 9801. ▲ 6.12 Multiple-File Project It is common for a real-world application to have multiple files. There are two reasons for this: 1. Code reuse. After developing applications for some time, the developer will accumulate certain number of reusable programs. By reusing the previously verified programs, the programmer can reduce the application development time. 2. Divide and Conquer. Applications are often very complicated. However, there is always a deadline for the application software. Missing deadline often means penalty or even losing business. In order not to miss the deadline, the project manager divides a complex project into several smaller and manageable subprojects and assigns each subproject to one developer. A subproject may be written as a single-file or multiplefile program. After each subproject has been written and tested, the whole project can be built by combining all the subprojects together. In the following we will use the circuit shown in Figure 14.10 to illustrate the setup of a multiple-file project. We would like to use the circuit shown in Figure 14.10 to display the following patterns repeatedly, with each row displayed for 600 ms: 012345 123456 234567 345678 456789 567890 678901 789012 890123 901234 The circuit in Figure 14.10 uses the time-multiplexing technique to display six digits. The first 74HC595 shift register drives the seven-segment pattern to be displayed, whereas the second 74HC595 selects a display to be lighted. Both shift registers have the SPI interface. These six displays are lighted in turn from left to right, with each display turned on for 1 ms and then turned off. Because this application is related to timing, we need to call a function to create a time delay of 1 ms. We have a delays_xmega.c file that contains a function called delayby1ms(), which will create a delay that is a multiple of 1 ms. The delays_xmega.c file also contains functions for several other time delays. The prototypes of these delay functions are stored in the header file delays_xmega.h. We also need to set up the system clock source. For this purpose, we create a file called sysClock_xmega.c (to be discussed in Chapter 7) for the XMega device. The function setCPUClockto32Mwith16MCrystal() sets the CPU clock to 32 MHz, using an external 16-MHz crystal. The header file associated with sysClock_xmega.c is sysClock_xmega.h. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 6.12 ■ Multiple-File Project 191 We create a project called sevenSegDisplay, which would contain a file with the same name to hold the main function and several other required functions as follows: #include ,avr\io.h. #include “sysClock_xmega.h” #include “delays_xmega.h” #define d0 0xFC // seven-segment pattern of 0 #define d1 0x60 // seven-segment pattern of 1 #define d2 0xDA // seven-segment pattern of 2 #define d3 0xF2 // seven-segment pattern of 3 #define d4 0x66 // seven-segment pattern of 4 #define d5 0xB6 // seven-segment pattern of 5 #define d6 0xBE // seven-segment pattern of 6 #define d7 0xE0 // seven-segment pattern of 7 #define d8 0xFE // seven-segment pattern of 8 #define d9 0xF6 // seven-segment pattern of 9 #define S0 0x7F // value to allow only display #0 to be turned on #define S1 0xBF // value to allow only display #1 to be turned on #define S2 0xDF // value to allow only display #2 to be turned on #define S3 0xEF // value to allow only display #3 to be turned on #define S4 0xF7 // value to allow only display #4 to be turned on #define S5 0xFB // value to allow only display #4 to be turned on void initSPIx(void); void putcSPID_Xmaster(unsigned char cx); void main (void) { unsigned char dispTab[10][12] 5 {{S0,d0,S1,d1,S2,d2,S3,d3,S4,d4,S5,d5}, {S0,d1,S1,d2,S2,d3,S3,d4,S4,d5,S5,d6}, {S0,d2,S1,d3,S2,d4,S3,d5,S4,d6,S5,d7}, {S0,d3,S1,d4,S2,d5,S3,d6,S4,d7,S5,d8}, {S0,d4,S1,d5,S2,d6,S3,d7,S4,d8,S5,d9}, {S0,d5,S1,d6,S2,d7,S3,d8,S4,d9,S5,d0}, {S0,d6,S1,d7,S2,d8,S3,d9,S4,d0,S5,d1}, {S0,d7,S1,d8,S2,d9,S3,d0,S4,d1,S5,d2}, {S0,d8,S1,d9,S2,d0,S3,d1,S4,d2,S5,d3}, {S0,d9,S1,d0,S2,d1,S3,d2,S4,d3,S5,d4}}; unsigned char ix, iy, k; setclkCPUto32Mwith16MCrystal(); initSPIx(); while(1) { for (ix 5 0; ix , 10; ix11){ // there are ten different patterns for (k 5 0; k , 100; k11){ // each row lasts for 600 ms Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 192 Chapter 6 ■ C Language Programming for (iy 5 0; iy , 12; iy 15 2){ // time-multiplex six digits putcSPID_Xmaster(dispTab[ix][iy]); // send out digit select value putcSPID_Xmaster(dispTab[ix][iy11]); // send out seven-segment pattern PORTD.OUT &5 0xE7; // transfer data from shift register to output latch PORTD.OUT |5 0x18; // within the 74HC595 delayby1ms(1); // wait for 1 ms } } } } } // ------------------------------------------------------------------------------------------------------------------// This function enables SPI module to master mode, set SCK to idle low, shift // data MSB first on the rising edge of SCK, and set data shift rate to 4 MHz. // ------------------------------------------------------------------------------------------------------------------void initSPIx(void) { PORTD.DIR 5 0xBF; // configure MOSI, SCK for output, MISO for input SPID.CTRL 5 0xF1; // enable master mode, SCK idle low, sample data on rising edge, 4 MHz SPID.INTCTRL 5 0; } // -----------------------------------------------------------------------------------------------------------// The SPI master of the XMega device associated with PORTD calls this function // to send a character to an SPI slave. // -----------------------------------------------------------------------------------------------------------void putcSPID_Xmaster(unsigned char cx) { char tmp; SPID.DATA 5 cx; // write data to SPI data register while(!(SPID.STATUS & SPI_IF_bm)); // wait for data byte to be shifted out tmp 5 SPID.DATA; // clear the IF flag } Assuming that we create this project under the c:\books\avrFinal\programs\ch06 directory, then the following directories will be created: 1. c:\books\avrFinal\programs\ch06\sevenSegDisplay—project directory 2. c:\books\avrFinal\programs\ch06\sevenSegDisplay\sevenSegDisplay—solution directory We should place the sysClock_xmega.h and delays_xmega.h header files under the solution directory because we use the following two statements to include these two header files to the project: #include #include “sysClock_xmega.h” “delays_xmega.h” Both the sysClock_xmega.c and delays_xmega.c files must be included to this project. After the sevenSegDisplay project is created, we should see the screen, as shown in Figure 6.25. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. ■ 193 Summary Source: Atmel Corporation, The Atmel AVR Microcontroller 6.13 Figure 6.25 ■ AVR Studio screen for the sevenSegDisplay project 6.13 Summary A C program consists of one or more functions and variables. The main( ) function is required in every C program. It is the entry point of a C program. A function contains statements that specify the operations to be performed. The types of statements in a function could be declaration, assignment, function call, control, and NULL. A variable stores a value to be used during the computation. A variable must be declared before it can be used. The declaration of a variable consists of the name and the type of the variable. There are four basic data types in C: int, char, float, and double. Several qualifiers can be added to the variable declarations. They are short, long, signed, and unsigned. Constants are often needed in forming a statement. There are four types of constants: integers, characters, floating-point numbers, and strings. There are seven arithmetic operators: 1, 2, *, /, %, 11, and 2 2. There are six bitwise operators: &, |, ˆ, ~, .., and ,,. Bitwise operators can be applied only to integers. Relational operators are used in control statements. They are 5 5, !5, ., .5, ,, ,5, &&, ||, and !. The control-flow statements specify the order in which computations are performed. Control-flow statements include if-else statement, multi-way conditional statement, switch statement, for-loop statement, while statement, and do-while statement. Every C program consists of one or more functions. The definition of a function cannot be embedded within another function. The same function can be called from several different places within a program. Generally, a function will process information passed to it from the Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 194 Chapter 6 ■ C Language Programming calling statement of the program and return a single value. Information is passed to a function via special identifiers called arguments (also called parameters) and returned via the return statement. Some functions, however, accept information but do not return anything (for example, the library function printf). A pointer holds the address of a variable. Pointers can be used to pass information back and forth between a function and its reference (calling) point. In particular, pointers provide a way to return multiple data items from a function via function arguments. Pointers also permit references to other functions to be specified as arguments to a given function. Two operators are related with pointers: * and &. The * operator returns the value of the variable pointed to by the pointer. The & operator returns the address of a variable. Data items that have common characteristics are placed in an array. An array may be onedimensional or multidimensional. The dimension of an array is specified by the number of square bracket pairs [] following the array name. An array name can be used as an argument to a function, thus permitting the entire array to be passed to the function. To pass an array to a function, the array name must appear by itself, without brackets or subscripts. An alternative way to pass arrays to a function is to use pointers. A variable defined inside a function is an internal variable of that function. External variables are defined outside of any function and are thus potentially available to many functions. The scope of a name is the part of the program within which the name can be used. The scope of an external variable or a function lasts from the point at which it is declared to the end of the file being compiled. In C language, parallel I/O is performed by an assignment statement. An input operation is performed by making the PORT data register as one of the source operands, whereas an output operation is performed by making the PORT data register as the destination of a statement. The header file in C language is used mainly to hold constant definitions (registers and bits are in this category), macros, functional prototype declarations, and type definition. It is not meant to hold program files. The register and bit definitions contained in the header file allows the user to use symbolic names to refer to registers and bits, which would improve the readability of the program. 6.14 Exercises E6.1 What is the value of ax/bx, assuming that ax 5 93 and bx 5 19? E6.2 What is the value of ax % bx, assuming that ax 5 93 and bx 5 23? E6.3 What is the value of ax ^ bx, assuming that ax 5 0x93 and bx 5 7D? E6.4 What are the values of ax ,, 2 and ax .. 2, assuming that ax 5 0xD7? E6.5 What is the value of ax & bx, assuming that ax 5 0xB6 and bx 5 0xED? E6.6 Write a program to find the median of an array of 8-bit unsigned integers. When the array has an even number of elements, the median is defined as the average of the middle two elements. Otherwise, it is defined as the middle element of the array. You need to sort the array in order to find the median. E6.7 Write a program to find the mode of the array of 8-bit unsigned integers. The mode is the element that occurs most frequently. E6.8 Write a function to test whether a given number is a multiple of 8. A 1 is returned if the given number is a multiple of 8. Otherwise, a 0 is returned. The number to be tested is an integer and is an argument to this function. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 6.15 ■ Lab Assignments 195 E6.9 Write a function that finds the greatest common divisor (GCD) of two unsigned integers m and n. E6.10 What is a function prototype? What is the difference between a function prototype and function definition? E6.11 Write a switch statement that will examine the value of an integer variable yy and assign one of the following values to the variable dd, depending on the value of yy: (a) 15, if yy 5 5 1 (b) 25, if yy 5 5 2 (c) 35, if yy 5 5 3 (d) 45, if yy 5 5 4 (e) 55, if yy 5 5 5 E6.12 Write a function that converts a lowercase letter to uppercase. E6.13 Write a function that swaps the first element of the array with the last element, swaps the second element of the array with the second to last element, and so on. E6.14 Write a function that swaps the first row of a matrix with the last row, swaps the second row of the matrix with the second-to-last row, and so on. E6.15 Write a loop to compute the sum of the squares of the first 100 odd integers. E6.16 An Armstrong number is a number of n digits that is equal to the sum of each digit raised to the nth power. For example, 153 (which has three decimal digits) equals 131 53 1 33. Write a function to test whether a three-digit number is an Armstrong number and a test program to store all three-digit Armstrong numbers in an array. E6.17 Write a function to test whether a four-digit decimal number is an Armstrong number and a main program to find all four-digit Armstrong numbers and store them in an array. E6.18 Write a program to find the first five numbers that when divided by 2, 3, 4, 5, or 6 leave a remainder of 1, and when divided by 7, have no remainder. E6.19 Write a function that tests whether a four-digit decimal number has the property that the sum of the squares of the upper and lower halves equals the original number. The function returns a 1 if a given number has this property. Otherwise, it returns a 0. E6.20 Write a function that can convert a NULL-terminated string that represents a decimal number into a binary number. Assume that the string represents a signed binary number no larger than 16-bit. E6.21 Write a function that can convert a binary number into a NULL-terminated BCD string that represents the given binary number. 6.15 Lab Assignments L6.1 Write a program that finds four prime numbers that are closest to but less than 20,000 and four prime numbers that are closest to but higher than 30,000. L6.2 Write a program to find the first five numbers that when divided by 2, 3, 4, 5, and 6 leave a remainder of 1, and when divided by 7, have no remainder. L6.3 Write a function and a test program to find all the 3-digit decimal Armstrong numbers and store them in an array. L6.4 Write a function and a test program to find all the 4-digit decimal Armstrong numbers and store them in an array. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 7 System Clock Configuration 7.1 Objectives After completing this chapter, you will be able to • Understand the importance of the system clock generation. • Understand the possible system clock generation options. • Understand the Mega device clock circuit module. • Be able to configure the Mega system clock signal by programming the fuse map. • Understand the XMega device clock circuit module. • Be able to configure the XMega system clock by programming the appropriate registers. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 198 Chapter 7 ■ System Clock Configuration 7.2 Overview of System Clock Generation Time delays are needed to achieve the desired effects of I/O operations. Examples include LED flashing, time-multiplexing of multiple seven-segment displays, keeping track of time of day, siren generation, song playing, LCD write operation, stepper motor driving, keypad and keyboard debouncing, EEPROM and flash memory internal write operation, and so on. Without accurate time delays, these operations cannot be performed properly and correctly. Time delay creation is based upon an accurate system clock frequency. Devices such as ceramic resonators, crystal oscillators, and RC circuits (on-chip or off-chip) have been used to generate a system clock. Among them, the crystal oscillator has the tightest frequency tolerance and should be used in any system requiring accurate timing. When timing accuracy is not critical, either a ceramic resonator or an RC circuit can be used. The clock signal required by the MCU must be a square waveform. However, the waveform generated from a ceramic oscillator, a crystal oscillator, or an RC circuit is not a square wave and must be squared up before it can be used by the MCU. Because this circuit is indispensible, all MCUs have incorporated it on a chip. The frequency of the crystal oscillator may not be the same as the on-chip system clock. The MCU may include a circuit to multiply or divide the frequency of the oscillator. Frequency division is achieved by using a countdown counter. However, frequency multiplication must be performed by a phase-lock loop (PLL). The PLL is a circuit technique that can not only stabilize but also multiply the clock frequency. Many of the latest MCUs (including the XMega AVR) have incorporated a PLL circuit on the chip. In addition to the CPU, every peripheral module in the MCU also requires a clock signal to function. To satisfy this demand, the MCU includes a complicated circuit to generate clock signals and distribute them to every peripheral module. 7.3 The Clock System of the AVR Mega Devices The clock distribution of the AVR Mega devices is shown in Figure 7.1. The CPU clock (clkCPU) is routed to parts of the system concerned with the AVR core operation. Examples of such module are general-purpose registers, the status registers, and data memory. The I/O clock (clkI/O) is used by the majority of the I/O modules, like timer/counters, SPI, and USART. The I/O clock is also used by the external interrupt module. The flash clock (clkFLASH) controls the operation of the flash memory interface. The asynchronous clock (clkASY) allows the asynchronous timer/counter to be clocked directly from an external clock or an external 32 kHz clock crystal. The ADC clock (clkADC) provides an operation clock required by the ADC module. 7.3.1 Clock Sources The clock sources available to the Mega devices are listed in Table 7.1. The user selects the clock source by programming the CKSEL fuse bits (via the AVR Studio IDE). The low-power crystal oscillator or the full-swing crystal oscillator should be connected to the XTAL1 (input) and XTAL2 (output) pins. The low-power crystal oscillator has reduced voltage swing on the XTAL2 output, is not capable of driving other clock inputs, and may be more susceptible to noisy environment. The full-swing crystal oscillator can drive other clock input and should be used in a noisy environment. A typical crystal oscillator circuit connection is shown in Figure 7.2. The recommended values for C1 and C2 are from 12 to 22 pF. When a lowpower crystal oscillator with frequency in the range of 8 to 16 MHz is used, the bit 3 to 1 of the CKSEL fuses should be set to 111. When a full-swing crystal oscillator with a frequency in the range of 0.4 to 16 MHz is used, the bit 3 to 1 of the CKSEL fuses should be set to 011. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 7.3 ■ 199 The Clock System of the AVR Mega Devices Asynchronous timer/counter General I/O modules ADC RAM CPU core Flash and EEPROM clkADC clkI/O AVR clock Control unit clkASY clkCPU clkFLASH Reset logic Watchdog timer System clock prescaler Watchdog oscillator Clock multiplexer Timer/Counter oscillator Figure 7.1 ■ External clock Crystal oscillator Low-frequency crystal oscillator Calibrated RC oscillator Source: Atmel Corporation, The Atmel AVR Microcontroller Source clock AVR Mega device clock distribution Device clocking option Low-power crystal oscillator CKSEL[3:0] 1111–1000 Full-swing crystal oscillator 0111–0110 Low-frequency crystal oscillator 0101–0100 Internal 128 kHz RC oscillator 0011 Calibrated internal RC oscillator 0010 External clock 0000 Reserved 0001 Note: For all fuses, “1” means unprogrammed, whereas “0” means programmed Source: Atmel Corporation, The Atmel AVR Microcontroller Table 7.1 ■ Mega device clocking options select 7.3.2 Default Clock Source A Mega device is shipped with a calibrated internal RC oscillator at 8.0 MHz and with the CKDIV8 fuse programmed (value is 0), resulting in a 1.0 MHz system clock. The startup time is set to maximum and the time-out period enabled. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 200 Chapter 7 ■ System Clock Configuration XTAL2 C1 XTAL1 Figure 7.2 ■ Source: Atmel Corporation, The Atmel AVR Microcontroller C2 Crystal oscillator connections 7.3.3 External Clock An external clock source (a square wave with a stable frequency) can be used to generate clock signals required by all the modules. When an external clock source is used, it is connected to the XTAL1 pin, and the XTAL2 pin is left unconnected. 7.3.4 Watchdog Oscillator The Watchdog timer is a circuit that is used to detect software errors (to be detailed in Chapter 9). The clock source of the Watchdog timer is derived from the on-chip 128 kHz RC oscillator. 7.3.5 Low-Frequency Oscillator The Mega device can use a 32.768 kHz watch oscillator as its clock source. The crystal should be connected as shown in Figure 7.2. 7.3.6 Timer/Counter Oscillator The Mega device can operate its timer/counter2 from an external 32.768 kHz watch crystal or an external clock source. This crystal should be connected to the TOSC1 (input) and TOSC2 (output) pins. The circuit connection method is identical to that in Figure 7.2. 7.3.7 System Clock Prescaler 7 6 5 4 CLKPCE — — — R/W R R R 3 2 1 0 CLKPS3 CLKPS2 CLKPS1 CLKPS0 R/W R/W R/W R/W CLKPCE: Clock prescaler change enable This bit must be written to 1 to enable change of CLKPS bits. The CLKPCE bit is only updated when the other bits in CLKPR are simultaneously to 0. CLKPCE is cleared by hardware four cycles after it is written or when CLKPS bits are written. CLKPS3~0: Clock prescaler selects 3~0 These bits define division factor between the selected clock source and the internal system clock, as shown in Table 7.2. Figure 7.3 ■ Reset value = 0x0x Source: Atmel Corporation, The Atmel AVR Microcontroller In Figure 7.1, the clock source selected by the clock multiplexer is further divided by the system clock prescaler. The possible prescaling factor is chosen by the CLKPR register. The contents of the CLKPR register are shown in Figure 7.3. Clock prescale register (CLKPR) Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 7.3 ■ 201 The Clock System of the AVR Mega Devices CLKPS[3∼0] Clock division factor 0000 1 0001 2 0010 4 0011 8 0100 16 0101 32 0110 64 0111 128 1000 256 1001∼1111 Reserved Source: Atmel Corporation, The Atmel AVR Microcontroller Table 7.2 ■ Mega device clock prescaler select The CKDIV8 fuse determines the initial value of the CLKPS bits. If the CKDIV8 fuse is unprogrammed (value is 1), the CLKPS bits resets to 0000. If the CKDIV8 fuse is programmed, CLKPS bits are reset to 0011, giving a division factor of 8 at startup. Any value can be written to the CLKPS bits regardless of the CKDIV8 fuse setting. The application software must ensure that a sufficient division factor is chosen if the selected clock source has a higher frequency than the maximum frequency of the device at the present operating conditions. The procedure to change the CKDIV8 fuse after creating a new project (when using the AVR Studio) is as follows: Source: Atmel Corporation, The Atmel AVR Microcontroller Step 1 Select toolsãAVR Programming… from the AVR Studio IDE window menu, as shown in Figure 7.4. A pop-up dialog appears, as shown in Figure 7.5, which allows the user to choose the programming tool, device, and interface. Figure 7.4 ■ Prepare to change CKDIV8 fuse Step 2 Choose the programmer (e.g., JTAGICE mkII), device (e.g., the Mega2560 on the STK600), and programming interface (JTAG); click Apply and Fuses, and the screen changes to that in Figure 7.6. The ATMega2560 demo kit without external crystal oscillator is used in this example. In Figure 7.6, the Mega2560 uses an internal RC oscillator to generate the Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 202 Chapter 7 ■ System Clock Configuration Source: Atmel Corporation, The Atmel AVR Microcontroller system clock and has 6 clock cycles of startup time. The last fuse is SUT_CKSEL, which allows the user to select the appropriate system clock source and the startup time. The user clicks the downward arrow to the right of SUT_CKSEL to bring up all the options for the clock source, as shown in Figure 7.7. ■ AVR Programming popup dialog Source: Atmel Corporation, The Atmel AVR Microcontroller Figure 7.5 Figure 7.6 ■ Default setting of the fuses (CKDIV8 is not programmed) Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. ■ 203 The Clock System of the AVR Mega Devices Source: Atmel Corporation, The Atmel AVR Microcontroller 7.3 Figure 7.7 ■ All possible clock sources and startup times Source: Atmel Corporation, The Atmel AVR Microcontroller Step 3 Figure 7.6 shows that the CKDIV8 is not programmed (without a ∨ character in the square of the value column). If we want to use the internal RC oscillator to generate clkCPU, then we should unprogram the CKDIV8 fuse. Make the change to the right of CKDIV8 and click Program, and the screen reflects the new values. Figure 7.8 ■ The fuse map for the EasyAVR1280M demo board Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 204 Chapter 7 ■ System Clock Configuration The fuse map of the EasyAVR1280M demo board is shown in Figure 7.8. The Mega device outputs the system clock on the CLKO pin. To enable the output, the CKOUT fuse in Figure 7.7 and Figure 7.8 should be programmed. The CLKO signal is used to drive other circuitry on the system. The EasyAVR1280M demo kit uses an external 7.3728 MHz crystal oscillator to generate the system clock. 7.4 Clock System of the XMega Devices The XMega device generates clock signals for internal operation from a large number of sources. The clock system, clock sources and clock distribution for the XMega device are illustrated in Figure 7.9. The XMega device utilizes a phase-locked loop (PLL) and prescalers to generate a wide range of clock frequencies. To stabilize the clock frequency, the XMega clock system implements a digital frequency locked loop (DFLL) that performs automatic run-time calibration to the internal oscillators. A crystal oscillator failure monitor can be enabled to issue a nonmaskable interrupt and switch to the internal oscillator if the external oscillator fails. Interrupts and interrupt handling are discussed in Chapter 9. Real time counter Peripherals Non-volatile memory AVR CPU RAM clkCPU clkPER clkPER2 clkPER4 clkRTC System clock prescalers Brown-out detection Watchdog timer clkSYS System clock multiplexer DIV4 32 kHz Int. ULP 32.768 kHz Int. Osc. 2 MHz Int. Osc. 32 MHz Int. Osc. XTAL 32 kHz XTAL1 XTAL2 ■ TOSC1 TOSC2 Figure 7.9 XTAL 0.4–16 MHz External clock Source: Atmel Corporation, The Atmel AVR Microcontroller PLL XMega device clock system, clock sources, and distribution Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 7.4 ■ Clock System of the XMega Devices 205 After reset, the XMega device starts operation using the 2 MHz internal oscillator. During normal operation, the system clock source and prescalers can be changed from software at any time. 7.4.1 Internal Oscillators The XMega device has four internal oscillators that serve different purposes, as described below. 32 KHZ U LT R A - L O W - P O W E R O S C I L L AT O R This oscillator provides an approximate 32 kHz clock and employs a built-in prescaler providing both a 32 kHz output and a 1 kHz output. It is automatically enabled or disabled when used as the clock source of any part of the device. It is used as the clock source for the Watchdog timer and Brown-out detection circuitry. It can also be chosen as the clock source of the real-time counter (RTC). 32.768 KHZ C A L I B R AT E D I N T E R N A L O S C I L L AT O R This RC oscillator provides a 32.768 kHz clock. A factory-calibrated value is written to the 32.768 kHz oscillator calibration register (OSC.RC32KCAL) during reset to ensure that the oscillator is running within its specification. The calibration register can also be written into from software for run-time calibration of the oscillator frequency. This oscillator employs a built-in prescaler to provide both a 32.768 kHz output and a 1.024 kHz output. 3 2 M H Z R U N - T I M E C A L I B R AT E D I N T E R N A L O S C I L L AT O R This RC oscillator provides an approximate 32 MHz clock. The oscillator employs a DFLL that can be enabled for automatic run-time calibration of the oscillator. A factory-calibrated value is written to the 32 MHz DFLL calibration registers (DFLLRC32M.CALA and DFLLRC32M.CALB) during reset to ensure that the oscillator is running within its specification. The calibration registers can also be written from software for manual run-time calibration of the oscillator. 2 M H Z R U N - T I M E C A L I B R AT E D I N T E R N A L O S C I L L AT O R This oscillator provides a 2 MHz clock. Like the 32 MHz oscillator, it also utilizes the DFLL for automatic run-time calibration. A factory-calibrated value is written into the 2 MHz DFLL calibration registers (DFLLRC2M.CALA and DFLLRC2M.CALB) during reset to ensure that the oscillator is running within its specification. The calibration register can also be written from software for manual run-time calibration of the oscillator. 7.4.2 External Clock Sources The XTAL1 and XTAL2 pins are used to drive an external oscillator, either a quartz crystal or a ceramic resonator. The TOSC1 and TOSC2 pins are dedicated to driving a 32 kHz crystal oscillator. The crystal oscillator connection is shown in Figure 7.2. 0 . 4 ~ 1 6 M H Z C R Y S TA L O S C I L L AT O R This oscillator operates in four different modes (programmed via the XOSCCTRL register), optimized for different frequency ranges, all within 0.4∼16 MHz. EXTERNAL CLOCK INPUT When an external clock signal is chosen to generate system clocks, it should be connected to the XTAL1 pin. In this mode, XTAL2 is used as a general-purpose I/O pin. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 206 Chapter 7 ■ System Clock Configuration 3 2 K H Z C R Y S TA L O S C I L L AT O R A 32 kHz crystal oscillator can be connected between the TOSC1 and TOSC2 pins by enabling a dedicated low-frequency oscillator input circuit. 7.4.3 System Clock Selection and Prescalers All the calibrated internal oscillators, the external clock sources, and the PLL output can be used as the system clock source. The system clock source is selectable from software and can be changed during normal operation. A clock source must be enabled and stable before it can be selected as the source of the system clock. The enabling or disabling of the PLL, external oscillator, and internal oscillators is controlled by the oscillator control register (OSC.CTRL). The status of each of these clock sources is recorded in the oscillator status register (OSC. STATUS). The contents of OSC.CTRL and OSC.STATUS registers are shown in Figure 7.10 and Figure 7.11, respectively. The selection of external oscillator is controlled by the external oscillator control register (OSC.XOSCCTRL) shown in Figure 7.12. The system clock is fed into a prescaler block that can divide the clock signal by a factor from 1 to 2048 before it is routed to the CPU and peripherals. The prescaler settings are changed from software during normal operation. The first stage, prescaler A, can divide by a factor from 1 to 512. The prescalers B and C can be individually configured to either pass the clock through or divide it by a factor from 1 to 4. The prescaler guarantees that derived clocks are always in phase and that no glitches or intermediate frequencies occur when changing the prescaler setting. The system clock selection and prescaler circuit is shown in Figure 7.13, where it is shown that the XMega peripheral modules may run at twice (clkPER2) or four times (clkPER4) the CPU clock frequency. The system clock selection (via the CLK.CTRL register) and prescaler registers (via the CLK.PSCTRL register) are protected by the configuration change protection mechanism, employing a timed write procedure (write 0xD8 into CPU_CCP and then write into one of these two registers within four clock cycles) for changing the system clock and prescaler settings. 6 5 4 3 — — PLLEN XOSCEN 2 1 RC32KEN RC32MEN 0 RC2MEN Reset value = 0 x 01 R R R R/W R/W R/W R/W R/W PLLEN: PLL enable 0 = PLL disabled 1 = PLL enabled. The PLL must be configured with the desired multiplication factor and input source before it is enabled. XOSCEN: External oscillator enable Setting this bit enables the external clock source selected by the XOSCCTRL register. The contents of the XOSCCTRL register are shown in Figure 7.12. RC32KEN: 32 kHz internal RC oscillator enable Setting this bit enables the 32 kHz internal RC oscillator. RC32MEN: 32 MHz internal RC oscillator enable Setting this bit enables the 32 MHz internal RC oscillator. RC2MEN: 2 MHz internal RC oscillator enable Setting this bit enables the 2 MHz internal RC oscillator. By default, the 2 MHz internal RC oscillator is enabled and this bit is set. Figure 7.10 ■ Source: Atmel Corporation, The Atmel AVR Microcontroller 7 — XMega oscillator control register (OSC.CTRL) Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 207 Clock System of the XMega Devices 7 6 5 4 — — — PLLRDY 3 2 1 0 XOSCRDY RC32KRDY RC32MRDY RC2MRDY Reset value = 0x00 R R R R R R R R PLLRDY: PLL Ready 0 = PLL is not locked on to the selected frequency. 1 = PLL has locked on to the selected frequency and is ready to be used as system clock source. XOSCRDY: External oscillator ready 0 = External clock source is not stable. 1 = External clock source is stable and ready to be used as the system clock source. RC32KRDY: 32 kHz internal RC oscillator ready 0 = The 32 kHz internal oscillator is not stable yet. 1 = The 32 kHz internal oscillator is stable and ready to be used as the system clock source. RC32MRDY: 32 MHz internal RC oscillator ready 0 = The 32 MHz internal RC oscillator is not stable yet. 1 = The 32 MHz internal RC oscillator is stable and ready to be used. RC2MRDY: 2 MHz internal RC oscillator ready 0 = The 2 MHz internal RC oscillator is not stable yet. 1 = The 2 MHz internal RC oscillator is stable and ready to be used. ■ Figure 7.11 7 XMega oscillator status register (OSC.STATUS) 6 FRQRANGE[1:0] 5 4 X32KLPM — 3 2 1 0 XOSCSEL[3:0] Reset value = 0x00 R/W R/W R/W R R/W R/W R/W R/W FRQRANGE: Crystal oscillator frequency range select See Table 6.14 X32KLPM: Crystal oscillator 32 kHz low power mode 0 = 32 kHz crystal oscillator operates in normal power mode. 1 = 32 kHz crystal oscillator operates in low power mode (reduce the swing on the TOSC2 pin). XOSCSEL[3:0]: Crystal oscillator selection See Table 6.15 ■ Figure 7.12 Source: Atmel Corporation, The Atmel AVR Microcontroller ■ Source: Atmel Corporation, The Atmel AVR Microcontroller 7.4 XMega XOSC control register (OSC.XOSCCTRL) FRQRANGE[1:0] Group configuration 00 04TO2 Frequency range 0.4 MHz ∼ 2 MHz 01 2TO9 2 MHz ∼ 9 MHz 10 9TO12 11 12TO16 9 MHz ∼ 12 MHz 12 MHz ∼ 16 MHz Recommended range for C1 and C2 (pF) 100 15 15 10 Source: Atmel Corporation, The Atmel AVR Microcontroller Table 7.3 ■ Oscillator frequency range selection Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 208 Chapter 7 ■ System Clock Configuration XOSCSEL[3:0] Group configuration Selected clock source 0000 EXTCK External clock 6 CLK 0010 32KHZ 16k CLK 0011 XTAL_256CLK(1) 32 kHz TOSC 0.4∼16 MHz XTAL (2) 0111 XTAL_1KCLK 1011 XTAL_16KCLK Startup time 256 CLK 0.4∼16 MHz XTAL 1K CLK 0.4∼16 MHz XTAL 16K CLK Notes: 1. This option should only be used when frequency stability at start-up is not important for the application. This option is not suitable for crystal. 2. This option is intended for use with ceramic resonators and will ensure frequency stability at start-up. It can also be used when the frequency stability at start-up is not important for the application. Source: Atmel Corporation, The Atmel AVR Microcontroller ■ External oscillator selection and startup time Internal 32 kHz Osc. Internal 2 MHz Osc. Internal 32 MHz Osc. ClkSYS XOSC Prescaler A 1, 2, 4, …, 512 ClkCPU Prescaler C 1, 2 Prescaler B 1, 2, 4 ClkPER Internal PLL ClkPER2 ClkPER4 ■ XMega system clock selection and prescalers 7 6 — — 5 4 3 — — — R R R R SCLKSEL[2:0]: System clock selection R 2 1 0 SCLKSEL[2:0] R/W R/W R/W SCLKSEL[2:0] Group configuration Description 000 001 010 011 100 101-111 RC2MHz RC32MHz RC32KHz XOSC PLL — 2-MHz internal RC oscillator 32-MHz internal RC oscillator 32-kHz internal oscillator External oscillator or clock Phase locked loop Reserved Figure 7.14 ■ Reset value = 0x00 Source: Atmel Corporation, The Atmel AVR Microcontroller Figure 7.13 Source: Atmel Corporation, The Atmel AVR Microcontroller Table 7.4 XMega system clock control register (CLK.CTRL) The selection of the system clock source is controlled by the system clock control register (CLK.CTRL) in the CLK module. The contents of the CLK.CTRL register are shown in Figure 7.14. The selection of prescaler factors is controlled by the system clock prescaler register (CLK. PSCTRL) shown in Figure 7.15. The user can lock the setting of the clock source and prescaler by setting the bit 0 of the clock system lock register (CLK.LOCK) shown in Figure 7.16. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 7.4 ■ 209 Clock System of the XMega Devices 7 6 5 4 — 2 3 1 0 PSBCDIV[1:0] PSADIV[4:0] R R/W R/W R/W R/W PSADIV[4:0]: Prescaler A division factor See Table 7.5 PSBDIV[1:0]: Prescaler B and C division factor See Table 7.6 R/W R/W Reset value = 0x00 R/W Source: Atmel Corporation, The Atmel AVR Microcontroller ■ Figure 7.15 XMega system clock prescaler register (CLK.PSCTRL) PSADIV[4:0] Group configuration Description 00000 1 No division 00001 2 Divide by 2 00011 4 Divide by 4 00101 8 Divide by 8 00111 16 Divide by 16 01001 32 Divide by 32 01011 64 Divide by 64 01101 128 Divide by 128 01111 256 Divide by 256 10001 512 Divide by 512 others – Reserved Source: Atmel Corporation, The Atmel AVR Microcontroller Table 7.5 ■ Prescaler A division factor PSBCDIV[1:0] Group configuration Prescaler B division Prescaler C division 00 1_1 No division No division 01 1_2 No division Divide by 2 10 4_1 Divide by 4 No division 11 2_2 Divide by 2 Divide by 2 Source: Atmel Corporation, The Atmel AVR Microcontroller Table 7.6 ■ Prescaler B and C division factor 7.4.4 PLL Circuit The XMega clock system has a PLL circuit that can multiply the frequency of the incoming clock signal by 1 to 31. It allows the user to use a low frequency crystal oscillator to generate higher frequency system clocks. Four different reference clock sources can be chosen as input to the PLL: • • 2 MHz internal oscillator 32 MHz internal oscillator divided by 4 Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. Chapter 7 ■ System Clock Configuration 7 6 5 4 3 2 — — — — — — 1 — LOCK 0 R R R R R R R R/W Reset value = 0x00 LOCK: Clock system lock When this bit is written to 1, the CTRL and PSCTRL registers cannot be changed, and the system clock selection and prescaler settings is protected against all further updates until after the next reset. This bit is protected by the configuration change protection mechanism. The user must write the value 0xD8 into the CCP register before he or she can change this register. Figure 7.16 • • ■ Source: Atmel Corporation, The Atmel AVR Microcontroller 210 XMega clock system lock register (CLK.LOCK) 0.4 MHz to 16 MHz crystal oscillator External clock To enable the PLL the following procedure must be followed: 1. Enable clock reference source. 2. Set the multiplication factor and select clock reference for the PLL. 3. Wait until the clock reference source is stable. 4. Enable PLL. The clock source selection and the setting of multiplication factor for PLL are controlled by the PLL control register (OSC.PLLCTRL). The contents of the OSC.PLLCTRL register are shown in Figure 7.17. 6 PLLSRC[1:0] R/W R/W 5 4 3 R 2 1 0 R/W R/W PLLFAC[4:0] — R/W R/W R/W PLLSRC[1:0]: Clock source PLLSRC[1:0] Group configuration PLL input source 00 01 10 11 RC2M — RC32M XOSC 2 MHz internal RC oscillator Reserved 32 MHz internal RC oscillator External clock source(1) Note: 32 kHz cannot be selected as source for the PLL. An external clock must have a frequency no lower than 0.4 MHz. PLLFAC[4:0]: Multiplication factor This field can be from 1 to 31. The output frequency from the PLL should be in a range from 10 MHz to 200 MHz. Figure 7.17 ■ Reset value = 0x00 Source: Atmel Corporation, The Atmel AVR Microcontroller 7 XMega PLL control register (OSC.PLLCTRL) 7.4.5 DFLL 2 MHz and DFLL 32 MHz The XMega device provides two built-in DFLLs to improve the accuracy of the 2 MHz and 32 MHz internal oscillator. The DFLL compares the oscillator frequency with a more accurate reference clock to do automatic run-time calibration of the oscillator. The choices for the reference clocks include these: Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 7.4 ■ 211 Clock System of the XMega Devices • • 32 kHz calibrated internal oscillator 32 kHz crystal oscillator connected to the TOSC pins The DFLLs divide the reference clock by 32 to derive a 1 kHz reference. The reference clock is individually selected for each DFLL, as shown in Figure 7.18. The DFLL must be enabled to function. If the internal oscillator runs too fast or too slow, the DFLL decrements or increments the corresponding DFLL calibration register value by 1 to adjust the oscillator frequency slightly. When the DFLL is enabled, the DFLL calibration register cannot be written from software. 32 kHz crystal osc. 32 kHz internal osc. DFLL 2 MHz Int. osc DFLL 32 MHz Int. osc Figure 7.18 ■ Source: Atmel Corporation, The Atmel AVR Microcontroller TOSC1 TOSC2 DFLL reference clock selection The DFLL for 32 MHz and 2 MHz internal oscillators belongs to the DFLLRC32M and DFLLRC2M modules, respectively. Each module has the same set of registers: • • • • • • DFLL control register (CTRL) Calibration register A (CALA) Calibration register B (CALB) Oscillator compare register 0 (COMP0) Oscillator compare register 1 (COMP1) Oscillator compare register 2 (COMP2) Setting the bit 0 of the CTRL register (DFLLRC32M.CTRL or DFLLRC2M.CTRL) enables the DFLL and auto-calibration of the internal oscillator (32 MHz or 2 MHz). The CALA and CALB registers hold the 13 bits of the DFLL calibration value that is used for automatic runtime calibration the internal oscillator. The contents of the CALA and CALB registers are shown in Figure 7.19. COMP0, COMP1, and COMP2 represent the low, middle, and high bytes of the COMP register that holds the oscillator compare value. During reset, COMP is loaded with the default value representing the ideal relationship between oscillator frequency and the 1.024 kHz reference clock. It is possible to write these bits from software and then enable the oscillator to tune to a frequency different from its normal frequency. These bits can only be written when the DFLL is disabled. The contents of COMP0∼COMP2 are shown in Figure 7.20. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. ■ System Clock Configuration 7 6 5 3 4 2 1 0 Reset value = 0x40 CALL[6:0] COMP0 R R/W R/W R/W R/W R/W R/W CALL[6:0]: DFLL calibration bits 6~0 These 7 bits are set to its middle value after reset. 7 6 5 4 3 2 1 R/W 0 Reset value = 0b00xxxxxx CALH[12:7] COMP1 R/W R/W R/W R/W R/W R/W R/W R/W CALH[12:7]: DFLH calibration bits 12~7 These 6 bits are the most significant bits of the calibration register. When the DFLL is disabled, the 13-bit calibration register can be written in the software. ■ Figure 7.19 7 XMega calibration registers A and B (CALA, CALB) 6 5 4 COMP0 R/W R/W R/W 7 6 5 COMP1 COMP2 3 2 1 0 Reset value = 0x00 COMP[7:0] R/W R/W R/W R/W 4 3 2 1 R/W R/W R/W 2 1 R/W 0 Reset value = 0x00 COMP[15:8] R/W Source: Atmel Corporation, The Atmel AVR Microcontroller Chapter 7 R/W R/W R/W 7 6 5 4 3 — — — — — R R R R R R/W 0 Reset value = 0x00 COMP[19:16] R/W R/W R/W Source: Atmel Corporation, The Atmel AVR Microcontroller 212 Figure 7.20 ■ XMega oscillator compare register 0, 1, and 2 (COMP0, COMP1, and COMP2) 7 6 5 4 3 2 — — — — — — R R R R R R 1 0 RC32MCREF RC2MCREF R/W Reset value = 0x00 R/W RC32MCREF: 32 MHz calibration reference 0 = Internal 32.768 kHz internal RC oscillator is used as calibration source of 32 MHz DFLL. 1 = External 32.768 kHz crystal oscillator is used as calibration source of 32 MHz DFLL. RC2MCREF: 2 MHz calibration reference 0 = Internal 32.768 kHz internal RC oscillator is used as calibration source of 2 MHz DFLL. 1 = External 32.768 kHz crystal oscillator is used as calibration source of 2 MHz DFLL. Figure 7.21 ■ Source: Atmel Corporation, The Atmel AVR Microcontroller The reference clock sources used by the 32 MHz and 2 MHz DFLL are selected by the DFLL control register (OSC.DFLLCTRL) in the OSC module. The contents of the OSC.DFLLCTRL register are shown in Figure 7.21. XMega DFLL control register (OSC.DFLLCTRL) Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 7.4 ■ 213 Clock System of the XMega Devices The procedure for enabling a DFLL is as follows: 1. Select internal or external clock reference with the DFLL’s control bit in the DFLL control register (OSC.DFLLCTRL). 2. Set the DFLL enable bit (ENABLE) in the control register (DFLLRC32M.CTRL or DFLLRC2M.CTRL) to 1, to enable the DFLL. 3. The calibration process starts immediately. 7.4.6 External Oscillator Failure Detector When using an external crystal or external clock source, there is always a slight probability of the source failure. As a safety precaution, the XMega clock system has an external oscillator failure detector that monitors the external clock source and reacts if it stops. If the external source is selected as the main system clock source and it fails, the failure detector switches to the internal 2 MHz RC oscillator and issues a nonmaskable interrupt. If the external source is enabled but is not selected as the main system clock source, the external source is only disabled, but the nonmaskable interrupt is still issued. The external failure detector must be enabled. To avoid accidental enabling, the user must follow a special sequence required to enable it. The procedure is as follows: 1. Load the protected I/O register signature (0×D8) into the CPU.CCP register. 2. Set the failure detection enable bit (XOSCFDEN) in the external oscillator failure detection register (OSC.XOSCFAIL) to logic one. 3. The failure detector is now enabled until the next system reset. Example 7.1 ▼ Write a subroutine to use a 16 MHz external oscillator to generate a 32 MHz clkCPU. Solution: One way to generate a 32 MHz clkCPU is to use the PLL to multiply the 16 MHz by 2 and set the prescalers A, B, and C to 1, 1, and 1. setCPUClkto32Mwith16MCrystal: ; select 16-MHz crystal as external clock source waitXOSC: waitPLL: ldi sts lds ori sts lds sbrs rjmp ldi sts lds ori sts lds sbrs tmp1,0xCB OSC_XOSCCTRL,tmp1 tmp2,OSC_CTRL tmp2,OSC_XOSCEN_bm OSC_CTRL,tmp2 tmp1,OSC_STATUS tmp1,OSC_XOSCRDY_bp waitXOSC tmp1,0xC2 OSC_PLLCTRL,tmp1 tmp1,OSC_CTRL tmp1,OSC_PLLEN_bm OSC_CTRL,tmp1 tmp1,OSC_STATUS tmp1,OSC_PLLRDY_bp; ; select external crystal with fre_range=12∼16MHz, ; startup time=16k CLKs ; enable external clock source ;" ;" ; check bit position for the skip instruction ; jump if external crystal oscillator is not ready ; select XOSC as source to PLL and set multiplying ; factor of PLL to 2 ; enable PLL ;" ;" ; wait until PLL is ready ;" Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 214 Chapter 7 ■ System Clock Configuration rjmp ldi sts ldi sts ldi sts ldi sts ret waitPLL tmp1,0xD8 CPU_CCP,tmp1 tmp1,0x04 CLK_CTRL,tmp1 tmp1,0xD8 CPU_CCP,tmp1 tmp1,0 CLK_PSCTRL,tmp1 ;" ; allow write into protected register ;" ; select PLL to generate system clock ;" ; allow write into protected register ;" ; set system clock prescale factor A,B,C ; to 0,0,0 The C language version of the function is as follows: void setCPUClkto32Mwith16MCrystal(void) { OSC.XOSCCTRL = 0xCB; // select 16-MHz external crystal as clock source OSC.CTRL |= OSC_XOSCEN_bm; // enable XOSC while(!(OSC.STATUS & OSC_XOSCRDY_bm)); // wait until XOSC is ready OSC.PLLCTRL = 0xC2; // use XOSC as input to PLL, set multiplying factor to 2 OSC.CTRL |= OSC_PLLEN_bm; // enable PLL while(!(OSC.STATUS & OSC_PLLRDY_bm)); // wait until PLL is ready CCP = 0xD8; // allow write into protected register CLK.CTRL = 0x04; // select PLL to generate system clocks CCP = 0xD8; // allow write into protected register CLK.PSCTRL = 0; // set prescaler A,B,C to 1,1,1 } ▲ Example 7.2 ▼ Write a subroutine to use the internal 32 MHz oscillator to generate a 32 MHz clkCPU. Solution: The subroutine that selects the 32 MHz internal oscillator to generate the system clock, enable DFLL auto-calibration, and set the system clock prescaler to 1,1,1 is as follows: ; ---------------------------------------------------------------------------------------------------------------------; This subroutine uses the 32-MHz internal oscillator to generate a 32-MHz ClkCPU. ; ---------------------------------------------------------------------------------------------------------------------setCPUClkto32Mwith32MIntOsc: lds ori sts wait32MIntOSC: lds sbrs rjmp ldi sts ldi r16,OSC_CTRL r16,OSC_RC32MEN_bm OSC_CTRL,r16 ; enable 32-MHz internal oscillator ;" ;" r16,OSC_STATUS r16,OSC_RC32MRDY_bp wait32MIntOsc r16,0xD8 CPU_CCP,r16 r16,0x01 ; wait until 32-MHz oscillator is ready ;" ;" ; allow configuration to change ;" ; use 32-MHz internal oscillator to generate Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 7.5 ■ 215 Summary sts ldi sts ldi sts lds ori sts lds ori sts ret CLK_CTRL,r16 r16,0xD8 CPU_CCP,r16 r16,0 CLK_PSCTRL,r16 r16,OSC_DFLLCTRL r16,OSC_RC32MCREF_bm OSC_DFLLCTRL,r16 r16,DFLLRC32M_CTRL r16,0x01 DFLLRC32M_CTRL,r16 ; system clock ; allow configuration to change ;" ; set system clock prescaler A, B, and C to 1,1,1 ;" ; use external 32.768-kHz crystal to ; calibrate the 32-MHz internal oscillator ;" ; enable DFLL ;" ;" The C language version of the function is as follows: void setCPUClkto32Mwith32MIntOsc (void) { OSC.CTRL |= OSC_RC32MEN_bm; // enable internal 32-MHz oscillator while(!(OSC.STATUS & OSC_RC32MRDY_bm)); // wait until 32-MHz is ready CCP = 0xD8; // allow configuration to change CLK.CTRL = 1; // use internal 32-MHz oscillator to generate system clock CCP = 0xD8; // allow configuration to change CLK.PSCTRL= 0; // set system clock prescaler A, B, C to 1,1,1 OSC.DFLLCTRL = 0x00; // use external 32.768-kHz oscillator to auto-calibrate 32-MHz DFLL DFLLRC32M.CTRL |= 0x01; // enable 32-MHz DFLL } ▲ 7.5 Summary We have learned that a clock signal is needed to synchronize and pace the instruction execution in Chapter 1. We also have learned how to create time delays using program loops in Chapter 3. In addition to the CPU, all peripheral modules also need clock signals to control their operations. The embedded system designer has the choice of using a ceramic resonator, a crystal oscillator, or an RC circuit (on-chip or off-chip) to generate the system clock. The system clock is a periodic square wave with roughly 50% duty cycle. The output signal from a ceramic resonator, a crystal oscillator, or an RC circuit is not a square wave and must be squared up before it can be used. In addition, the frequency of the output of a ceramic resonator or a crystal oscillator need not be the same as the system clock. Circuit techniques are used to multiply the frequency of the clock signal generated by the ceramic resonator, the crystal oscillator, or an RC circuit. All MCUs include a clock module to configure the clock input source properly and distribute the generated clock signals to all of the modules that need them. Both the Mega and XMega provide on-chip RC oscillators as possible sources for the system clock. These on-chip oscillators can be calibrated to become more accurate. A Mega device relies on fuse programming to select the clock generation method. However, the XMega clock generation is completely controlled by the software program. The XMega’s clock system also Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 216 Chapter 7 ■ System Clock Configuration includes a PLL circuit that can multiply the chosen clock signal’s frequency so that a higher frequency clock signal can be generated from an internal RC or external crystal oscillator with a lower frequency. 7.6 Exercises E7.1 What is the default system clock source of the Mega device after reset, and what is the default frequency of clkCPU? E7.2 What is the default system clock source for the XMega devices after reset? E7.3 Write an assembly subroutine to use an 8 MHz external oscillator to generate a 32 MHz clkCPU for the XMega device. E7.4 Write a C function to use an 8 MHz external oscillator to generate a 32 MHz clkCPU for the XMega device. E7.5 Write an assembly subroutine that uses the internal 2 MHz oscillator to generate system clocks so that the frequency of clkCPU is 32 MHz. E7.6 Write a C function that uses the internal 2 MHz oscillator to generate system clocks so that the frequency of clkCPU is 32 MHz. E7.7 Write an assembly subroutine that uses the external 4 MHz crystal to directly generate the clkSYS and configure the prescaler properly so that clkCPU frequency is set to 32 MHz. E7.8 Write a C function that uses the external 8 MHz crystal oscillator to directly generate the clkSYS and configure the prescaler properly so that clkCPU frequency is set to 32 MHz. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 8 Parallel I/O 8.1 Objectives After completing this chapter, you will be able to • Explain the I/O addressing issue. • Explain I/O synchronization methods. • Verify voltage compatibility when interfacing a microcontroller with peripheral devices. • Verify current compatibility when driving peripheral devices. • Turn LEDs on and off. • Input data from the DIP switches. • Use seven-segment displays to display decimal numbers and a small set of English letters. • Use the I/O pin to generate waveform and make sound. • Write programs to generate waveforms using a D/A converter Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 218 Chapter 8 ■ Parallel I/O 8.2 I/O Introduction to I/O PORTs The term PORT is often used with I/O functions. An I/O PORT consists of a group of pins (often eight) and a set of registers including data registers (or latch), data direction register, and control register(s) (optional). An I/O PORT is often bidirectional in the sense that it can output and input data at different times. The directions of I/O pins are established by programming the data direction register. The data register (or latch) allows the I/O pins to maintain their voltage levels if the application program does not change them. Some I/O PORTs may have more sophisticated functions and hence require one or more control registers for their configuration. The I/O PORT allows the user to interface with I/O devices, such as dual-inline-package (DIP) switches, keypads, keyboards, light-emitting diodes (LEDs), seven-segment displays, liquid crystal displays (LCDs), stepper motors, D/A converters, and so on. I/O devices are also called peripheral devices in the sense that they are outside the core of a computer system. 8.2.1 I/O Addressing Issue When performing I/O operations, the CPU deals directly with the I/O PORT registers. This involves two issues: • Address space. This issue is related to the question of whether I/O devices should be treated the same as memory devices, that is, whether the I/O registers should occupy the same address space (some people like to call it memory space) as the memory devices (SRAM, DRAM, EEPROM, or flash memory) or have a separate address space. Both approaches have been used by microprocessor and microcontroller vendors. The current trend is for I/O devices and memory components to share the same address space. • Addressing Modes and Instructions. I/O devices may have their own addressing modes and instruction set or share the same addressing modes and instruction set with the memory devices. The AVR Mega devices have a dedicated I/O space that contains 64 locations (bytes) from 0x20 to 0x5F. These 64 bytes hold control registers, stack pointer, and other I/O registers. The user accesses these registers, using the I/O instructions listed in Table 8.1. These I/O registers are also accessed as data space locations, using LD/LDS/LDD and ST/STS/STD instructions. For those Mega devices (Mega640/1280/1281/2560/2561) with more than 64 I/O registers, an extended I/O space that spans from 0x60 to 0x1FF is added. I/O registers located in this range are only accessed using the LD/LDS/LDD and ST/STS/STD instructions. The user can use direct, indirect with displacement, indirect, indirect with pre-decrement, and indirect with post-increment addressing modes to specify an I/O register. For the XMega devices, all I/O registers reside in the lowest 4096 addresses of the data memory. This is referred to as the I/O memory space. The lowest 64 addresses are accessed directly using the I/O instructions listed in Table 8.1, or as the data space locations from 0x00 to 0x3F. The rest is the extended I/O memory space, ranging from 0x40 to 0x0FFF. I/O registers here must be accessed as data space locations, using load (LD/LDS/LDD) and store (ST/STS/ STD) instructions. Atmel assigns a symbolic name to each I/O register so that the user can use it to access any I/O register. Using the symbolic name to refer to an I/O register makes your program more readable. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 8.2 ■ 219 I/O Introduction to I/O PORTs Mnemonic Description Operation in Rd, A Input from I/O location Rd ← I/O(A) out A, Rr Output to I/O location I/O(A)1 ← Rr sbic A, b Skip if bit in I/O register is zero If(I/O(A, b)2 5 0) then PC d PC 1 2 or 3 sbis A, b Skip if bit in I/O register is one If(I/O(A, b)2 5 1) then PC d PC 1 2 or 3 sbi A, b Set bit in I/O register I/O(A, b)2 ← 1 cbi A, b Clear bit in I/O register I/O(A, b)2 ← 0 1 Notes: 1. I/O(A) refers to I/O space at address A. 2. I/O(A, b) refers to bit b of the I/O register at address A (0x00 to 0x1F). Source: Atmel Corporation, The Atmel AVR Microcontroller Table 8.1 ■ AVR I/O Instructions 8.2.2 I/O Synchronization As described in Section 1.5, microprocessors either cannot provide the current required by the peripheral devices or operate at a voltage level different from those of peripheral devices. Therefore, they usually communicate with peripheral devices via interface chips. For the microcontroller, the functions of most of these interface chips and the CPU are built into the same chip. When transferring data in the parallel format (multiple bits at a time), the microcontroller reads and writes data through the parallel PORT. When transferring data in the serial format (one bit in one clock cycle), the microcontroller reads and writes data through the serial interface such as a universal synchronous asynchronous receiver and transceiver (USART), serial peripheral interface (SPI), inter-integrated circuit (I2C), or controller area network (CAN). Because data transfers go through the interface chip (or logic for the MCU), the synchronization issue occurs in two places. One is between the processor and the interface chip (or logic for the MCU). The other is between the interface chip (or logic for the MCU) and the peripheral devices. 8.2.3 Synchronization Issue for Parallel PORTs The design of parallel PORTs of today’s microcontrollers (including the AVR Mega and XMega) is to allow the data written into the data register to appear on the output pins directly and allow the read operation from the data register to obtain the instantaneous voltage levels on the input PORT pins. There is no concern about the synchronization issue. This is quite different from the era of microprocessors. To perform an I/O operation, the microprocessor needs to make sure that interface chip for the input device has new data before it reads it or that the interface chip for the output device can handle new data before it sends new data to it. This is achieved by either polling or interrupt. The interface chip is designed to have status flags to indicate whether it has new data or can accept new data for output. The interface chip may use a strobe signal or handshake signals to achieve synchronization between the interface chip and the peripheral device. This type of synchronization is no longer needed in today’s microcontrollers. 8.2.4 Synchronization Issue for Serial Interface For the serial interface, the data transfer rate between the processor and the interface logic is much faster than that between the interface logic and the peripheral device. The processor needs to make sure that there is new data in the interface logic (usually held in a data register) Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 220 Chapter 8 ■ Parallel I/O before reading it. It also has to make sure that the interface logic can handle more data before sending new data to it. This is achieved by using either the polling or the interrupt method to make sure that the new I/O operation can be started. The synchronization between the interface logic and the peripheral device is achieved by following certain data transfer protocols. For example, the interface logic and the peripheral device use the same clock signal to synchronize data transfer in the synchronous protocol. The SPI and I2C module use this approach. For data transfers that use asynchronous protocol, both the transmitter and receiver agree on a common data transfer rate, and the receiver uses a sampling clock signal with a frequency that is a multiple (16, 32, or 64) of the data rate to detect the incoming data. This is used in the USART module. 8.3 I/O Pin Driving Circuit Structure The internal logic values of the microcontroller drive the I/O pins through driving circuits. There are several possible driving circuit configurations: totem pole, bus keeper, wired-OR, and wire-AND. 8.3.1 Totem Pole DIRn Pn OUTn INn Figure 8.1 ■ Source: Atmel Corporation, The Atmel AVR Microcontroller The totem-pole circuit configuration is illustrated in Figure 8.1. When a pin is configured for totem pole (push–pull), the pin is driven high or low, according to the corresponding bit setting in the OUT register. In this configuration, there is no current limitation for sink or source other than what the pin is capable of. If the pin is configured for input, the pin floats if no external pulling circuit (pull-up or pull-down) is connected. The input circuit (driver of the INn signal) is a Schmidt trigger circuit that can square up the slow-rising input signal to a sharp-rising output signal. Totem pole block diagram There are two variations for the totem-pole driving circuit. One version has a pull-down circuit, whereas the other version has a pull-up. TOTEM POLE WITH PULL-DOWN The circuit of this version of the totem pole is shown in Figure 8.2. The pin Pn is configured for input or output, depending on whether the DIRn signal is driven to 0 or 1. The pull-down resistor is enabled when the pin is configured for input. The nth bit (INn) of the IN register holds the instantaneous values of the I/O pin Pn. When the Pn pin is configured for input and is not driven, it is pulled to low by the RPD resistor. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. ■ 221 I/O Pin Driving Circuit Structure DIRn Pn OUTn RPD INn Figure 8.2 TOTEM POLE WITH ■ Source: Atmel Corporation, The Atmel AVR Microcontroller 8.3 Totem pole with pull-down PULL-UP DIRn RPU Pn OUTn INn Figure 8.3 ■ Source: Atmel Corporation, The Atmel AVR Microcontroller The circuit of this version of totem pole is shown in Figure 8.3. When the pin is configured for input, the pull-up resistor is enabled. The rectangle containing the word RPU is the pull-up resistor. When the input pin is not driven, the voltage at the input pin is pulled up to high by the RPU resistor. Totem pole with pull-up (on input) 8.3.2 Bus Keeper The bus-keeper configuration is shown in Figure 8.4. When the I/O pin driver circuit is configured to bus-keeper mode, it provides a weak bus keeper that keeps the pin at its logic level when the pin is no longer driven to any logic state. If the last level on the pin/bus was 1, the bus keeper uses the internal pull resistor to keep the bus high. If the last logic level on the pin/bus was 0, the bus keeper uses the internal pull resistor to keep the bus low. The bus keeper’s weak output produces the same logical level as the last output level. It acts as a pull-up if the last level was 1, and pull-down if the last level was 0. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 222 Chapter 8 ■ Parallel I/O Pn OUTn INn Figure 8.4 ■ Source: Atmel Corporation, The Atmel AVR Microcontroller DIRn Totem pole with bus keeper 8.3.3 Wired-OR OUTn Pn RPD INn Figure 8.5 ■ Source: Atmel Corporation, The Atmel AVR Microcontroller The circuit for the wired-OR configuration is shown in Figure 8.5. With the wired-OR configuration, the pin is driven high when the corresponding bit in the OUT register is written to 1. When a bit of the OUT register is set to 0, the corresponding pin is not driven and can be pulled low with the internal or an external pull-resistor. An internal pull-down is shown in Figure 8.5. Wire-OR with optional pull-down 8.3.4 Wired-AND The circuit of the wired-AND configuration is shown in Figure 8.6. With the wired-AND configuration, the Pn pin is driven low when the corresponding bit in the OUT register is written to 0. When OUTn is set to 1, the Pn pin is released, allowing the pin to be pulled high with the internal or an external pull-up resistor. If an internal pull-up resistor is used, this is also active if the pin is set as input. 8.4 Electrical Characteristic Consideration for I/O Interfacing Most embedded systems require the use of logic chips, peripheral devices in addition to the microcontroller, to perform their function. Because these chips may use different types of integrated circuit (IC) technologies, there is a concern that the resultant embedded system may not function properly. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. ■ 223 Electrical Characteristic Consideration for I/O Interfacing INn RPU Pn OUTn Figure 8.6 ■ Source: Atmel Corporation, The Atmel AVR Microcontroller 8.4 Wire-AND with optional pull-up The major concern in interfacing IC chips that are made with different technologies is whether they are electrically compatible. There are two issues involved in electrical compatibility: • Voltage-level compatibility. Is the high output level of an IC chip high enough to be considered as a high for the input of another IC chip? Is the low output level of an IC chip low enough to be considered as a low for the input of another IC chip? • Current drive capability. Does the output of an IC chip have enough current to drive its load? Can the output circuit of an IC chip sink the currents of its load? Signal timing is also an important factor for making sure that the digital circuit functions correctly. The main concern about timing is whether the signal from one chip becomes valid early enough to be used by other chips. This is a timing compatibility issue. When the operating frequency becomes very high, the transmission line effect and ground bounce effect must be considered too. However, we are not dealing with high-frequency systems in this text, so these two issues are not discussed. 8.4.1 Voltage-Level Compatibility There are many IC technologies in use today. Some of them are bipolar; others are unipolar. A bipolar IC technology has both the electron and hole currents in any moment. However, in a unipolar IC technology, the current in any part of the circuit is either the electron current or the hole current. The unipolar CMOS technology is the dominant IC technology in use today. The voltage-level compatibility issue arises because IC technologies differ in the following four voltages: • Input high voltage (VIH). This is the voltage level that is treated as a logic 1 when applied to the input of a digital circuit. • Input low voltage (VIL). This is the voltage level that is treated as a logic 0 when applied to the input of a digital circuit. • • This is the voltage level when a digital circuit outputs a logic 1. Output low voltage (VOL). This is the voltage level when a digital circuit outputs a logic 0. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 224 ■ Chapter 8 Parallel I/O In order for the digital circuit X to be able to drive circuit Y correctly, the following conditions must be satisfied: • VOHX ê VIHY (the output high voltage of circuit X must be higher than or equal to the input high voltage of circuit Y). The difference between VOH and VIH of the same technology is referred to as the noise margin high (NMH). • VOLX Ä VILY (the output low voltage of circuit X must be lower than or equal to the input low voltage of circuit Y). The difference between VIL and VOL of the same technology is referred to as the noise margin low (NML). The input and output voltage levels of a few popular logic families are listed in Table 8.2, from which one can draw the following conclusions: • There is no problem using the CMOS logic chip to drive the bipolar logic chip at the same power supply level. • The AVR Mega has no problem driving the CMOS logic chip and being driven by the CMOS logic chip at the same power supply level. • The BiCMOS logic is not suitable for driving the AVR Mega and other CMOS logic chips at the same power supply level. • The bipolar logic ICs are not suitable for driving the CMOS logic ICs or the AVR microcontroller at the same power supply level. Logic family 3 AVR Mega AVR XMega6 S4 LS4 4 VDD VIH VOH VIL VOL 5V 3.0 V 4.2 V 1.5 V 0.9 V 2.4,3.6 V 0.7 VCC VCC2 0.3 V7 0.3 VCC 0.45 V8 5V 2V 3.0,3.4 V1 0.8 V 0.4,0.5 V2 5V 2V 3.0,3.4 V1 0.8 V 0.4,0.5 V2 1 AS 5V 2V 3.0,3.4 V 0.8 V 0.35 V F4 5V 2V 3.4 V 0.8 V 0.3 V HC 3 5V 3.5 V 4.9 V 1.5 V 0.1 V 3 5V 3.5 V 4.9 V 1.5 V 0.1 V ACT3 5V 2V 4.9 V 0.8 V 0.1 V 5 5V 2V 3V 0.8 V 0.55 V BCT5 5V 2V 3.3 V 0.8 V 0.42 V 5 5V 2V 2.4 V 0.8 V 0.55 V HCT ABT FCT Notes: 1. VOH value will get lower when output current is larger. 2. VOL value will get higher when output current is larger. The VOL values of different logic gates are slightly different. 3. AVR Mega, XMega, HC, HCT, and ACT are based on the CMOS technology. 4. S, LS, AS, and F logic families are based on the bipolar technology. 5. ABT, BCT, and FCT use the BiCMOS technology. 6. XMega MCU can operate with VCC from 2.4~3.6 V or 1.6~2.4 V. 7. This is a typical value. 8. This is also a typical value. Source: Atmel Corporation, The Atmel AVR Microcontroller Table 8.2 ■ Input and output voltage levels of common logic families Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 8.4 ■ Electrical Characteristic Consideration for I/O Interfacing 225 The CMOS is the most widely used semiconductor technology. The power supply of the CMOS technology can be in a wide range. As a result, the VIH and VIL are not a single value. However, we can use 0.7 VCC and 0.3 VCC (VCC is the power supply) as an estimate of the VIH and VIL. 8.4.2 Current Drive Capability A microcontroller needs to drive other peripheral I/O devices in an embedded system. The second electrical compatibility issue is whether the microcontroller can supply (when the output voltage is high, also called source) or sink (when the output voltage is low) the current needed by the I/O devices that it interfaces with. Depending upon the voltage level of an output pin, the current may flow out from (supply the current) or into (sink the current) the pin. The designer must make sure that the following two requirements are satisfied: • Each I/O pin can supply (flowing out from the pin) and sink (flowing into the pin) the current needed by the I/O devices that it interfaces with. For example, each of the AVR Mega device I/O pins can source and sink 40 mA. • The total current required to drive I/O devices does not exceed the maximum current rating of the microcontroller. For example, the total DC current that an AVR Mega device can supply is 200 mA. Each logic chip has the following four currents that are involved in the current drive calculation: • Input high current (IIH). This is the input current (flowing into the input pin) when the input voltage is high. • Input low current (IIL). This is the input current (flowing out of the input pin) when the input voltage is low. • Output high current (IOH). This is the output current (flowing out of the output pin) when the output voltage is high. • Output low current (IOL). This is the output current (flowing into the output pin) when the output voltage is low. The current capabilities of several common logic families and the AVR Mega and XMega devices are listed in Table 8.3. In the CMOS technology, the gate terminal (one of the three terminals in an N- or P-transistor) draws a significant current only when they are being charged up toward VCC or pulled down toward GND level. After that, the gate terminal draws only leakage currents. Bipolar technology is different from the CMOS technology in that a DC current always flows into or out of the base terminal of the transistor of a bipolar logic chip. To determine whether a pin can supply and sink currents to all the peripheral pins that it drives directly, the designer needs to check the following two requirements: 1. The IOH of an I/O pin of the microcontroller is equal to or greater than the sum of currents flowing into all peripheral pins that are connected directly to the microcontroller I/O pins. 2. The IOL of an I/O pin of the microcontroller is equal to or greater than the sum of currents flowing out of all peripheral pins that are connected directly to the microcontroller I/O pins. In addition, the designer must also make sure that the total current needed to drive the peripheral signal pins does not exceed the total current that the microcontroller can supply. One question that arises here is what should be done if an I/O pin cannot supply (or sink) the current needed to drive the peripheral pins? A simple solution is to add buffer chips Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 226 Chapter 8 ■ Parallel I/O Logic family VCC IIH IIL IOH IOL 5V 1 µA 1 µA 40 mA 40 mA4 AVR XMega 2.4,3.6 V 1 µA 1 µA 20 mA 20 mA5 S 5V 50 µA 1.0 mA 15 mA 24 mA AVR Mega 23 LS 5V 20 µA 0.2 mA 15 mA 24 mA AS 5V 20 µA 1 mA 15 mA 64 mA F 5V 20 µA 1 mA 15 mA 64 mA HC3 5V 1 µA 1 µA 25 mA 25 mA 3 HCT 5V 1 µA 1 µA 25 mA 25 mA ACT3 5V 1 µA 1 µA 24 mA 24 mA 3 ABT 5V 1 µA 1 µA 32 mA 64 mA BCT 5V 20 µA 1 mA 15 mA 64 mA 3 5V 1 µA 1 µA 15 mA 64 mA FCT Notes: 1. Values are based on the 74xx244 of Texas Instrument (xx is the technology name). 2. The total supply currents of AVR Mega and XMega are 200 mA and 200 mA. 3. The values for IIH and IIL are maximum input leakage currents. 4. The AVR Mega power supply has ranges 1.8,2.4 V and 2.4,5.5 V. 5. The AVR XMega power supply has two ranges 1.6,2.4 V and 2.4,3.6 V. Source: Atmel Corporation, The Atmel AVR Microcontroller Table 8.3 ■ Current capabilities of common logic families1 (for example, 74ABT244) that can supply enough current between the microcontroller and the peripheral chips. This technique is widely used in microcontroller applications and is illustrated in several examples in this chapter. 8.4.3 Timing Compatibility D thd Q D tsu CLK CLK Q (a) Figure 8.7 ■ (b) Source: Atmel Corporation, The Atmel AVR Microcontroller If an I/O pin is driving a peripheral pin that does not contain latches or flip-flops, then timing is not an issue. A latch or flip-flop usually has a control signal or clock signal to control the latching of an input signal. As illustrated in Figure 8.7, the D input to the D flip-flop must be valid for tsu ns before the rising edge of the CLK signal and remain valid for at least thd ns after the rising edge of the CLK signal in order for its value to be correctly copied to the output signal Q. The timing parameters tsu and thd are referred to as the setup and hold time requirements of the D flip-flop and its latching timing requirement Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 8.5 ■ 227 Overview of the AVR Mega Parallel PORTs D flip-flop. The main timing consideration is that the setup- and hold-time requirements for all latches and flip-flops in a digital system must be satisfied in order for the system to work correctly. A signal may pass through several intermediate chips before it is used by the final latch or flip-flop. The time delays of all intermediate devices must be added when considering the timing analysis. Timing requirement analysis can be very complicated and is best illustrated using examples. 8.5 Overview of the AVR Mega Parallel PORTs Source: Atmel Corporation, The Atmel AVR Microcontroller An AVR Mega MCU may have up to 11 parallel PORTs (PORTA, PORTB, …, PORTL [there is no PORTI]). Each PORT has true read-modify-write functionality; that is, the user can change the direction or value of any individual pin without affecting other pins by using the SBI or CBI instruction. Each PORT has symmetrical drive characteristics with both high sink and source capability. The pin driver is strong enough to drive an LED display directly. All PORT pins have individually selectable pull-up resistors with a supply-voltage invariant resistance. All I/O pins have protection diodes to both VCC and Ground, as indicated in Figure 8.8, to prevent the chip from being damaged by static. RPU Pxn Logic Figure 8.8 ■ I/O pin protection diodes Three I/O memory locations are allocated for each PORT, one each for the data register (PORTx), data direction register (DDRx), and the PORT input register (PINx). The letter x represents one of the letters in {A, B, C, D, E, F, G, H, J, K, and L}. The contents of these three registers are shown in Figures 8.9 through 8.11. The PINx register is read-only, whereas PORTx and DDRx are read/writable. However, writing a 1 to a bit in the PINx register causes the corresponding bit in the PORTx register to toggle. In addition, the pull-up resistors of all pins of all PORTs can be disabled by setting the PUD bit in the MCUCR register. 7 6 5 4 3 2 1 0 PORTx7 PORTx6 PORTx5 PORTx4 PORTx3 PORTx2 PORTx1 PORTx0 R/W R/W R/W R/W R/W R/W R/W R/W Reset value = 0x00 Source: Atmel Corporation, The Atmel AVR Microcontroller Figure 8.9 ■ PORTx data register (PORTx, x 5 A, B, C, D, E, F, G, H, J, K, or L) Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 228 Chapter 8 ■ Parallel I/O 7 6 5 4 3 2 1 0 DDx7 DDx6 DDx5 DDx4 DDx3 DDx2 DDx1 DDx0 R/W R/W R/W R/W R/W R/W R/W R/W Reset value = 0x00 Source: Atmel Corporation, The Atmel AVR Microcontroller Figure 8.10 ■ PORTx data direction register (DDRx, x 5 A, B, C, D, E, F, G, H, J, K, or L) 7 6 5 4 3 2 1 0 PINx7 PINx6 PINx5 PINx4 PINx3 PINx2 PINx1 PINx0 R/W R/W R/W R/W R/W R/W R/W R/W Reset value = NA Source: Atmel Corporation, The Atmel AVR Microcontroller Figure 8.11 ■ PORTx input pins register (PINx, x 5 A, B, C, D, E, F, G, H, J, K, or L) 8.5.1 Configuring the Mega I/O Pins The DDxn bit in the DDRx register selects the direction of the Pxn pin. The Pxn pin is configured as an output if the DDxn bit in the DDRx register is 1. If the DDxn bit is cleared to 0, the Pxn pin is configured as an input. If the PORTxn bit of the PORTx register is written to 1 when the pin is configured for input, the pull-up resistor is activated. By writing a 0 to the PORTxn bit or configuring the pin for output, the pull-up resistor is disabled. The PORT pins are tri-stated when reset condition becomes active, even if no clocks are running. If the PORTxn bit is written to 1 when the associated pin is configured for output, the Pxn pin is driven high. If the PORTxn bit is written to 0 when the Pxn pin is configured for output, the Pxn pin is driven low. 8.5.2 Toggling the Mega I/O Pin An I/O pin can be toggled by writing a 1 to the PINxn bit, independent of the value of the DDRxn bit of the DDRx register. The SBI instruction can be used to perform this operation. 8.5.3 Reading the Pin Value Independent of the setting of the data direction bit DDxn, the PORT pin can be read through the PINxn bit of the PINx register. Example 8.1 ▼ Write a sequence of instructions and C statements to configure PORTD for output and output the value 0x49 to it. Solution: The following instructions perform the specified operations: .include … ldi out ldi out ,m2560def.inc. ; or include file of other Mega devices r16,0xFF DDRD,r16 r16,0x49 PORTD,r16 ; configure PORTD for output ; " ; output the value 0x49 to PORTD ; " Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 8.5 ■ Overview of the AVR Mega Parallel PORTs 229 The following C statements perform the same operations: #include … DDRD PORTD ,avr\io.h. 5 0xFF; 5 0x49; ▲ Example 8.2 ▼ Write a sequence of instructions and C statements to configure PORTB for input, read the value of PORTB, and save it in data memory location at 0x1000. Solution: The following instructions perform the specified operations: .include … clr out in st ,m2560def.inc. r16 DDRB,r16 r17,PINB 0x1000,r17 ; configure PORTB for input ; " ; read the current PORTB value ; store the value of PORTB in memory location at 0x1000 The following C statements perform the same operations: #include ,avr\io.h. … char *ptr; ptr 5 0x1000; … DDRB 5 0x00; *ptr 5 PINB; // use ptr to point to memory location at 0x1000 // configure PORTB for input // read PORTB value and store it in memory location at 0x1000 ▲ 8.5.4 Unconnected Pins If some pins are unused, it is recommended to ensure that these pins have a defined level. Even though most of the digital inputs are disabled in the deep sleep modes, floating inputs should be avoided, to reduce current consumption in all other modes where the digital inputs are enabled (reset, active mode, and idle mode). The simplest method to ensure a defined level of an unused pin is to enable the internal pull-up. In this case, the pull-up is disabled during reset. If low power consumption during reset is important, it is recommended to use an external pull-up or pull-down. Connecting unused pins directly to VCC or GND is not recommended because this may cause excessive currents if the pin is accidentally configured as an output. 8.5.5 Alternate PORT Functions Most PORT pins have alternate functions in addition to being general digital I/Os. The alternate pin functions for each PORT are listed in Tables 8.4 through 8.15. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 230 Chapter 8 ■ Parallel I/O PORT pin Alternate function PA7 AD7 (external memory interface address and data bit 7) PA6 AD6 (external memory interface address and data bit 6) PA5 AD5 (external memory interface address and data bit 5) PA4 AD4 (external memory interface address and data bit 4) PA3 AD3 (external memory interface address and data bit 3) PA2 AD2 (external memory interface address and data bit 2) PA1 AD1 (external memory interface address and data bit 1) PA0 AD0 (external memory interface address and data bit 0) Source: Atmel Corporation, The Atmel AVR Microcontroller Table 8.4 ■ PORTA pins alternate functions PORT pin Alternate function PB7 OC0A/OC1C/PCINT7 (output compare and PWM output A for Timer/Counter0, output compare and PWM output C for Timer/Counter 1 or pin change interrupt 7) PB6 OC1B/PCINT6 (output compare and PWM output B for Timer/Counter1 or pin change interrupt 6) PB5 OC1A/PCINT5 (output compare and PWM output A for Timer/Counter1 or pin change interrupt 5) PB4 OC2A/PCINT4 (output compare and PWM output A for Timer/Counter2 or pin change interrupt 4 PB3 MISO/PCINT3 (SPI bus master input/slave output or pin change interrupt 3) PB2 MOSI/PCINT2 (SPI bus master output/slave input or pin change interrupt 2) PB1 SCK/PCINT1 (SPI bus serial clock or pin change interrupt 1) PB0 SS/PCINT0 (SPI slave select input or pin change interrupt 0) Source: Atmel Corporation, The Atmel AVR Microcontroller Table 8.5 ■ PORTB pins alternate functions PORT pin Alternate function PC7 A15 (External memory interface address bit 15) PC6 A14 (External memory interface address bit 14) PC5 A13 (External memory interface address bit 13) PC4 A12 (External memory interface address bit 12) PC3 A11 (External memory interface address bit 11) PC2 A10 (External memory interface address bit 10) PC1 A9 (External memory interface address bit 9) PC0 A8 (External memory interface address bit 8) Source: Atmel Corporation, The Atmel AVR Microcontroller Table 8.6 ■ PORTC pins alternate functions Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 8.5 ■ Overview of the AVR Mega Parallel PORTs PORT pin 231 Alternate function PD7 T0 (Timer/Counter0 clock input) PD6 T1 (Timer/Counter1 clock input) PD5 XCK1 (USART1 external clock input/output) PD4 ICP1 (Timer/Counter1 input capture trigger) PD3 INT3/TXD1 (External interrupt 3 input or USART1 transmit pin) PD2 INT2/RXD1 (External interrupt 2 input or USART1 receive pin) PD1 INT1/SDA (External interrupt 1 input or TWI serial data) PD0 INT0/SCL (External interrupt 0 input or TWI serial clock) Source: Atmel Corporation, The Atmel AVR Microcontroller Table 8.7 ■ PORTD pins alternate functions PORT pin Alternate function PE7 INT7/ICP3/CLKO (External interrupt 7 input, Timer/Counter3 input capture trigger or divided system clock PE6 INT6/T3 (External interrupt 6 input or Timer/Counter3 clock input) PE5 INT5/OC3C (External interrupt 5 input or output compare and PWM output C for Timer/Counter3) PE4 INT4/OC3B (External interrupt 4 input or output compare and PWM output B for Timer/Counter3) PE3 AIN1/OC3A (Analog comparator negative input 1 or output compare and PWM output A for Timer/Counter3) PE2 AIN0/XCK0 (Analog comparator positive input 0 or USART0 external clock) PE1 PDO/TXD0 (Programming data output or USART0 transmit pin) PE0 PDI/RXD0/PCINT8 (Programming data input, USART0 receive pin or pin change interrupt 8) Source: Atmel Corporation, The Atmel AVR Microcontroller Table 8.8 ■ PORTE pins alternate functions PORT pin Alternate function PF7 ADC7/TDI (ADC input channel 7 or JTAG test data input) PF6 ADC6/TDO (ADC input channel 6 or JTAG test data output) PF5 ADC5/TMS (ADC input channel 5 or JTAG test mode select) PF4 ADC4/TCK (ADC input channel 4 or JTAG test clock) PF3 ADC3 (ADC input channel 3) PF2 ADC2 (ADC input channel 2) PF1 ADC1 (ADC input channel 1) PF0 ADC0 (ADC input channel 0) Source: Atmel Corporation, The Atmel AVR Microcontroller Table 8.9 ■ PORTF pins alternate functions Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 232 Chapter 8 ■ Parallel I/O PORT pin Alternate function PG5 OC0B (output compare and PWM output B for Timer/Counter0) PG4 TOSC1 (RTC oscillator Timer/Counter 2) PG3 TOSC2 (RTC oscillator Timer/Counter 2) PG2 ALE (Address latch enable to external memory) PG1 RD (Read strobe to external memory) PG0 WR (Write strobe to external memory) Source: Atmel Corporation, The Atmel AVR Microcontroller Table 8.10 ■ PORTG pins alternate functions PORT pin Alternate function PH7 T4 (Timer/Counter4 clock input) PH6 OC2B (Output compare and PWM output B for Timer/Counter2) PH5 OC4C (Output compare and PWM output C for Timer/Counter4) PH4 OC4B (Output compare and PWM output B for Timer/Counter4) PH3 OC4A (Output compare and PWM output A for Timer/Counter4) PH2 XCK2 (USART2 external clock) PH1 TXD2 (USART2 transmit pin) PH0 RXD2 (USART2 receive pin) Source: Atmel Corporation, The Atmel AVR Microcontroller Table 8.11 PORT pin ■ PORTH pins alternate functions Alternate function PJ7 -- PJ6 PCINT15 (Pin change interrupt 15) PJ5 PCINT14 (Pin change interrupt 14) PJ4 PCINT13 (Pin change interrupt 13) PJ3 PCINT12 (Pin change interrupt 12) PJ2 XCK3/PCINT11 (USART3 external clock or pin change interrupt 11) PJ1 TXD3/PCINT10 (USART3 transmit pin or pin change interrupt 10) PJ0 RXD3/PCINT9 (USART3 receive pin or pin change interrupt 9) Source: Atmel Corporation, The Atmel AVR Microcontroller Table 8.12 ■ PORTJ pins alternate functions Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 8.6 ■ 233 Overview of AVR XMega Parallel PORTs PORT pin Alternate function PK7 ADC15/PCINT23 (ADC input channel 15 or pin change interrupt 23) PK6 ADC14/PCINT22 (ADC input channel 14 or pin change interrupt 22) PK5 ADC13/PCINT21 (ADC input channel 13 or pin change interrupt 21) PK4 ADC12/PCINT20 (ADC input channel 12 or pin change interrupt 20) PK3 ADC11/PCINT19 (ADC input channel 11 or pin change interrupt 19) PK2 ADC10/PCINT18 (ADC input channel 10 or pin change interrupt 18) PK1 ADC9/PCINT17 (ADC input channel 9 or pin change interrupt 17) PK0 ADC8/PCINT16 (ADC input channel 8 or pin change interrupt 16) Source: Atmel Corporation, The Atmel AVR Microcontroller Table 8.13 ■ PORTK pins alternate functions PORT pin Alternate function PL7 -- PL6 -- PL5 OC5C (Output compare and PWM output C for Timer/Counter5) PL4 OC5B (Output compare and PWM output B for Timer/Counter5) PL3 OC5A (Output compare and PWM output A for Timer/Counter5) PL2 T5 (Timer/Counter5 clock input) PL1 ICP5 (Timer/Counter5 input capture trigger) PL0 ICP4 (Timer/Counter4 input capture trigger) Source: Atmel Corporation, The Atmel AVR Microcontroller Table 8.14 ■ PORTL pins alternate functions 8.6 Overview of AVR XMega Parallel PORTs An XMega MCU may have up to 14 parallel PORTs (A, B, C, D, E, F, H, J, K, L, M, N, P, Q, and R). Most PORTs have eight pins. A few of them have less than 8 pins. Each pin can be configured as input or output with highly configurable driver and pull settings. The register naming of XMega AVR in C has been discussed in Section 6.10. Each PORT also implements several functions including interrupts, synchronous/asynchronous input sensing, and asynchronous wake-up signaling, which are discussed in Chapter 9. The output driver and pull setting of each pin can be configured to one of the following: • • • • • • • Totem pole Totem pole with pull-up Totem pole with pull-down Wired-OR Wired-AND Bus keeper Inverted I/O Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 234 Chapter 8 ■ Parallel I/O Like the AVR Mega, each I/O PORT of the AVR XMega has one data direction register (DIR), one data output register (OUT), and one data input (IN) register. In addition, each pin has a pin configuration (PINnCTRL) register for additional pin configuration. The contents of the PINnCTRL register are shown in Figure 8.12. 7 6 SRLEN INVEN 5 R/W R/W 4 3 2 OPC[2:0] R/W R/W 1 0 Reset value = 0x00 ISC[2:0] R/W R/W R/W R/W SRLEN: Slew rate limit enable 0 = Disable slew rate limit 1 = Enable slew rate limit on pin n INVEN: Inverted I/O enable 0 = Disable inverting output and input on pin n 1 = Enable inverting output and input on pin n OPC[2:0] Group configuration Output configuration Pull configuration 000 001 010 011 100 101 110 111 TOTEM BUSKEEPER PULLDOWN PULLUP WIREDOR WIREDAND WIREDORPULL WIREDANDPULL Totem pole Totem pole Totem pole Totem pole Wired OR Wire AND Wired OR Wired AND (N/A) Bus keeper Pull-down (on input) Pull-up (on input) (N/A) (N/A) Pull-down Pull-up ISC[2:0]: Input sense configuration ISC[2:0] Group configuration Description 000 001 010 011 100 101 110 111 BOTHEDGES RISING FALLING LEVEL Sense both edges Sense rising edge Sense falling edge Sense low level Reserved Reserved Reserved Input buffer disabled Figure 8.12 INPUT_DISABLE ■ Source: Atmel Corporation, The Atmel AVR Microcontroller OPC[2:0]: Output and pull configuration Pin n configuration register (PORTx.PINnCTRL) 8.6.1 Setting the Direction of PORT Pins The direction of XMega AVR PORT pins is controlled through the DIR register. A PORT pin n is configured for output if the DIRn bit in the DIR register is 1. If the DIRn bit is 0, the PORT pin is configured for input. For example, the following instruction configures the upper four pins of PORTD for output and the lower four pins for input: ldi sts r16,0xF0 PORTD_DIR,r16 The following C statement performs the same configuration: PORTD.DIR 5 0xF0; Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 8.6 ■ Overview of AVR XMega Parallel PORTs 235 The DIR register can be accessed directly, or manipulated through the strobe registers DIRSET, DIRCLR, and DIRTGL. Writing a bit mask (with certain bit positions set to 1) to the DIRSET register causes that bit mask to be set in the DIR register. Writing a bit mask to the DIRCLR register causes that bit mask to be cleared in the DIR register. Writing a bit mask to the DIRTGL register causes the bits in the mask to be toggled in the DIR register. For example, the following sequence of instructions causes the odd bits of the DIR register to be set to 1 and hence configures the odd pins of PORTD for output: ldi sts r16,0xAA PORTD_DIRSET,r16 The sequence of instructions ldi sts r16,0x59 PORTD_DIRCLR,r16 causes bits 6, 4, 3, and 0 of the DIR register of PORTD to be cleared to 0 and hence configures the pin 6, 4, 3, and 0 of PORTD for input. The sequence of instructions ldi sts r16,0x39 PORTD_DIRTGL,r16 causes bits 5, 4, 3, and 0 of the DIR register of PORTD to be toggled (from input to output and vice versa) and hence change the direction of these four pins. 8.6.2 Controlling the Output Value of PORT Pins The output value of a PORT pin is controlled through the OUT register. The direction of the PORT pin must be set to output for the corresponding OUT register bit to have any effect. The OUT register can either be accessed directly, or manipulated through the strobe registers OUTSET, OUTCLR, and OUTTGL. Writing a bit mask to the OUTSET register causes that bit mask to be set in the OUT register. Writing a bit mask to the OUTCLR register causes the bits in the mask to be cleared in the OUT register. Writing a bit mask to the OUTTGL register causes the bits in the mask to be toggled in the OUT register. 8.6.3 Reading the Logic State of PORT Pins The logic state of a PORT pin can be obtained by reading the IN register. The current logic state of the PORT pin n can be read through the INn bit, regardless of the setting of the direction bit. 8.6.4 Pin Configuration Each I/O pin has its own configuration register named PINnCTRL (shown in Figure 8.12), where n signifies the pin number. Through these registers, a number of parameters can be configured on a pin-by-pin basis. These parameters are explained in the following paragraphs: O U T P U T / P U L L C O N F I G U R AT I O N The output/pull configuration bits are used to configure the output driver behavior and the pull configuration. Table 8.15 shows a parametric overview of the possible configurations. In the Totem pole configuration of Table 8.15, the output is driven to VCC or GND as commanded by the corresponding bit in the OUT register. In the Wired-OR configuration, writing a 1 to the OUTn bit causes the pin n to be driven to VCC. Writing a 0 to the OUTn bit releases the pin, allowing the pin to be pulled to GND with an internal or external pull-down resistor. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 236 Chapter 8 ■ Parallel I/O Symbol Output configuration PORT_OPC_TOTEM_gc Pull configuration Totem pole (N/A) PORT_OPC_BUSKEEPER_gc Totem pole Bus keeper on input and output PORT_OPC_PULLDOWN_gc Totem pole Pull-down on input PORT_OPC_PULLUP_gc Totem pole Pull-up on input PORT_OPC_WIREDOR_gc Wired_OR (N/A) PORT_OPC_WIREDAND_gc Wired_AND (N/A) PORT_OPC_WIREDORPULL_gc Wired_OR Pull-down PORT_OPC_WIREDANDPULL_gc Wired_AND Pull-up Source: Atmel Corporation, The Atmel AVR Microcontroller Table 8.15 ■ XMega I/O pin output/pull configuration In the Wired-AND configuration, writing a 0 to the OUTn bit causes the pin n to be driven to GND. Writing a 1 to the OUTn bit releases the pin, allowing the pin to be pulled to VCC with an internal or external pull-up resistor. The bus keeper on input and output configuration of Table 8.15 provides a weak bus keeper that keeps the pin at the same logic level when the pin is not driven to any logic state. The pull-down configuration enables the internal pull-down resistor for the pin. The pull-up configuration enables the internal pull-up resistor for the pin. I N P U T / S E N S E C O N F I G U R AT I O N The input/sense configuration bit controls the input sensing and digital input buffer of the I/O pin. The possible input/sense configurations are listed in Table 8.16. Four sense configurations are available, and they affect how interrupts and events are generated from the pin. A pin can sense the rising edge, the falling edge, either edges, or the low level. Note that sensing on the high level can be achieved by setting the “Inverted I/O” bit in the PINnCTRL register. If the pin is used to generate events and the sense setting is set to low level, the pin is transparent to the event system, meaning that the level on the pin is directly connected to the event line. Setting the input/ sense field to Digital input buffer disabled disables the digital input buffer on the pin. This can be used to reduce power consumption when the pin is unused, or used only for analog functions. The corresponding bit in the IN register always reads “0” when the digital input buffer is disabled. Symbol Configuration PORT_ISC_BOTHEDGES_gc Sense both edges PORT_ISC_RISING_gc Sense rising edge PORT_ISC_FALLING_gc Sense falling edge PORT_ISC_LEVEL_gc Sense low level (transparent for events) PORT_ISC_INPUT_DISABLE_gc Digital input buffer disabled Source: Atmel Corporation, The Atmel AVR Microcontroller Table 8.16 ■ XMega I/O pin input/sense configuration INVERSION The “Inverted I/O” bit in the PINnCTRL registers controls the polarity of the pin. If this bit is written to 0, all input and output logic is not inverted. Setting the “Inverted I/O” bit for a pin inverts the input/output signal for any peripheral module overriding the pin. As an example, it is possible to invert a PWM output signal from a timer/counter module simply by setting the “Inverted I/O” bit. This can be useful for easy switching between active high and active low driving. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 8.6 ■ Overview of AVR XMega Parallel PORTs 237 S L E W R AT E The slew rate determines how fast a signal can rise toward the maximum and fall to the minimum level. Slew rate control can be enabled for all I/O pins individually. Enabling the slew rate limiter typically increases the rise/fall time by 50–150%, depending on voltage, temperature, and load. 8.6.5 Multipin Configuration Configuring I/O pins via the PINnCTRL register would be inefficient because this register only configures one pin at a time. To increase efficiency, the AVR XMega allows the user to configure all I/O pins of the same PORT that require the same configuration at once, using a process called multipin configuration process. This process consists of the following steps: Step 1 Write a bit pattern matching the pins to be configured to the MPCMASK register in the PORTCFG module. Step 2 Write the value of configuration to one of the PINnCTRL registers of that PORT. The PINnCTRL register to be written into need not be any one targeted by the MPCMASK register. When a pin configuration is written to one of the PINnCTRL registers of that PORT, that value is written to all the PINnCTRL registers of the pins matching the bit pattern in the MPCMASK register. It is not necessary to write to one of the registers that are targeted by the PINMASK register. If the bit mask in PINMASK does not target the register that is written to, the register remains unchanged. Note that it is important that the multipin configuration not be interrupted by a task that writes to a PINnCTRL register. If the MPCMASK register is already written, an interrupt is executed, and the interrupt service routine (ISR) writes to any PINnCTRL register, pins belonging to a different I/O PORT than intended are configured. The recommended solution is to store and then disable the global interrupt flag before doing a multipin configuration and restore the global interrupt flag after the configuration has been written. Example 8.3 ▼ Write an instruction sequence to configure pins 0~3 on PORTC for Wired-OR with pulldown operation, and sense the rising edge. Solution: ldi sts ldi sts r16,0x0F PORTCFG_MPCMASK,r16 r16,0x31 PORTC_PIN0CTRL,r16 ; configure pins 0~3 simultaneously ; " ; configure output to Wired-OR, input sense the rising edge ; " The same configuration is achieved by the following C statements: PORTCFG.MPCMASK 5 0x0F; PORTC.PIN0CTRL 5 0x31; // apply the same configuration to pins 0~3 // output Wired-OR with pull down ▲ 8.6.6 Virtual PORTs The I/O instructions in the AVR instruction set can only operate on addresses that are within the AVR I/O space. Using these instructions instead of their data space equivalents is both faster and consumes less program memory. All I/O PORT registers on the XMega have addresses outside the I/O space. The solution to this is to use the virtual PORTs. Up to four of the I/O PORTs can be mapped into virtual PORTs that have registers in the I/O space. The virtual PORTs make the DIR, OUT, Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 238 Chapter 8 ■ Parallel I/O IN, and INTFLAGS registers of the desired I/O PORT available in the I/O space. The other less used I/O PORT registers are still available through the regular PORT module registers. The module names for virtual PORTs are VPORT0, VPORT1, VPORT2, and VPORT3, respectively. Registers VPCTRLA and VPCTRLB are used to map I/O PORTs to virtual PORTs. The contents of these two registers are shown in Figure 8.13 and Figure 8.14. These two registers belong to the PORTCFG module. 7 6 5 4 3 VP1MAP[3:0] R/W R/W 2 1 0 Reset value = 0x00 VP0MAP[3:0] R/W R/W R/W R/W R/W R/W Note: VP1MAP[3:0] and VP0MAP[3:0] mapping are shown in Table 8.17. Source: Atmel Corporation, The Atmel AVR Microcontroller Figure 8.13 7 ■ Virtual PORT-map control register A (VPCTRLA) 6 5 4 3 VP3MAP[3:0] R/W R/W 2 1 0 Reset value = 0x00 VP2MAP[3:0] R/W R/W R/W R/W R/W R/W Note: VP3MAP[3:0] and VP2MAP[3:0] mapping are shown in Table 8.17. Source: Atmel Corporation, The Atmel AVR Microcontroller Figure 8.14 ■ Virtual PORT-map control register B (VPCTRLB) VPnMAP[3:0] Group configuration Description 0000 PORTA PORTA mapped to virtual PORTN 0001 PORTB PORTB mapped to virtual PORTN 0010 PORTC PORTC mapped to virtual PORTN 0011 PORTD PORTD mapped to virtual PORTN 0100 PORTE PORTE mapped to virtual PORTN 0101 PORTF PORTF mapped to virtual PORTN 0110 PORTG PORTG mapped to virtual PORTN 0111 PORTH PORTH mapped to virtual PORTN 1000 PORTJ PORTJ mapped to virtual PORTN 1001 PORTK PORTK mapped to virtual PORTN 1010 PORTL PORTL mapped to virtual PORTN 1011 PORTM PORTM mapped to virtual PORTN 1100 PORTN PORTN mapped to virtual PORTN 1101 PORTP PORTP mapped to virtual PORTN 1110 PORTQ PORTQ mapped to virtual PORTN 1111 PORTR PORTR mapped to virtual PORTN Source: Atmel Corporation, The Atmel AVR Microcontroller Table 8.17 ■ Virtual PORT mapping Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 8.7 ■ 239 Simple I/O Devices Example 8.4 ▼ Write a program to map PORTC to virtual PORT0, and PORTD to virtual PORT1; configure VPORT0 for input and VPORT1 for output; read data from VPORT0; and output it to VPORT1. Solution: The following instruction sequence performs the specified operation: ldi sts ldi out ldi out in out r16,0x32 PORTCFG_VPCTRLA,r16 r16,0 VPORT0_DIR,r16 r16,0xFF VPORT1_DIR,r16 r16,VPORT0_IN VPORT1_OUT,r16 ; map PORTC and D to VPORT0 and VPORT1, respectively ; " ; configure VPORT0 for input ; " ; configure VPORT1 for output ; " ; read from VPORT0 ; output it to VPORT1 The following sequence of C statements performs the same operation: PORTCFG.VPCTRLA5 0x32; VPORT0.DIR 5 0; VPORT1.DIR 5 0xFF; VPORT1.OUT 5 VPORT0.IN; // map PORTC and D to VPORT0 and VPORT1 // configure VPORT0 for input // configure VPORT1 for output // read from VPORT0 and output to VPORT1 ▲ 8.6.7 Alternate PORT Functions of XMega Most PORT pins have alternate pin functions in addition to being a general-purpose I/O pin. When an alternate function is enabled, it might override the normal PORT pin function or pin value. This happens when other peripherals that require pins are enabled or configured to use pins. A summary of alternate PORT functions for the XMega64A1/128A1/192A1/256A1/38 4A1 is given in Appendix E. 8.7 Simple I/O Devices Many embedded systems only require simple input/output devices such as switches, lightemitting diodes, keypads, and seven-segment displays, to interface with the user. 8.7.1 Interfacing with LEDs The LED is often used to indicate the system operation mode—whether power is turned on, whether system operation is normal, and so on. An LED can illuminate when it is forward biased and has sufficient current flowing through it. The current required to light an LED may range from a few to more than 10 mA. The forward voltage drop across the LED can range from about 1.6 V to more than 2.2 V. Figure 8.15 suggests three methods for interfacing with LEDs. Methods (a) and (b) are recommended for use with LEDs that need only 1 or 2 mA to produce enough brightness. The Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 240 Chapter 8 ■ Parallel I/O VDD VDD PORT pin R1 R2 PORT pin (a) Positive direct drive Figure 8.15 ■ R3 PORT pin (b) Inverse direct drive (c) Buffered drive Source: Atmel Corporation, The Atmel AVR Microcontroller circuit (c) is recommended for use with LEDs that need larger current to light. Resistors R1, R2, and R3 are referred to as current-limiting resistors because they set the magnitude of the current flowing through the LED. Circuit for driving an LED Example 8.5 ▼ Use the AVR Mega PORTK to drive eight LEDs and output the value 0x58 to PORTK. Show the circuit connection and give an instruction sequence to perform the desired operation. Solution: The circuit shown in Figure 8.16 can be used to drive eight LEDs. ldi out ldi sts r16,0xFF DDRK,r16 r16,0x58 PORTK,r16 ; configure PORTK for output ; " ; output the value 0x58 to LEDs ; " The following C statements perform the same operation: DDRK 5 0xFF; PORTK 5 0x58; // use PORTK.DIR instead of DDRK for XMega // use PORTK.OUT instead of PORTK for XMega Mega2560 1kΩ Source: Atmel Corporation, The Atmel AVR Microcontroller PK7 PK6 PK5 PK4 PK3 PK2 PK1 PK0 Figure 8.16 ■ Circuit connection for Example 8.5 ▲ Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 8.7 ■ 241 Simple I/O Devices Example 8.6 ▼ Replace the Mega2560 MCU in Figure 8.16 with the XMega128A1, and also change PORTK to PORTC. Write an assembly program to turn on one LED at a time for 100 ms from top to bottom and then from bottom to top. Repeat this pattern forever. Solution: The values to turn on one LED at a time from top-to-bottom and then from bottomto-top should be placed in an array (ledArr). Let ptr and j be the pointer to the LED pattern array and the loop index, respectively. The algorithm of this program is as follows: Step 1 j ← 0; ptr ← ledArr; Step 2 Read the value pointed to by ptr and output it to PORTK. Step 3 Increment j and move ptr. Step 4 Wait for 100 ms. Step 5 If (j 5 5 array count) Goto Step 1 Else Goto Step 2 The assembly program that implements this algorithm is as follows: start: again: loop: .include ,ATXMega128A1def.inc. .equ NN 5 16 .def j 5 r17 .def temp 5 r18 .cseg .org 0x00 rjmp start .org 0xF6 ldi r16,low(RAMEND) sts CPU_SPL,r16 ldi r16,high(RAMEND) sts CPU_SPH,r16 call setCPUclkto32Mwith16MCrystal ldi temp,0xFF sts PORTC_DIR,temp ldi ZL,low(ledArr,,1) ldi ZH,high(ledArr,,1) ldi j,0 lpm temp,z1 sts PORTC_OUT,temp ldi r16,2 rcall delayby100ms inc j cpi j,NN brne loop rjmp again .include “sysClock_XMega.asm” ; array count ; loop index ; temporary storage ; set up stack pointer ; " ; " ; " ; set up system clock ; configure PORTC for output ; " ; set up pointer to LED pattern array ; " ; read one LED pattern ; output to LED ; wait for 200 ms ; " ; test end of LED pattern array ; " ; " Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 242 Chapter 8 ■ Parallel I/O delayby100ms: push loop2: ldi loop1: ldi loop0: ldi loopi: push pop dec brne dec brne dec brne dec brne pop ret ledArr: .db .db r28 r28,200 r21,250 r20,4 r0 r0 r20 loopi r21 loop0 r28 loop1 r16 loop2 r28 0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01 0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80 The C language version of the program is as follows: #include ,avr/io.h. #include “delays_XMega.h” // include delays_XMega.c to this project #include “sysClock_XMega.h” // include sysClock_XMega.c to this project #define NN 16 char ledArr[NN] 5 {0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01, 0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80}; int main(void) { int j; PORTC.DIR 5 0xFF; // configure PORTC for output setCPUclkto32Mwith16MCrystal(); // set CPU clock to 32 MHz while(1) { for(j 5 0; j , NN; j11){ PORTC.OUT 5 ledArr[j]; // output the LED pattern delayby100ms(1); } } } ▲ 8.7.2 Interfacing with Seven-Segment Displays Seven-segment displays are often used when the embedded system product needs to display only a few digits. Seven-segment displays are mainly used to display decimal digits and a small subset of letters. Although an AVR MCU has enough current to drive a seven-segment display, it is not advisable to do so when an AVR-based embedded product needs to drive many other I/O devices. In Figure 8.17, PORTK drives a common-cathode seven-segment display through the Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 8.7 ■ 243 Simple I/O Devices buffer chip SN74LV244 from TI. The SN74LV244 can operate with a power supply ranging from 2 V to 5.5 V. Assume that both the Mega2560 and the SN74LV244 use a 5 V power supply. Both the Mega2560 and the SN74LV244 are implemented in CMOS technology and hence are compatible in voltage levels. The high output voltage of the SN74LV244 is 5 V. The segment current is 3.2 mA (5 (5 – 1.8)V/1 kV), assuming that the voltage drop of the sevensegment display is 1.8 V. Mega2560 1 kΩ g b c d Common cathode Figure 8.17 ■ Source: Atmel Corporation, The Atmel AVR Microcontroller a a b f c d e e f g SN74LV244 PK6 PK5 PK4 PK3 PK2 PK1 PK0 Driving a single seven-segment display To display decimal digits 0 to 9, appropriate values must be sent to PORTK in Figure 8.17. The light patterns corresponding to 10 decimal digits are shown in Table 8.18. The numbers in Table 8.18 require that segments a~g be connected from the second most significant pin (PK6) to the least significant pin (PK0) of PORTK. The SN74LV244 can source and sink up to 35 mA continuously. The maximum current that needs to be sourced and sunk by the SN74LV244 is 22.4 mA (5 7 * 3.2 mA) and hence is within its capacity. Segments Decimal digit a b c d e f g Corresponding hex number 0 1 1 1 1 1 1 0 0x7E 1 0 1 1 0 0 0 0 0x30 2 1 1 0 1 1 0 1 0x6D 3 1 1 1 1 0 0 1 0x79 4 0 1 1 0 0 1 1 0x33 5 1 0 1 1 0 1 1 0x5B 6 1 0 1 1 1 1 1 0x5F 7 1 1 1 0 0 0 0 0x70 8 1 1 1 1 1 1 1 0x7F 9 1 1 1 1 0 1 1 0x7B Note: Segments a through g are connected to the second most significant through least significant I/O pins. Source: Atmel Corporation, The Atmel AVR Microcontroller Table 8.18 ■ Decimal to seven-segment decoder Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 244 Chapter 8 ■ Parallel I/O When an application is required to display multiple decimal digits, the time-multiplexing technique is often used. An example of the circuit that displays six decimal digits (for the XMega128A1) is shown in Figure 8.18. PORTA outputs the segment pattern, whereas PORTB outputs the digit select signals. Whenever a PORTB pin is driven low, the driven display is lighted because its common cathode pin has been driven low. In the time-multiplexing technique, each display is lighted in turn briefly (for example, 1 ms) and then turned off. When one display is lighted, all other displays are turned off. Within 1 second, each seven-segment display is lighted and then turned off many times. Because of the persistence of vision, the six displays appear to be lighted simultaneously. PA5 PA0 g SN74LV244A VDD XMega128A1 Figure 8.18 ■ PB5 1A1 1Y1 PB4 1A2 1Y2 PB3 1A3 1Y3 PB2 1A4 1Y4 PB1 2A1 2Y1 PB0 2A2 2Y2 OE1 OE2 3.3 V . . . g Common cathode Common cathode Common cathode Imax = 24.4 mA PA6 . . . . . . . . . g a b Imax = 24.4 mA SN74LV244 a b Imax = 24.4 mA . . 430 Ω . #0 #4 a b . . . Source: Atmel Corporation, The Atmel AVR Microcontroller #5 430 Ω PORTA and PORTB together drive six seven-segment displays (XMega128A1) To implement the time-multiplexing technique, we need a delay subroutine (or function). A delay subroutine (or function) can be implemented by program loops (Chapter 3) or timer function (Chapters 11 and 12). Example 8.7 ▼ Write a program to display 123456 on the six 7-segment displays shown in Figure 8.18 assuming that the XMega device has a 32 MHz CPU clock. Solution: The digits 1, 2, 3, 4, 5, and 6 are displayed on seven-segment displays #5, #4, …, and #0, respectively. The values to be output to PORTA_OUT and PORTB_OUT to display one digit at a time are shown in Table 8.19. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 8.7 ■ 245 Simple I/O Devices Seven-segment display Displayed BCD digit PORTA_OUT PORTB_OUT #5 1 0x30 0xDF #4 2 0x6D 0xEF #3 3 0x79 0xF7 #2 4 0x33 0xFB #1 5 0x5B 0xFD #0 6 0x5F 0xFE Source: Atmel Corporation, The Atmel AVR Microcontroller ■ Table 8.19 Table of display patterns for Example 7.7 This table can be created by the following assembler directives: disTab: db db 0x30,0xDF,0x6D,0xEF,0x79,0xF7 0x33,0xFB,0x5B,0xFD,0x5F,0xFE The program logic of this example is shown in Figure 8.19. Start PORTA_OUT ← *ptr PORTB_OUT ← *(ptr+1) ptr ← ptr + 2 Wait for 1 ms No Reach the end of table? Yes Figure 8.19 ■ Source: Atmel Corporation, The Atmel AVR Microcontroller Ptr ← Address of display table Time-multiplexing seven-segment display algorithm The program that implements this algorithm is as follows: .include ,ATXMega128A1def.inc. .def temp 5 r16 .equ NN 5 12 .def j 5 r17 .cseg .org 0x00 rjmp start Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 246 Chapter 8 start: again: loop: disTab: ■ Parallel I/O .org 0xF6 ldi temp,low(RAMEND) ; temp is r16 out CPU_SPL,temp ; initialize the SP (use SPL for Mega devices) ldi temp,high(RAMEND) ; " out CPU_SPH,temp ; (use SPH for Mega devices) call setCPUclkto32Mwith16MCrystal ldi temp,0xFF sts PORTA_DIR,temp ; configure PORTA for output sts PORTB_DIR,temp ; configure PORTB for output ldi ZL,low(disTab ,, 1) ; set up pointer to seven-segment display pattern array ldi ZH,high(disTab ,, 1) ; " ldi j,0 ; initialize loop index lpm temp,z1 ; read segment pattern sts PORTA_OUT,temp ; output segment pattern lpm temp,z1 ; read digit select value sts PORTB_OUT,temp ; output digit select value ldi r16,1 ; wait for 1 ms rcall delayby1ms ; " inc j inc j cpi j,NN ; reach the end of the segment pattern array? brne loop rjmp again .include “delays_XMega.asm” .include “sysClock_XMega.asm” ret .db 0x30,0xDF,0x6D,0xEF,0x79,0xF7 .db 0x33,0xFB,0x5B,0xFD,0x5F,0xFE The C language version of the program is as follows: #include ,avr\io.h. #include “sysClock_XMega.h” // include sysClock_XMega.c into the project #include “delays_XMega.h” // include delays_XMega.c into the project char dispTab[6][2] 5 {{0x30,0xDF},{0x6D,0xEF},{0x79,0xF7}, {0x33,0xFB},{0x5B,0xFD},{0x5F,0xFE}}; void main (void) { unsigned char j; setCPUclkto32Mwith16MCrystal(); PORTA.DIR 5 0xFF; // configure PORTA for output PORTB.DIR 5 0xFF; // configure PORTB for output while(1) { for(j 5 0; j , 6; j11){ PORTA.OUT 5 dispTab[j][0]; // output segment pattern PORTB.OUT 5 dispTab[j][1]; // output digit select delayby1ms(1); // wait for 1 ms } } } ▲ Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 8.7 ■ 247 Simple I/O Devices 8.7.3 Generating a Digital Waveform Using an I/O Pin A periodic digital waveform can be generated by manipulating I/O voltage level and inserting an appropriate delay (equal to half of the waveform period) between the two voltage levels. For example, a 500 Hz periodic square wave can be generated from the PH7 pin, using the following algorithm: Step 1 Configure the PH7 pin for output. Step 2 Pull the PH7 pin to high. Step 3 Wait for 1 ms. Step 4 Pull the PH7 pin to low. Step 5 Wait for 1 ms. Step 6 Go to Step 2. Example 8.8 ▼ Write a program to generate a 500 Hz periodic square waveform from the PH7 pin of the XMega device assuming that the XMega device has a 32 MHz CPU clock. Solution: The following instruction sequence implements the algorithm described previously: start: forever: .include .def .cseg .org rjmp .org ldi out ldi out call lds ori sts lds ori sts ldi call lds andi sts ,ATXMega128A1def.inc. temp 5 r16 0x00 start 0xF6 temp,low(RAMEND) CPU_SPL,temp temp,high(RAMEND) CPU_SPH,temp setCPUclkto32Mwith16Mcrystal temp,PORTH_DIR temp,0x80 PORTH_DIR,temp temp,PORTH_OUT temp,0x80 PORTH_OUT,temp r16,1 delayby1ms temp,PORTH_OUT temp,0x7F PORTH_OUT,temp ; initialize the SP ; (use SPL for Mega devices) ; " ; (use SPH for Mega devices) ; not needed for Mega devices ; configure PH7 for output ; " ; " ; get the PORTH data register ; set pin 7 to high ; " ; wait for 1 ms ; " ; pull the PH7 pin low ; " ; " Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 248 Chapter 8 ■ Parallel I/O ldi r16,1 call delayby1ms rjmp forever .include “sysClock_XMega.asm” .include “delays_XMega.asm” ; wait for 1 ms ; " The C language version of the program is as follows: #include ,avr\io.h. #include “delays_XMega.h” // include delays_XMega.c to the project #include “sysClock_XMega.h” // include sysClock_XMega.c to the project void main (void) { setCPUclkto32Mwith16MCrystal(); PORTH.DIR |5 0x80; // configure PH7 pin for output while(1){ PORTH.OUT |5 0x80; // pull PH7 pin high delayby1ms(1); // wait for 1 ms PORTH.OUT &5 0x7F; // pull PH7 pin low delayby1ms(1); // wait for 1 ms } } ▲ 8.7.4 Making a Sound using an I/O Pin By connecting the PH7 pin in Example 8.8 to a speaker (or a buzzer) and making the frequency in the audible range, a sound can be made. Because the frequency of the square wave generated in Example 8.8 is in the audible range, a sound can be heard if a speaker is connected to the PH7 pin. By alternating the frequency of the generated waveform from the I/O pin between two different values, a two-tone siren can be generated. The duration of the siren tone is variable. The siren would sound more urgent if the tone duration is shorter. The following example generates a two-tone siren that alternates between 250 Hz and 500 Hz, with each tone lasting for half of a second. The period of a 250 Hz square wave is 4 ms. Therefore, we need to repeat this waveform 125 times in half a second. Similarly, the 500 Hz square wave needs to be repeated 250 times. Example 8.9 ▼ Write a program to generate a two-tone siren that alternates between 250 Hz and 500 Hz, with each siren tone lasting for half of a second, using the PH7 pin driving a buzzer or speaker, assuming that the CPU clock is 32 MHz. Solution: The assembly program that generates the two-tone siren with the specified frequencies is as follows: start: .include ,ATXMega128A1def.inc. .def lpCnt 5 r17 .def temp 5 r18 .cseg .org 0x00 rjmp start .org 0xF6 ldi temp,low(RAMEND) ; initialize the SP Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 8.7 ■ Simple I/O Devices ever: f500Hz: f250Hz: 249 out CPU_SPL,temp ; (use SPL for Mega devices) ldi temp,high(RAMEND) ; " out CPU_SPH,temp ; (use SPH for Mega devices) call setCPUclkto32Mwith16MCrystal ; not needed for Mega devices lds temp,PORTH_DIR ; configure PH7 for output ori temp,0x80 ; " sts PORTH_DIR,temp ; " ldi lpCnt,125 ; repeat this tone for 0.5 s lds temp,PORTH_OUT ; create a tone of 250 Hz ori temp,0x80 ; " sts PORTH_OUT,temp ; " ldi r16,2 ; " call delayby1ms ; " lds temp,PORTH_OUT ; " andi temp,0x7F ; " sts PORTH_OUT,temp ; " ldi r16,2 ; " call delayby1ms ; " dec lpCnt brne f500Hz ldi lpCnt,250 ; repeat this tone for 0.5 s lds temp,PORTH_OUT ; creates a tone of 500 Hz ori temp,0x80 ; " sts PORTH_OUT,temp ; " ldi r16,1 ; " call delayby1ms ; " lds temp,PORTH_OUT ; " andi temp,0x7F ; " sts PORTH_OUT,temp ; " ldi r16,1 ; " call delayby1ms ; " dec lpCnt brne f250Hz rjmp ever .include “sysClock_XMega.asm” .include “delays_XMega.asm” The C language version of the program is as follows: #include ,avr/io.h. #include “delays_XMega.h” // also include delays_XMega.c to the project #include “sysClock_XMega.h” // also include sysClock_XMega.c to the project int main(void) { unsigned int k; setCPUclkto32Mwith16MCrystal(); PORTH.DIR |5 0x80; // configure PA7 pin for output while(1) { for(k 5 0; k , 125; k11){ // repeat for half of a second PORTH.OUT |5 0x80; delayby1ms(2); PORTH.OUT &5 0x7F; Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 250 Chapter 8 ■ Parallel I/O delayby1ms(2); } for(k 5 0; k , 250; k11){ // repeat for half of a second PORTH.OUT |5 0x80; delayby1ms(1); PORTH.OUT &5 0x7F; delayby1ms(1); } } } ▲ 8.7.5 Interfacing with DIP Switches A switch is probably the simplest input device we can find. To make input more efficient, a set of eight switches organized as a dual inline package (DIP) is often used. A DIP package can be connected to any input PORT with eight pins. An example of circuit connection for a DIP package is shown in Figure 8.20. VCC PJ7 PJ6 PJ5 PJ4 PJ3 PJ2 PJ1 PJ0 Figure 8.20 ■ XMega128A1 Source: Atmel Corporation, The Atmel AVR Microcontroller 10 kΩ Connecting a DIP package to PORTJ of XMega128A1 Example 8.10 ▼ Write a sequence of instructions to read the value from a DIP package connected to the PORTJ of the XMega128A1 (or a Mega device), and leave it in register r0. Solution: The instruction sequence to configure PORTJ for input and read its contents into r0 is as follows: ldi sts lds r16,0x00 PORTJ_DIR,r16 r0,PORTJ_IN ▲ Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 8.8 ■ 251 Interfacing with a D/A Converter 8.8 Interfacing with a D/A Converter A D/A converter converts a digital value into an analog voltage. A few important DAC characteristics are listed here: • Resolution. The resolution of a DAC refers to the number of bits used to represent a value to be converted. In general, the more bits the better. The resolution of a commercial DAC may range from 8 bits to 24 bits. • Conversion Time. DAC conversion time is the amount of time required to convert a digital value to an analog voltage or current. It is desirable to have short conversion time for a DAC. The DAC conversion time has a wide range. It could be as short as 10 ns or longer than 30 µs. • Number of channels. This parameter refers to the number of outputs that a DAC chip has. • Input Format. A DAC may require data to be input in parallel format or serial format (using the SPI or I2C interface). Parallel format is more suitable for highspeed DAC. Serial input format is more suitable for low pin count MCUs and those applications that do not require very high throughput. 8.8.1 The AD7302 DAC The AD7302 is a dual-channel, 8-bit, DAC chip from Analog Devices that has a parallel interface with the microcontroller. The AD7302 converts an 8-bit digital value into an analog voltage. The block diagram of the AD7302 is shown in Figure 8.21. To send data to the AD7302, the CS signal must be pulled to low. On the rising edge of the WR or CS signal, the values on pins D7 through D0 are latched into the input register. When the signal LDAC is low, the data in the input register are transferred to the DAC register, and a new D/A conversion is started. If the LDAC signal is tied low, then the data in the input register are transferred to the DAC register on the rising edge of the WR signal. Input register DAC register I DAC A I/V VOUTA D7 D0 Input register DAC register I DAC B I/V VOUTB A/B WR CS Control logic ÷2 PD Figure 8.21 Power on reset MUX ■ CLR LDAC REFIN VDD DGND AGND Source: Atmel Corporation, The Atmel AVR Microcontroller AD7302 Functional block diagram of the AD7302 Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 252 Chapter 8 ■ Parallel I/O The AD7302 needs a reference voltage to perform D/A conversion. The reference voltage can come from either the external REFIN input or the internal VDD. The A /B signal selects the channel (A or B) to perform the D/A conversion. Channel A is selected when this signal is low. Otherwise, Channel B is selected. When the PD pin is low, the AD7302 is placed in the powerdown mode and reduces the power consumption to 1 µW. Each digital sample takes about 1.2 µs to convert. The AD7302 operates from a single 2.7 to 5.5 V power supply and typically consumes 15 mW at 5 V, making it suitable for battery-powered applications. The output voltage (VOUTA or VOUTB) from either DAC is given by VOUT A/B 5 2 3 VREF 3 (N/255) where, VREF is derived internally from the voltage applied at the REFIN pin or VDD. If the voltage applied to the REFIN pin is within 1 V of the VDD, VDD/2 is used as the reference voltage automatically. Otherwise, the voltage applied at the REFIN pin is used as the reference voltage. The range of VREF is from 1 V to VDD/2. N is the decimal equivalent of the code loaded to the DAC register, ranging from 0 to 255. 8.8.2 Interfacing the AD7302 with the AVR Mega or XMega Devices AD7302 Mega2560 PA7~PA0 D7..D0 3.3 V VDD REFIN PB0 VDD WR PD CLR PB1 A/B CS LDAC Figure 8.22 ■ VOUTA VOUTB AGND DGND Source: Atmel Corporation, The Atmel AVR Microcontroller The data to be sent to the AD7302 for conversion can be sent via a parallel PORT (connect to pins D7~D0). Both the CS and LDAC signals can be tied to ground permanently. An output pin can be used (as the WR signal) to control the transferring of data to the input register. An example of circuit connection between the Mega2560 and the AD7302 is shown in Figure 8.22. Circuit connection between the AD7302 and the Mega2560 Example 8.11 ▼ Write a program to generate a sawtooth waveform from the VOUTA pin, assuming that the Mega2560 is running with an 8 MHz crystal oscillator. Solution: One way to generate a sawtooth waveform is to divide one period of the sawtooth waveform into certain number of points (for example, 52 points). The program starts from Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 8.8 ■ 253 Interfacing with a D/A Converter outputting 0 and then increments the output value by 5 in each following step until the value 255 is reached, and then repeats. The assembly program that follows this algorithm to generate the sawtooth waveform is as shown here: start: again: loop: .include .def .def .def .def .cseg .org rjmp .org ldi out ldi out ldi sts sts ldi ldi clr clr cbi cbi out sbi nop nop nop add inc cp brne rjmp ,m2560def.inc. temp 5 r16 j 5 r17 delta 5 r18 LpEnd 5 r19 0x00 start 0xF6 temp,low(RAMEND) SPL,temp temp,high(RAMEND) SPH,temp temp,0xFF DDRA,temp DDRB,temp delta,5 LpEnd,52 j temp PORTB,1 PORTB,0 PORTA,temp PORTB,0 temp,delta j j, LpEnd loop again ; loop index ; amount of increment ; Loop end value (5 52) ; initialize the SP ; (use CPU_SPL for XMega devices) ; " ; (use CPU_SPH for XMega devices) ; configure PORTA for output ; configure PORTB for output ; set up increment amount ; set up loop limit ; start j from 0 ; start temp from 0 ; select channel A ; enable write to AD7302 ; send a value to be converted ; start DAC ; insert idle time ; to allow enough internal DAC operation to complete ; " ; increment to next step ; increment loop count ; reach the end of the loop? The C language version of the program is as follows: #include ,avr\io.h. void main (void) { unsigned char j, tmp, delta; delta 5 5; DDRA 5 0xFF; // configure PORTA for output DDRB 5 0xFF; // configure PORTB for output PORTB &5 0xFD; // select VOUTA output while (1) { tmp 5 0; for (j 5 0; j , 52; j11){ PORTB &5 0xFE; // enable write Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 254 Chapter 8 ■ Parallel I/O PORTA 5 tmp; // output the value to be converted PORTB |5 0x01; // start DAC tmp 15 delta; } } } ▲ 8.9 Summary A user employs I/O devices to interact with embedded systems. LEDs are often used to indicate whether the product is functioning properly and whether the power is on. LEDs are also used to display certain patterns. Matrix displays are based on LEDs and are often used to display messages in public buildings. Today, LEDs are even used to provide lighting because of their low power consumption. A set of DIP switches is used as a simple input device. The software needs to output a message to remind the user to set up a value in the DIP switches and assert an interrupt to inform the MCU to read the value. The AVR Mega and XMega devices have many signal pins. These signal pins are divided into I/O PORTs. An I/O PORT consists of a set of signal pins and registers required for the I/O operation. Because an I/O pin can be used for input and output, the user must configure the direction of the I/O pin before using it in data transfer. This is achieved by writing an appropriate value into a data direction register. For AVR Mega and XMega devices, a pin is configured for output if a 1 is written to its associated bit position of the PORT data direction register. In addition, the AVR allows the user to configure the input pin sensing edge and pull-up or pull-down. To output data, the MCU writes data to the PORT data register. To input data, the MCU reads from the PORT input register. When interfacing peripheral chips with the microcontroller, the user must make sure that these peripheral chips are electrically compatible with the microcontroller. D/A converters are often used to convert digital values into voltages. Square, saw-tooth, triangular, staircase, and sinusoidal waveforms can be generated from a D/A converter easily. The digital value to be converted can be represented in 8 bits, 10 bits, or many more bits. The more bits are used, the better the resolution gets. A high-fidelity digital audio system uses 24 bits to encode a value to be converted back to audio sound. 8.10 Exercises E8.1 Write an instruction sequence to output the value 0x53 to PORTA. E8.2 Write an instruction sequence to read the voltage levels on PORTB pins and place the value in register r20. E8.3 Suppose that the PORTA pins PA4~PA0 are connected to green, yellow, red, blue, and purple LEDs. The circuit connection is similar to that in Figure 8.16. Write a program to light the green, yellow, red, blue, and purple in turn for 0.1, 0.2, 0.3, 0.4, and 0.5 seconds forever. Use both the assembly and C languages. E8.4 Traffic light controller simulation. Use PORTC pins PC5~PC0 of the XMega and green, yellow, and red LEDs to simulate a traffic-light controller. The traffic-light patterns and durations for the east–west and north–south traffic are given in Table 8E.4. Write an assembly and C program to control the light patterns, and connect the circuit to demonstrate the change of lights. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 8.10 ■ 255 Exercises East-West North-South Duration (sec) Green Yellow Red Green Yellow Red PC5 PC4 PC3 PC2 PC1 PC0 1 0 0 0 0 1 0 1 0 0 0 1 5 0 0 1 1 0 0 20 0 0 1 0 1 0 4 25 Source: Atmel Corporation, The Atmel AVR Microcontroller Table 8E4 ■ Traffic light pattern and duration E8.5 For the circuit shown in Figure 8.18, write a program to display 1, 2, 3, 4, 5, and 6 from left to right, one digit at a time, with each digit lasting for 100 ms. E8.6 Write a program to display the following patterns from the seven-segment display circuit shown in Figure 8.18 from display #5 to #0, and repeat with each pattern lasting for 600 ms: 123456 234567 345678 456789 567890 678901 789012 890123 901234 012345 E8.7 Write a C program to display the following patterns from the seven-segment display circuit shown in Figure 8.18, from display #5 to #0, and repeat with each pattern lasting for 600 ms: 0 10 210 3210 43210 543210 654321 765432 876543 987654 098765 109876 210987 321098 432109 E8.8 Write an instruction sequence to configure pins 0, 2, 3, and 7 of PORTB with pull-up operation and sense falling edge for the XMega devices. E8.9 Write an instruction sequence to map PORTs A, B, C, and D of XMega to virtual PORTs 0, 1, 2, and 3, respectively. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 256 Chapter 8 ■ Parallel I/O E8.10 For the circuit shown in Figure 8.22, write an assembly program to generate a triangular waveform from the VOUTB pin, assuming that the Mega2560 is running with an 8 MHz crystal oscillator. E8.11 For the circuit shown in Figure 8.22, write an assembly program to generate a triangular waveform from VOUTA pin and a sine wave from the VOUTB pin, assuming that the Mega2560 is running with an 8 MHz crystal oscillator. Divide both waveforms into 50 points per period. E8.12 Suppose that common-anode seven-segment displays are used instead of commoncathode seven-segment displays. Show the changes that must be made in the circuit shown in Figure 8.17. What needs to be modified in Table 8.18 for the seven-segment displays? E8.13 Can the HCT technology drive the ABT technology at the same power supply? E8.14 Verify whether the XMega with 3.3 V power supply is electrically compatible with the BCT technology with 5 V power supply. E8.15 Are the FCT technology with 5 V power supply and the XMega devices with 3.3 V power supply electrically compatible? 8.11 Lab Assignments L8.1 Three-Tone Siren Generation. Connect the PH7 pin to a speaker or buzzer. Write a program to generate a three-tone siren with frequency equals 250 Hz, 500 Hz, and 1 kHz, respectively. Each tone lasts for half a second. L8.2 Waveform Generation. Use a circuit similar to that in Figure 8.22 to generate a 1 kHz square wave from V OUTA and a 2 kHz square wave from V OUTB simultaneously. Use the oscilloscope to display the generated waveform. L8.3 Waveform Generation. Use the circuit similar to that in Figure 8.22 to generate a sine wave from VOUTA pin. Divide one period of the sine waveform into 52 points. L8.4 LED Flashing. Write a program to flash the LEDs driven by PORTK on your demo board with the following pattern: 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. Turn on all LEDs for 200 ms and turn them off for 200 ms. Repeat Step 1 three more times. Turn on one LED at a time, from left to right, with each LED turned on for 200 ms. Repeat Step 3 three more times. Turn on one LED at a time, from right to left, with each LED turned on for 200 ms. Repeat Step 5 three more times. Turn LEDs driven by pins PK7 and PK0 on and off four times. The on and off times both 200 ms. Turn LEDs driven by pins PK6 and PK1 on and off four times. The on and off times both 200 ms. Turn LEDs driven by pins PK5 and PK2 on and off four times. The on and off times both 200 ms. Turn LEDs driven by pins PK4 and PK3 on and off four times. The on and off times both 200 ms. Turn LEDs driven by pins PK3 and PK4 on and off four times. The on and off times both 200 ms. Turn LEDs driven by pins PK2 and PK5 on and off four times. The on and off times both 200 ms. Turn LEDs driven by pins PK1 and PK6 on and off four times. The on and off times both 200 ms. are are are are are are are Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 8.11 ■ Lab Assignments 257 14. Turn LEDs driven by pins PK0 and PK7 on and off four times. The on and off times are both 200 ms. 15. Go to Step 1 and repeat. L8.5 Use PORTH to drive two 74HC48s. The 74HC48 is a common cathode seven-segment display driver that accepts a four-digit binary number and converts it into the corresponding seven-segment pattern. Write a program that displays the value from 00 to 99 on these two 7-segment displays three times and then stops. Display each value for 200 ms. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 9 Interrupt Handling, Resets, and Power Management 9.1 Objectives After completing this chapter, you will be able to • Explain the nature of interrupts and resets. • Explain how interrupts are handled by the CPU. • • • • Enable and disable interrupts. Set up interrupt priority. Write interrupt service routines. Use a watchdog timer reset to detect software errors. • Use the low-power mode to save power consumption. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 260 Chapter 9 ■ Interrupt Handling, Resets, and Power Management 9.2 Basic Concepts on Interrupt In computing, an interrupt is an asynchronous signal indicating the need for attention, or a synchronous event in software indicating the need for a change in execution. A hardware interrupt causes the processor to save its state of execution and begin execution of an interrupt handler (also referred to as an interrupt service routine). The state of execution consists of at least the contents of the program counter and a few other important registers. Software interrupts are usually implemented as instructions in the instruction set, which causes a context switch to an interrupt handler similar to a hardware interrupt. Not all of the microcontrollers implement software interrupts. Interrupts are often used to implement computer multitasking, especially in real-time computing. Such a system is said to be interrupt driven. An act of interrupting is referred to as an interrupt request (IRQ). 9.2.1 Why Interrupt Is Useful Most computers and embedded products are designed to perform multiple functions. In addition to executing general-purpose instructions, the MCU also needs to perform the following operations: • I/O operations. Before reading data from an input device, the CPU needs to know whether the I/O device has new data. We can either let the CPU find out whether new data are available by polling the I/O device or getting the I/O device to inform the CPU of this condition by using an interrupt signal. If the polling method is used, then the CPU cannot perform any other operation until new data become available, which is quite wasteful for the CPU time. Using the interrupt approach, the CPU can continue to perform other operations before new data become available. To output data, the CPU has to make sure that the output device can accept new data before it sends out data. Again, we can either let the CPU find out whether the output device is ready for more data or let the output device inform the CPU, using an interrupt signal. Apparently, the interrupt method prevents the CPU from busy waiting. • Routine tasks. Many computers and embedded systems have to perform routine works such as checking and informing appointment times; updating and redisplaying time of day; checking and measuring environment temperature, pressure, humidity, and so on. Routine tasks are performed by using the timer interrupts. A timer can be set up to overflow periodically and interrupt the CPU. Whenever a timer interrupt occurs, the CPU is reminded to perform those routine tasks. It is difficult to imagine how the CPU could perform them without a timer interrupt. • Response to emergent events. Emergent events such as fire alarm, power failure, overheat, and so on, require the CPU to take action immediately. The interrupt mechanism forces the CPU to divert from normal program execution to do this, thus avoiding severe damage or data loss. 9.2.2 Enabling and Disabling Interrupts An interrupt may be useful in some situations, but not desirable in other situations. Modern microcontrollers are designed to have the capability to selectively pay attention to interrupts. Whenever an interrupt is useful, the MCU enables it. Whenever an interrupt is not Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 9.2 ■ Basic Concepts on Interrupt 261 desirable, the MCU disables it. An interrupt that can be enabled and disabled selectively is called a maskable interrupt. There are other types of interrupts that the CPU cannot ignore and must take immediate action for; these are called nonmaskable interrupts. A program can request the CPU to service or ignore a maskable interrupt by setting or clearing an enable bit. An interrupt is said to be pending when it is active but not serviced by the CPU. A pending interrupt may or may not be serviced by the CPU, depending upon whether it is enabled. To make the interrupt system more flexible, a computer system normally provides a global and local interrupt masking capability. When none of the interrupts are desirable, the processor can disable all of the interrupts by clearing the global interrupt enable bit (or setting the global interrupt mask bit for some other microprocessors). In other situations, the processor can enable certain interrupts while at the same time disabling other undesirable interrupts. This is achieved by providing each interrupt source an enable bit in additional to the global interrupt enable bit. Today, almost all commercial processors have been designed to provide a two-level (or even three-level) interrupt-enabling capability. 9.2.3 Prioritizing Multiple Interrupts If a computer system supports multiple interrupt sources, then it is possible that several interrupts could be pending at about the same time. The CPU has to decide which interrupt should receive service first. The common solution is to prioritize all interrupt sources. In this approach, the CPU provides service to the interrupt with the highest priority among all pending interrupts. Most microcontrollers prioritize interrupts in hardware. For those microcontrollers that do not, the software can be written to handle certain interrupts before others, thus essentially prioritizing them. 9.2.4 Servicing the Interrupt When an enabled interrupt occurs, the CPU is forced to provide service to it by executing an interrupt service routine, after which it must resume the execution of the interrupted program. To be able to do so, the CPU saves the program counter before executing the interrupt service routine. After saving the program counter, the CPU had to identify the source of interrupt and locate the starting address of the interrupt service routine before it can begin to execute the interrupt service routine. When the CPU finishes the execution of the interrupt service routine, which is often very short, it restores the saved program counter and returns to the interrupted program for execution. An interrupt service routine is not much different from a subroutine, except for the last instruction. The last instruction of an interrupt service routine must be the return from interrupt (RETI) instruction. An interrupt service routine is not to be called. Instead, the execution of an interrupt service routine is triggered by the occurrence of the associated interrupt. 9.2.5 The Interrupt Vector The starting address of the interrupt service routine is referred to as an interrupt vector. The microcontroller must find out the starting address of the service routine of the pending interrupt in order to provide appropriate service to it. For some microcontrollers, each interrupt source has its own predefined interrupt vector (i.e., at a fixed location), whereas others store all the interrupt vectors in a table. Each interrupt vector is stored in a fixed location in a table that is referred to as the interrupt vector table. When the first approach is used, the CPU jumps to a predefined location to service the pending interrupt. However, the CPU needs to fetch the interrupt vector from the interrupt Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 262 Chapter 9 ■ Interrupt Handling, Resets, and Power Management vector table in the second approach. The Atmel AVR devices use the first approach to locate the interrupt vector. A table that contains the first four bytes of all interrupt service routines is predefined. The first four bytes of each interrupt service routine are of the following format: jmp xxx_ISR ; xxx_ISR is the actual service routine for an interrupt 9.2.6 Writing an Interrupt-Driven Program Interrupt programming consists of three major steps: Step 1 Initialization of the interrupt vector table. The purpose of this step is to place interrupt vectors in the interrupt vector table. This is achieved by using the assembly directives as follows: .org .dw .dw … 0x03 ISR1 ISR2 This step is not needed for the AVR microcontroller. Step 2 Write the service routine. The interrupt service routine must be as short as possible. An interrupt service routine for INT0 may be as simple as the following: int0ISR: .def … inc out reti cnt = r15 cnt PORTA,cnt ; output cnt to PORTA ; return from interrupt Step 3 Enable interrupts. An interrupt must be enabled before it can signal the MCU to provide service. It is a common mistake to forget enabling interrupts when writing interruptdriven programs. 9.3 Resets When a computer is first powered up, the initial values of program counter, CPU registers, flip-flops, and I/O control registers are unknown. The computer cannot execute programs correctly under these conditions. In order for computers to execute a program correctly after they are powered up, they are designed to have a reset mechanism. All critical registers, the program counters, and flip-flops are forced to a default value after a power-up reset so that the computer can start to execute a program correctly. For example, the program counter of the AVR MCU is forced to 0x0000 after reset, and hence, it always starts program execution from the address 0x0000 after power-on reset. In addition to the power-on reset, a computer may provide several resets to improve the performance and flexibility of the computer system. These resets include manual reset (applied to a pin), brown-out reset, watchdog reset, clock monitor reset, software reset, and so on. A manual reset without power-down has the same effect as power-on reset; it can force the program counter and critical registers to default values and allows the computer to reboot itself after a reset. Other reset sources are discussed later. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 9.4 ■ 263 The AVR Mega Interrupts 9.4 The AVR Mega Interrupts A Mega family device may have up to 56 interrupt sources, all of which are maskable and are divided into three categories: • • • Internal peripheral interrupts. The interrupt sources associated with timers, USART modules, SPI interface, TWI interface, A/D converter, CAN, and USB are in this category. External pin interrupts. A Mega AVR device may have up to eight external interrupt pins (INT0~INT7) that assert interrupt signals to the MCU. An interrupt may be asserted when one of these pins stays low, going low (falling edge), going high (rising edge), or simply toggles. Pin change interrupts. A Mega AVR device may have three pin change interrupts (PCINT0~PCINT2). These interrupts are mainly used to wake up the MCU when it is in sleep mode. These interrupts share the same pins with I/O PORTs B, E, J, and K. 9.4.1 AVR Mega Device Interrupt Vectors The 100-pin Mega devices (ATMega640/1280/2560) have the most interrupt sources among all Mega devices. The Mega devices with fewer pins have fewer interrupt sources. The reset and interrupt vectors of the ATMega640/1280/2560 are listed in Table 9.1. Vector no. Vector addr. Source Interrupt definition 1 0×0000 RESET Pin Reset, Power-on, brown-out, watchdog, JTAG reset 2 0×0002 INT0 External interrupt request 0 3 0×0004 INT1 External interrupt request 1 4 0×0006 INT2 External interrupt request 2 5 0×0008 INT3 External interrupt request 3 6 0×000A INT4 External interrupt request 4 7 0×000C INT5 External interrupt request 5 8 0×000E INT6 External interrupt request 6 9 0×0010 INT7 External interrupt request 7 10 0×0012 PCINT0 Pin change interrupt request 0 11 0×0014 PCINT1 Pin change interrupt request 1 12 0×0016 PCINT2 Pin change interrupt request 2 13 0×0018 WDT Watchdog time-out interrupt 14 0×001A Timer2 COMPA Timer/Counter2 compare match A 15 0×001C Timer2 COMPB Timer/Counter2 compare match B 16 0×001E Timer2 OVF Timer/Counter2 overflow 17 0×0020 Timer1 CAPT Timer/Counter1 capture event 18 0×0022 Timer1 COMPA Timer/Counter1 compare match A 19 0×0024 Timer1 COMPB Timer/Counter1 compare match B 20 0×0026 Timer1 COMPC Timer/Counter1 compare match C 21 0×0028 Timer1 OVF Timer/Counter1 overflow Table 9.1 ■ Reset and interrupt vectors for ATMega640/1280/2560 (Continued) Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 264 Chapter 9 Table 9.1 ■ ■ Interrupt Handling, Resets, and Power Management (Continued) Vector no. Vector addr. 22 0×002A Timer0 COMPA Source Timer/Counter0 compare match A Interrupt definition 23 0×002C Timer0 COMPB Timer/Counter0 compare match B 24 0×002E Timer0 OVF Timer/Counter0 overflow 25 0×0030 SPI, STC SPI serial transfer complete 26 0×0032 USATR0 RX USART0 Rx complete 27 0×0034 USATR0 UDRE USART0 data register empty 28 0×0036 USART0 TX USART0 Tx complete 29 0×0038 Analog Comp Analog comparator 30 0×003A ADC ADC conversion complete 31 0×003C EE Ready EEPROM ready 32 0×003E Timer3 CAPT Timer/Counter3 capture event 33 0×0040 Timer3 COMPA Timer/Counter3 compare match A 34 0×0042 Timer3 COMPB Timer/Counter3 compare match B 35 0×0044 Timer3 COMPC Timer/Counter3 compare match C 36 0×0046 Timer3 OVF Timer/Counter3 overflow 37 0×0048 USART1 RX USART1 Rx complete 38 0×004A USART1 UDRE USART1 data register empty 39 0×004C USART1 TX USART1 Tx complete 40 0×004E TWI 2-wire serial interface 41 0×0050 SPM Ready Store program memory ready 42 0×0052 Timer4 CAPT Timer/Counter4 capture event 43 0×0054 Timer4 COMPA Timer/Counter4 compare match A 44 0×0056 Timer4 COMPB Timer/Counter4 compare match B 45 0×0058 Timer4 COMPC Timer/Counter4 compare match C 46 0×005A Timer4 OVF Timer/Counter4 overflow 47 0×005C Timer5 CAPT Timer/Counter5 capture event 48 0×005E Timer5 COMPA Timer/Counter5 compare match A 49 0×0060 Timer5 COMPB Timer/Counter5 compare match B 50 0×0062 Timer5 COMPC Timer/Counter5 compare match C 51 0×0064 Timer5 OVF Timer/Counter5 overflow 52 0×0066 USART2 RX USART2 Rx complete 53 0×0068 USART2 UDRE USART2 data register empty 54 0×006A USART2 TX USART2 Tx complete 55 0×006C USATR3 RX USART3 Rx complete 56 0×006E USATR3 UDRE USART3 data register empty 57 0×0070 USART3 TX USART3 Tx complete Source: Atmel Corporation, The Atmel AVR Microcontroller Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 9.4 ■ 265 The AVR Mega Interrupts The Mega devices reserve a block of program memory starting from 0×0000 and allocate two words to service the reset and each interrupt source. Because two words are not enough for any interrupt handling, the user normally uses a jump instruction to send the CPU to another location to execute the actual interrupt service routine. The most typical and general program setup for the reset and interrupt vector addresses in ATMega640/1280/2560 is as follows: word Address code 0x0000 0x0002 0x0004 …. …. 0x0070 ; 0x0072 reset: 0x0073 0x0074 0x0075 0x0076 0x0077 jmp jmp jmp reset INT0 INT1 comments jmp USART3_TXC ldi out ldi out sei … r16,high(RAMEND) SPH,r16 r16,low(RAMEND) SPL,r16 ; reset handler ; INT0 handler ; INT1 handler ; other interrupt handlers ; " ; USART3 TX complete handler ; main program starts ; set stack pointer ; " ; " ; enable interrupts However, the user can also relocate the reset vector and interrupt vectors to the boot section by programming the BOOTRST fuse and the IVSEL bit of the microcontroller configuration register (MCUCR). The BOOTRST fuse can be programmed from the AVR Studio IDE. The possible reset and interrupt vectors placement are shown in Table 9.2. BOOTRST IVSEL Reset address Interrupt vectors start address 1 0 0×0000 0×0002 1 1 0×0000 Boot reset address 1 0×0002 0 0 Boot reset address 0×0002 0 1 Boot reset address Boot reset address 1 0×0002 Source: Atmel Corporation, The Atmel AVR Microcontroller Table 9.2 ■ Reset and interrupt vectors placement When the BOOTRST fuse is programmed (cleared to 0), the boot section size is set to 8 kB and the IVSEL bit in the MCUCR register is set to 1 before any interrupt is enabled, the most typical and general program setup for the reset and interrupt vector addresses is as follows: word Address code comments ; 0x1F000 0x1F002 0x1F004 .org jmp jmp jmp 0x1F000 reset EXT_INT0 EXT_INT1 ; reset handler ; INT0 handler ; INT1 handler Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 266 Chapter 9 ■ Interrupt Handling, Resets, and Power Management … 0x1F070 ; 0x1F072 reset: 0x1F073 0x1F074 0x1F075 0x1F076 0x1F077 jmp USART3_TXC ; USART3 TX complete handler ldi out ldi out sei <instrr> xxx r16,high(RAMEND) SPH,r16 r16,low(RAMEND) SPL,r16 ; main program start ; set up stack pointer ; " ; " ; enable interrupt 9.4.2 The Mega AVR Microcontroller Configuration Register (MCUCR) The placement of the interrupt vectors is controlled by the MCUCR register. In addition to controlling the interrupt vectors placement, this register also controls the enabling of I/O pins pull-up and the JTAG interface. The contents of the MCUCR register are shown in Figure 9.1. 6 5 4 3 2 1 0 — — PUD — — IVSEL IVCE R/W R R R/W R R R/W R/W Reset value = 0x00 JTD: JTAG Disable 0: JTAG interface is Enabled. 1: JTAG interface is Disabled. PUD: Pullup Disable 0: Enable pull-ups of all pins of all I/O PORTs. 1: Disable pull-ups of all pins of all I/O PORTs. IVSEL: Interrupt vector select 0: Interrupt vectors are placed at the start of the flash memory (i.e., 0x0002). 1: Interrupt vectors are placed at the start of the boot section. The start of the boot section is set by programming the BOOTSZ fuses. IVCE: Interrupt vector change enable 0: Disable interrupt vector change 1: Enable interrupt vector to be changed Figure 9.1 ■ Source: Atmel Corporation, The Atmel AVR Microcontroller 7 JTD MCU configuration register A special write procedure must be followed in order to change the IVSEL bit: Step 1 Write the IVCE bit to 1. Step 2 Within four system clock cycles, write the desired value to IVSEL while writing a 0 to the IVCE bit. The following assembly instruction sequence implements this procedure: in mov ori out ori out r16,MCUCR r17,r16 r16,(1 << IVCE) MCUCR,r16 r17,(1 << IVSEL) MCUCR,r17 ; sets the IVCE bit ; sets IVSEL bit and clears IVCE bit Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 9.4 ■ 267 The AVR Mega Interrupts The same operation is implemented by the following sequence of C statements: unsigned … temp MCUCR MCUCR char temp; = MCUCR; = temp | (1 << IVCE); = temp | (1 << IVSEL); // sets the IVCE bit // sets the IVSEL bit and clears the IVCE bit 9.4.3 AVR Mega External Interrupt Pins 7 6 5 4 3 2 1 0 ISC31 ISC30 ISC21 ISC20 ISC11 ISC10 ISC01 ISC00 R/W R/W R/W R/W R/W R/W R/W R/W Reset value = 0x00 ISCn1: ISCn0: External interrupt 3~0 sense control bits 00 = The low level of INTn generates an interrupt request. 01 = Any edge of INTn generates an interrupt request. 10 = The falling edge of INTn generates an interrupt request. 11 = The rising edge of INTn generates an interrupt request. n = 0~3. ■ External interrupt control register A (EICRA) 7 6 5 4 3 2 1 0 ISC71 ISC70 ISC61 ISC60 ISC51 ISC50 ISC41 ISC40 R/W R/W R/W R/W R/W R/W R/W R/W Reset value = 0x00 ISCn1: ISCn0: External interrupt 7~4 sense control bits 00 = The low level of INTn generates an interrupt request. 01 = Any edge of INTn generates an interrupt request. 10 = The falling edge of INTn generates an interrupt request. 11 = The rising edge of INTn generates an interrupt request. n = 7, …, 4. Figure 9.3 ■ External interrupt control register B (EICRB) Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. Source: Atmel Corporation, The Atmel AVR Microcontroller Figure 9.2 Source: Atmel Corporation, The Atmel AVR Microcontroller The INT7:0 pins trigger interrupt requests to the MCU. These interrupts share the use of pins with PORTD and E (INT0/PD0, INT1/PD1, INT2/PD2, INT3/PD3, INT4/PE4, INT5/ PE5, INT6/PE6, INT7/PE7). External interrupts are triggered by a falling edge, a rising edge, or a low level. This is set up by programming the EICRA and EICRB registers. The EICRA register controls the triggering method for INT3~0, and the EICRB register controls the triggering method for INT7:4. The contents of EICRA and EICRB are shown in Figure 9.2 and Figure 9.3, respectively. Each of these external interrupt is disabled by clearing the associated mask bit in the EIMSK register. Whenever one of these external interrupt conditions occurs, the associated flag bit in the EIFR register is set to 1. The flag bit is cleared when the associated interrupt service routine is entered. The flag bit is also cleared by writing a 1 to it. The contents of EIMSK and EIFR are shown in Figure 9.4 and Figure 9.5, respectively. ■ Interrupt Handling, Resets, and Power Management 7 6 5 4 3 2 1 0 INT7 INT6 INT5 INT4 INT3 INT2 INT1 INT0 R/W R/W R/W R/W R/W R/W R/W R/W Reset value = 0x00 INTn: External interrupt request n enable (n = 0, …, 7) 0 = External interrupt n is disabled. 1 = External interrupt n is enabled. Figure 9.4 ■ External interrupt mask register (EIMSK) 7 6 5 4 3 2 1 0 INTF7 INTF6 INTF5 INTF4 INTF3 INTF2 INTF1 INTF0 R/W R/W R/W R/W R/W R/W R/W R/W Reset value = 0x00 INTFn: External interrupt flag n (n = 0, …, 7) 0 = External interrupt n condition did not occur since last time this flag was cleared. 1 = External interrupt n condition has occurred. Figure 9.5 ■ Source: Atmel Corporation, The Atmel AVR Microcontroller Chapter 9 Source: Atmel Corporation, The Atmel AVR Microcontroller 268 External interrupt flag register (EIFR) 9.4.4 Pin Change Interrupt The ATMega640/1280/2560 has 24 pins (PCINT23~0) that generate interrupt whenever one or more of these pins toggle. Pin change interrupt PCINT2 triggers if any enabled PCINT23~16 pin toggles; pin change interrupt PCINT1 triggers if any enabled PCINT15~8 pin toggles; and pin change interrupt PCINT0 triggers if any enabled PCINT7~0 pin toggles. Pin change interrupts on PCINT23:0 are detected asynchronously. This implies that these interrupts are used to wake up the MCU from sleep mode or idle mode. Each of the three pin change interrupts is enabled by setting the corresponding bit in the PCICR register, and each has an associated flag bit in the PCIFR register. The contents of these registers are shown in Figure 9.6 and Figure 9.7, respectively. Each of the 24 pins must be enabled before it can generate a pin change interrupt. The registers PCMSK2, PCMSK1, and PCMSK0 control the enabling and disabling of these 24 pins from generating interrupts. The contents of these three registers are shown in Figure 9.8 through Figure 9.10. 6 5 4 3 2 1 0 — — — — PCIE2 PCIE1 PCIE0 R R R R R R/W R/W R/W PCIE2: Pin change interrupt enable 2 0 = Pin change interrupt 2 disabled 1 = Pin change interrupt 2 enabled (any change on any enabled PCINT23~16 pin will cause an interrupt; PCINT23~16 pins are enabled individually by the PCMSK2 register). PCIE1: Pin change interrupt enable 1 0 = Pin change interrupt 1 disabled 1 = Pin change interrupt 1 enabled (any change on any enabled PCINT15~8 pin will cause an interrupt; PCINT15~8 pins are enabled individually by the PCMSK1 register). PCIE0: Pin change interrupt enable 0 0 = Pin change interrupt 0 disabled 1 = Pin change interrupt 0 enabled (any change on any enabled PCINT7~0 pin will cause an interrupt; PCINT7~0 pins are enabled individually by the PCMSK0 register). Figure 9.6 ■ Reset value = 0x00 Source: Atmel Corporation, The Atmel AVR Microcontroller 7 — Pin change interrupt control register (PCICR) Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 7 6 5 4 3 2 1 0 — — — — — PCIF2 PCIF1 PCIF0 R R R R R R/W R/W R/W Reset value = 0x00 PCIF2: Pin change interrupt flag 2 0 = No pins among PCINT23~16 have changed value. 1 = At least one of the PCINT23~16 pins has changed value. PCIF1: Pin change interrupt flag 1 0 = No pins among PCINT15~8 have changed value. 1 = At least one of the PCINT15~8 pins has changed value. PCIF0: Pin change interrupt flag 0 0 = No pins among PCINT7~0 have changed value. 1 = At least one of the PCINT7~0 pins has changed value. ■ Pin change interrupt flag register (PCIFR) 7 6 5 4 3 2 1 0 PCINT23 PCINT22 PCINT21 PCINT20 PCINT19 PCINT18 PCINT17 PCINT16 R/W R/W R/W R/W R/W R/W R/W R/W Reset value = 0x00 PCINTn: Pin change enable mask n (n = 23, …, 16) 0 = Disable pin change interrupt on the PCINTn pin 1 = Enable pin change on the PCINTn pin to interrupt the CPU. Both this bit and the PCIE2 bit of the PCICR register must be set in order for the interrupt to be enabled. Figure 9.8 ■ Source: Atmel Corporation, The Atmel AVR Microcontroller Figure 9.7 Source: Atmel Corporation, The Atmel AVR Microcontroller 269 The AVR Mega Interrupts Pin change mask register 2 (PCMSK2) 7 6 5 4 3 2 1 0 PCINT15 PCINT14 PCINT13 PCINT12 PCINT11 PCINT10 PCINT9 PCINT8 R/W R/W R/W R/W R/W R/W R/W R/W Reset value = 0x00 PCINTn: Pin change enable mask n (n = 15, …, 8) 0 = Disable pin change interrupt on the PCINTn pin 1 = Enable pin change on the PCINTn pin to interrupt the CPU. Both this bit and the PCIE1 bit of the PCICR register must be set in order for the interrupt to be enabled. Figure 9.9 ■ Pin change mask register 1 (PCMSK1) 7 6 5 4 3 2 1 0 PCINT7 PCINT6 PCINT5 PCINT4 PCINT3 PCINT2 PCINT1 PCINT0 R/W R/W R/W R/W R/W R/W R/W R/W Reset value = 0x00 PCINTn: Pin change enable mask n (n = 7, …, 0) 0 = Disable pin change interrupt on the PCINTn pin 1 = Enable pin change on the PCINTn pin to interrupt the CPU. Both this bit and the PCIE0 bit of the PCICR register must be set in order for the interrupt to be enabled. Figure 9.10 Source: Atmel Corporation, The Atmel AVR Microcontroller ■ ■ Pin change mask register0 (PCMSK0) Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. Source: Atmel Corporation, The Atmel AVR Microcontroller 9.4 270 Chapter 9 ■ Interrupt Handling, Resets, and Power Management Example 9.1 ▼ Write a main program and an interrupt service routine for the INT0 interrupt in assembly language. The main program configures PORTA for output and enables INT0 to interrupt on the falling edge and also initializes the variable cnt to 0. After that, the main program stays in an infinite loop to wait for INT0 interrupt to occur. The INT0 service routine simply increments cnt by 1 and outputs it to PORTA. Solution: The assembly language version of the program is as follows: .include <m2560def.inc> .def cnt = r20 .def tmp = r16 .cseg .org 0x00 jmp start jmp INT0_ISR .org 0xF6 ldi tmp,low(RAMEND) out SPL,tmp ldi r16,high(RAMEND) out SPH,tmp ldi tmp,0xFF out DDRA,tmp lds tmp,DDRD andi tmp,0xFE sts DDRD,tmp ldi cnt,0 ldi tmp,0x02 sts EICRA,tmp ldi tmp,0x01 sts EIMSK,tmp sei jmp again start: again: ; use r20 as cnt ; initialize the SP ; " ; " ; " ; configure PORTA for output ; " ; configure PD0/INT0 pin for input ; " ; " ; initialize cnt to 0 ; configure INT0 to interrupt on the falling edge ; " ; enable INT0 interrupt ; " ; enable interrupt globally ; forever loop ; -------------------------------------------------------------------------------------------------------------; The following is the service routine for INT0 ; -------------------------------------------------------------------------------------------------------------INT0_ISR: inc out reti cnt PORTA,cnt ; output cnt to PORTA ▲ 9.4.5 Writing Interrupt Service Routine in C for AVR Mega Devices The AVR interrupt is enabled and disabled globally by invoking the following two macros (defined in interrupt.h): • • sei()—enables interrupt globally cli()—disables interrupt globally Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 9.4 ■ The AVR Mega Interrupts 271 To provide service to interrupt, the AVR Studio C compiler requires the user to use the following format to write an interrupt service routine: ISR (vector number of the interrupt) { … } The symbolic names of all interrupt vector numbers and interrupt vectors have been defined in the appropriate header file (C language) and include file (assembly language). For example, the symbolic names of all interrupt vector numbers for the ATMega640/1280/2560 are defined in the iomxx0_1.h and are listed in Table 9.3. The symbolic name of the INT0 vector number is INT0_vect. The user also needs to include the interrupt.h file into his or her program. This file contains all the definitions and macros related to interrupt handling. For assembly language, the user derives the symbolic name of an interrupt source by changing the suffix _vect to Addr in Table 9.3 for each interrupt source when dealing with the Mega device interrupts. For example, use INT0addr is the symbolic name of the INT0 interrupt in assembly language. Example 9.2 ▼ Write the C language version of the interrupt service routine and the main function described in Example 9.1. Solution: The C language version of the interrupt service routine and the main function are as follows: #include <avr\io.h> #include <avr\interrupt.h> unsigned char cnt; int main (void) { DDRA = 0xFF; // configure PORTA for output DDRD &= 0xFE; // configure PD0/INT0 pin for input EICRA = 0x02; // configure INT0 to interrupt on the falling edge EIMSK = 0x01; // enable INT0 interrupt sei(); // enable interrupt globally cnt = 0; while(1); // wait for INT0 to occur return 0; } // -----------------------------------------------------------------------------------------------------// INT0 interrupt service routine. // -----------------------------------------------------------------------------------------------------ISR(INT0_vect) { cnt++; PORTA = cnt; // output cnt to PORTA } ▲ Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 272 Chapter 9 Interrupt source INT0 ■ Interrupt Handling, Resets, and Power Management Vector number 1 Symbolic name INT0_vect Interrupt source ADC Vector number 29 Symbolic name ADCC_vect INT1 2 INT1_vect EE READY 30 ERDY_vect INT2 3 INT2_vect TIMER3 CAPT 31 ICP3_vect INT3 4 INT3_vect TIMER3 COMPA 32 OC3A_vect INT4 5 INT4_vect TIMER3 COMPB 33 OC3B_vect INT5 6 INT5_vect TIMER3 COMPC 34 OC3C_vect INT6 7 INT6_vect TIMER3 OVF 35 OVF3_vect INT7 8 INT7_vect USART1 RX 36 URXC1_vect PCINT0 9 PCI0_vect USART1 UDRE 37 UDRE1_vect PCINT1 10 PCI1_vect USART1 TX 38 UTXC1_vect PCINT2 11 PCI2_vect TWI 39 TWI_vect WDT 12 WDT_vect SPM READY 40 SPMR_vect TIMER2 COMPA 13 OC2A_vect TIMER4 CAPT 41 ICP4_vect TIMER2 COMPB 14 OC2B_vect TIMER4 COMPA 42 OC4A_vect TIMER2 OVF 15 OVF2_vect TIMER4 COMPB 43 OC4B_vect TIMER1 CAPT 16 ICP1_vect TIMER4 COMPC 44 OC4C_vect TIMER1 COMPA 17 OC1A_vect TIMER4 OVF 45 OVF4_vect TIMER1 COMPB 18 OC1B_vect TIMER5 CAPT 46 ICP5_vect TIMER1 COMPC 19 OC1C_vect TIMER5 COMPA 47 OC5A_vect TIMER1 OVF 20 OVF1_vect TIMER5 COMPB 48 OC5B_vect TIMER0 COMPA 21 OC0A_vect TIMER5 COMPC 49 OC5C_vect TIMER0 COMPB 22 OC0B_vect TIMER5 OVF 50 OVF5_vect TIMER0 OVF 23 OVF0_vect USART2 RX 51 URXC2_vect SPI STC 24 SPI_vect USART2 UDRE 52 UDRE2_vect USART0 RX 25 URXC0_vect USART2 TX 53 UTXC2_vect USART0 UDRE 26 UDRE0_vect USART3 RX 54 URXC3_vect USART0 TX 27 UTXC0_vect USART3 UDRE 55 UDRE3_vect ANALOG COMP 28 ACI_vect USART3 TX 56 UTXC3_vect Source: Atmel Corporation, The Atmel AVR Microcontroller Table 9.3 ■ Symbolic name of vector numbers for ATMega640/1280/2560 9.5 The XMega Device Interrupts The interrupt structure of the XMega family of AVR devices is different from that of the Mega family. The XMega has a programmable multi-level interrupt controller (PMIC). The XMega supports maskable and nonmaskable interrupts. All peripheral interrupts are maskable. These interrupts are programmed to three different priority levels: high, medium, or low. Medium-level interrupts may interrupt low-level interrupt service routines. High-level Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 9.5 ■ The XMega Device Interrupts 273 interrupts may interrupt both low- and medium-level interrupt service routines. Low-level interrupts have an optional round-robin scheme to make sure all interrupts are serviced within a certain amount of time. The built-in oscillator failure detection mechanism can issue a nonmaskable Interrupt (NMI). 9.5.1 PMIC Operation Interrupts must be globally enabled for any interrupt to be generated. This is done by setting the global interrupt enable bit (I bit) in the CPU status register. The I bit is not cleared when an interrupt is acknowledged (also true for Mega devices). Each interrupt level (high, medium, and low) must be enabled before interrupts at the corresponding level can be generated. When an interrupt is enabled and the interrupt condition is present, the PMIC receives the interrupt request. Based on the interrupt level and interrupt priority of all ongoing interrupts, the new interrupt is either acknowledged or kept pending until it has the priority. The PMIC status register contains state information that ensures that the PMIC returns to the correct interrupt level when the RETI instruction is executed at the end of an interrupt handler. Returning from an interrupt returns the PMIC to the state it was at before entering the interrupt service routine. 9.5.2 XMega Maskable Interrupts All interrupts have an interrupt flag and individual control bits for enabling and setting the interrupt level. When the interrupt condition is present, the interrupt flag is set, even if the corresponding interrupt is not enabled. For most interrupts, the interrupt flag is automatically cleared when the interrupt service routine is entered. The interrupt flag can also be cleared by writing a 1 to it. If an interrupt condition occurs while another interrupt of higher priority is being serviced or pending, the interrupt flag is set and remembered until the interrupt has the priority. If an interrupt condition occurs while the corresponding interrupt is not enabled, the interrupt flag is set and remembered until the interrupt is enabled or the flag is cleared by software. Similarly, if one or more interrupt conditions occur while global interrupts are disabled, the corresponding interrupt flag is set and remembered until the global interrupt is enabled. All pending interrupts are then serviced according to their orders of priority. Interrupts are automatically disabled for up to 4 CPU clock cycles when the configuration change protection register (CPU.CCP) is written with the correct signature. There are two CCP signatures. One signature (0x9D) is for the store program memory (SPM) instruction. The other (0xD8) is for protecting unintentional write into the protected peripheral registers. The user must load the correct signature value into the CCP register before he or she can execute the SPM instruction or write into the peripheral register protected by this mechanism. 9.5.3 XMega Nonmaskable Interrupt Currently, the XMega devices have only one nonmaskable interrupt (NMI)—crystal oscillator failure. An NMI is serviced regardless of the setting of the I bit and it does not change the I bit. No maskable interrupt can interrupt a NMI interrupt handler. 9.5.4 XMega Interrupt Level The interrupt level can be independently set for each interrupt source. Each interrupt source uses two bits to configure its level as shown in Table 9.4. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 274 Chapter 9 ■ Interrupt Handling, Resets, and Power Management Interrupt level configuration Group configuration 00 OFF Interrupt disabled 01 LO Low-level interrupt 10 MED 11 HI Description Medium-level interrupt High-level interrupt Source: Atmel Corporation, The Atmel AVR Microcontroller ■ Table 9.4 XMega interrupt level 9.5.5 XMega Interrupt Priority Within each interrupt level, all interrupts have a priority. Whenever several interrupt requests are pending, the order of which interrupts are acknowledged is decided both by the level and the priority of the interrupt request. Interrupts in high or medium level have static priority. Low-level interrupts may have either static or round-robin (dynamic) priority within the low level. Interrupt vectors are located at fixed addresses. For static priority, the interrupt vector decides the priority within one interrupt level where the lowest interrupt vector has the highest priority. When the round-robin scheduling is enabled for low-priority interrupts, the interrupt vector for the last acknowledged low-level interrupt has the lowest priority next time one or more interrupts from the low level is requested. This is shown in Figure 9.11. IVEC x is the last acknowledged interrupt IVEC 0 IVEC 0 Lowest priority Highest priority IVEC N Figure 9.11 IVEC x IVEC x+1 Lowest priority IVEC x+2 Highest priority IVEC N ■ Source: Atmel Corporation, The Atmel AVR Microcontroller IVEC x IVEC x+1 IVEC x+1 is the last acknowledged interrupt Round-robin interrupt priority scheduling 9.5.6 PMIC Registers The PMIC has three registers to support its functioning. The PMIC status register (PMIC. STATUS) indicates which type of interrupts is being serviced (nonmaskable, high level, medium level, or low level). The PMIC priority register (PMIC.INTPRI) stores the interrupt vector of the last acknowledged low-level interrupt when the round-robin scheduling is enabled. The PMIC control register (PMIC.CTRL) enables/disables round-robin scheduling, high-level interrupts, medium-level interrupts, low-level interrupts, and interrupt vector relocation to boot section. The contents of these registers are shown in Figure 9.12, Figure 9.13, and Figure 9.14, respectively. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 275 The XMega Device Interrupts 6 5 4 3 — — — — R R R R R 2 1 0 HILVLEX MEDLVLEX LOLVLEX R R Reset value = 0x00 R Source: Atmel Corporation, The Atmel AVR Microcontroller 7 NMIEX NMIEX: Nonmaskable interrupt executing 0: Nonmaskable interrupt service routine is not executing. 1: Nonmaskable interrupt service routine is executing. HILVLEX: High-level interrupt executing 0: High-priority-level interrupt service routine is not executing. 1: High-priority-level interrupt service routine is executing. MEDLVLEX: Medium-level interrupt executing 0: Medium-priority-level interrupt service routine is not executing. 1: Medium-priority-level interrupt service routine is executing. LOLVLEX: Low-level interrupt executing 0: Low-priority-level interrupt service routine is not executing. 1: Low-priority-level interrupt service routine is executing. Figure 9.12 ■ 7 PMIC status register (PMIC.STATUS) 6 5 4 3 2 1 0 R/W R/W R/W INTPRI[7:0] R/W R/W R/W R/W R/W Reset value = 0x00 INTPRI: Interrupt priority When round-robin scheduling is enabled, this register stores the interrupt vector of the last acknowledged low-level interrupt. The stored interrupt vector will have the lowest priority next time one or more low-level interrupts are pending. The register is accessible from software to change the priority queue. This register is not reinitialized to its initial value if round-robin scheduling is disabled. So if default static priority is needed the register must be written into zero. Figure 9.13 ■ PMIC priority register (PMIC.INTPRI) 7 6 5 4 3 RREN IVSEL — — — R/W R/W R R R 2 1 0 HILVLEN MEDLVLEN LOLVLEN R/W R/W Reset value = 0x00 R/W RREN: Round-robin scheduling enable 0 = Low-level interrupts round-robin is disabled. 1 = Low-level interrupts round-robin is enabled. IVSEL: Interrupt vector select 0 = Interrupt vectors are placed at the start of on-chip flash memory. 1 = Interrupt vectors are moved to the start of the boot section of the flash memory. HILVLEN: High-level interrupt enable 0 = High-level interrupts disabled 1 = High-level interrupts enabled MEDLVLEN: Medium-level interrupt enable 0 = Medium-level interrupts disabled 1 = Medium-level interrupts enabled LOLVLEN: Low-level interrupt enable 0 = Low-level interrupts disabled 1 = Low-level interrupts enabled Figure 9.14 ■ Source: Atmel Corporation, The Atmel AVR Microcontroller ■ PMIC control register (PMIC.CTRL) Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. Source: Atmel Corporation, The Atmel AVR Microcontroller 9.5 276 Chapter 9 ■ Interrupt Handling, Resets, and Power Management To change the IVSEL bit of the PMIC.CTRL register, the user must write the signature value 0xD8 into the configuration change protection register (CCP) and then write the appropriate value into the PMIC.CTRL register to change the IVSEL bit. 9.5.7 XMega Interrupt Sources Among all XMega devices, the XMega64A1/128A1/256A1/384A1 have the most pins and interrupt sources. A base address is assigned to each peripheral module’s interrupts and each peripheral module may have one or multiple interrupt sources. The base interrupt addresses for the XMega A1 devices are given in Table 9.5. If a module has only one interrupt source, then the base interrupt address is also its interrupt vector. The include file ATXMega128A1def. inc (provided by AVR Studio IDE) contains the symbolic names of all interrupt vectors for the assembly language programmers. The list of all interrupt vectors and their symbolic names is given in Appendix B. The header file iox128a1.h contains the symbolic names of all interrupt vector numbers (of XMega64A1/128A1/256A1/384A1) to be used to indicate interrupt source in the interrupt service routine (for C language programmers). The complete list of these symbolic names is given in Appendix C. Base address (word address) Source Description 0×000 RESET 0×002 OSCF_INT_vect Crystal oscillator failure interrupt vector (NMI) 0×004 PORTC_INT_base PORTC interrupt base 0×008 PORTR_INT_base PORTR interrupt base 0×00C DMA_INT_base DMA controller interrupt base 0×014 RTC_INT_vect Real-time counter interrupt base 0×018 TWIC_INT_base Two-wire interface on PORTC interrupt base 0×01C TCC0_INT_vect Timer/Counter0 on PORTC interrupt base 0×028 TCC1_INT_vect Timer/Counter1 on PORTC interrupt base 0×030 SPIC_INT_vect SPI on PORTC interrupt base 0×032 USARTC0_INT_base USART0 on PORTC interrupt base 0×038 USARTC1_INT_base USART1 on PORTC interrupt base 0×03E AES_INT_vect AES interrupt vector 0×040 NVM_INT_base Nonvolatile memory interrupt base 0×044 PORTB_INT_base PORTB interrupt base 0×048 ACB_INT_base Analog comparator on PORTB interrupt base 0×04E ADCB_INT_base Analog to digital converter on PORTB interrupt base 0×056 PORTE_INT_base PORTE interrupt base 0×05A TWIE_INT_base Two-wire interface on PORTE interrupt base 0×05E TCE0_INT_base Timer/Counter0 on PORTE interrupt base (Continued) Table 9.5 ■ Reset and interrupt vector base addresses Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 9.5 ■ 277 The XMega Device Interrupts Table 9.5 ■ (Continued) Base address (word address) Source Description 0×06A TCE1_INT_base Timer/Counter1 on PORTE interrupt base 0×072 SPIE_INT_vect SPI on PORTE interrupt vector 0×074 USARTE0_INT_base USART0 on PORTE interrupt base 0×07A USARTE1_INT_base USART1 on PORTE interrupt base 0×080 PORTD_INT_base PORTD interrupt base 0×084 PORTA_INT_base PORTA interrupt base 0×088 ACA_INT_base Analog comparator on PORTA interrupt base 0×08E ADCA_INT_base Analog to digital converter on PORTA interrupt base 0×096 TWID_INT_base Two-wire interface on PORTD interrupt base 0×09A TCD0_INT_base Timer/Counter0 on PORTD interrupt base 0×0A6 TCD1_INT_base Timer/Counter1 on PORTD interrupt base 0×0AE SPID_INT_vect SPI on PORTD interrupt vector 0×0B0 USARTD0_INT_base USART0 on PORTD interrupt base 0×0B6 USARTD1_INT_base USART1 on PORTD interrupt base 0×0BC PORTQ_INT_base PORTQ interrupt base 0×0C0 PORTH_INT_base PORTH interrupt base 0×0C4 PORTJ_INT_base PORTJ interrupt base 0×0C8 PORTK_INT_base PORTK interrupt base 0×0D0 PORTF_INT_base PORTF interrupt base 0×0D4 TWIF_INT_base Two-wire interface on PORTF interrupt base 0×0D8 TCF0_INT_base Timer/Counter0 on PORTF interrupt base 0×0E4 TCF1_INT_base Timer/Counter1 on PORTF interrupt base 0×0EC SPIF_INT_base SPI on PORTF interrupt base 0×0EE USARTF0_INT_base USART0 on PORTF interrupt base 0×0F4 USARTF1_INT_base USART1 on PORTF interrupt base Source: Atmel Corporation, The Atmel AVR Microcontroller 9.5.8 XMega PORT Interrupt Unlike Mega devices, XMega devices have neither dedicated interrupt pins nor pin-change interrupts. Instead, each XMega I/O PORT has two interrupt vectors. Every pin can be configured to trigger an interrupt request. The I/O PORT uses a sensing circuit to detect an edge or the level on the I/O pin. The different sense configurations that are available to each pin are detection of a rising edge, a falling edge, both edges, and a low level. A high level can be detected by using an inverted input. Input sensing is used to trigger interrupt requests or sense when there is a change on the pin. As shown in Figure 9.15, the I/O pins support synchronous and asynchronous input sensing. Synchronous sensing requires presence of the peripheral clock, while asynchronous sensing does not require any clock. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 278 Chapter 9 ■ Interrupt Handling, Resets, and Power Management Edge detect Interrupt control IREQ Synchronous sensing Pn Synchronizer Edge detect D Q D Q R R Inverted I/O EVENT clkIO ■ Figure 9.15 Source: Atmel Corporation, The Atmel AVR Microcontroller Asynchronous sensing XMega input sensing circuit For synchronous sensing, all sense configurations are used to generate interrupts. For edge detection, the changed pin value must be sampled once by the peripheral clock for an interrupt request to be generated. For asynchronous sensing, only the pin 2 of each PORT has full asynchronous sense support. This means that for edge detection, pin 2 detects and latches any edge, and it always triggers an interrupt request. The other PORT pins have limited asynchronous sense support. This means that for edge detection the changed value must be held until the device wakes up and a clock is present. If the pin value returns to its initial value before the end of the device startup time, the device still wakes up, but no interrupt request is generated. A low level is always detected by all pins, regardless of a peripheral clock being present or not. If a pin is configured for low-level sensing, the interrupt is triggered as long as the pin is held low. In active mode the low level must be kept until the completion of the currently executing instructions for an interrupt to be generated. In all sleep modes the low level must be kept until the end of the device startup time for an interrupt to be generated. If the low level disappears before the end of the startup time, the device still wakes up, but no interrupt is generated. INT0 AND I N T 1 I N T E R R U P T C O N F I G U R AT I O N 7 6 5 4 3 — — — — INT1LVL[1:0] R R R R R/W INTnLVL[1:0]: Interrupt n level, n = 0 or 1 00 = Interrupt disabled 01 = Low level 10 = Medium level 11 = High level Figure 9.16 ■ 2 R/W 1 0 INT0LVL[1:0] R/W R/W Reset value = 0x00 Source: Atmel Corporation, The Atmel AVR Microcontroller Like any other interrupt source, INT0 and INT1 can be configured to low, medium, or high level. The PORTx.INTCTRL (x = A, …, R) register controls the setting of interrupt levels of INT0 and INT1 for PORTx. The contents of this register are shown in Figure 9.16. Interrupt control register (PORTx.INTCTRL) Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 9.5 ■ 279 The XMega Device Interrupts ASSIGNING I/O PINS AS SOURCES OF INT0 OR INT1 6 5 4 3 2 1 0 R/W R/W R/W 2 1 0 R/W R/W R/W INT0MSK[7:0] R/W R/W R/W R/W R/W Reset value = 0x00 INT0MSK[n]: Interrupt 0 mask, n = 7, …, 0 0 = Pin n is not the source for INT0 interrupt. 1 = Pin n is the source for INT0 interrupt. Figure 9.17 ■ 7 Interrupt 0 mask register (PORTx.INT0MASK) 6 5 4 3 INT1MSK[7:0] R/W R/W R/W R/W R/W Reset value = 0x00 INT1MSK[n]: Interrupt 0 mask, n = 7, …, 0 0 = Pin n is not the source for INT1 interrupt. 1 = Pin n is the source for INT1 interrupt. Figure 9.18 ■ Source: Atmel Corporation, The Atmel AVR Microcontroller 7 Source: Atmel Corporation, The Atmel AVR Microcontroller The user uses the PORTx.INT0MASK (x = A, …, R) and PORTx.INT1MASK registers to select those pins that can generate INT0 or INT1 interrupt, respectively. The contents of these two registers are shown in Figure 9.17 and Figure 9.18, respectively. Interrupt 1 mask register (PORTx.INT1MASK) I N P U T S E N S E C O N F I G U R AT I O N 7 6 5 4 3 2 1 0 R/W R/W R/W MPCMASK[7:0] R/W R/W R/W R/W R/W Reset value = 0x00 MPCMASK[n]: Multi-pin configuration mask (n = 7, …, 0) 0 = Pin n is not part of the multi-pin configuration. 1 = Pin n is part of the multi-pin configuration. When a pin configuration is written to one of the PINnCTRL registers of the PORT, that value is written to all the PINnCTRL registers of the pins matching the bit pattern in the MPCMASK register for that PORT. It is not necessary to write to one of the registers that is set by the MPCMASK register. The MPCMASK register is automatically cleared after any PINnCTRL registers is written. Figure 9.19 ■ Multipin configuration mask register (PORTCFG.MPCMASK) Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. Source: Atmel Corporation, The Atmel AVR Microcontroller After assigning a pin as a source of INT0 or INT1, the user also needs to configure the sense of the pin. By configuring the sense of a pin, the user can choose to use the low level, rising edge, falling edge, or both edges of a pin to interrupt the MCU. Each pin has an associated configuration register. The contents of the pin configuration register are shown in Figure 8.12. It is common for multiple pins to have the same configuration. The multipin configuration mask register allows multiple pins with identical configuration to be configured at the same time. The contents of this register are shown in Figure 9.19. 280 Chapter 9 ■ Interrupt Handling, Resets, and Power Management INTERRUPT FLAG REGISTER 7 6 5 4 3 2 1 0 — — — — — — INT1IF INT0IF R R R R R R R/W R/W Reset value = 0x00 INTnIF: Interrupt n flag (n = 0 or 1) 0 = No interrupt n condition occurred 1 = One or more of the input change according to the pin configuration has occurred. Figure 9.20 ■ Source: Atmel Corporation, The Atmel AVR Microcontroller The INT0 and INT1 interrupts of an I/O PORT has an associated flag bit in the interrupt flag register. The INTxIF flag is set when a pin change according to the pin’s input sense configuration occurs, and the pin is set as source for PORT interrupt n. Writing a 1 to this flag’s bit location clears the flag. The contents of the interrupt flag register are shown in Figure 9.20. Interrupt flag register (PORTx.INTFLAGS) Example 9.3 ▼ Write a sequence of assembly instructions to configure PORTA pins 3~0 as sources of INT0 and pins 7~4 as sources of INT1. Configure pins 3~0 to interrupt on the falling edge and pins 7~4 to interrupt on the rising edge. Place INT0 and INT1 at high- and medium-level priority, respectively. Solution: For pins 3~0, we disable slew rate limit and pin inverting input, configure pin to totem pole, and interrupt on the falling edge. For pins 7~4, we disable slew rate limit and pin inverting input, configure pin output to totem pole, and interrupt on the rising edge. The following instruction sequence can achieve the specified setting: ldi sts ldi sts ldi sts ldi sts ldi sts ldi sts ldi sts ldi sts tmp,0 PORTA_DIR,tmp tmp,0x0B PORTA_INTCTRL,tmp tmp,0x0F PORTA_INT0MASK,tmp tmp,0xF0 PORTA_INT1MASK,tmp tmp,0x0F PORTCFG_MPCMASK,tmp tmp,0x02 PORTA_PIN0CTRL,tmp tmp,0xF0 PORTCFG_MPCMASK,tmp tmp,0x01 PORTA_PIN4CTRL,tmp ; configure PORTA for input ; INT1 at medium level, INT0 at high level ; " ; assign pin 3~0 as source of INT0 ; " ; assign pin 7~4 as source of INT1 ; " ; let pins 3~0 to be configured simultaneously ; " ; configure pins 3~0 to interrupt MCU ; on their falling edge, disable slew rate limit ; let pins 7~4 to be configured simultaneously ; " ; configure pins 7~4 to interrupt MCU ; on their rising edge, disable slew rate limit ▲ Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 9.5 ■ 281 The XMega Device Interrupts Example 9.4 ▼ Write a sequence of C statements to configure PORTA pins as described in Example 9.3. Solution: The following C statements can perform the same configuration as that in Example 9.3: PORTA.DIR PORTA.INTCTRL PORTA.INT0MASK PORTA.INT1MASK PORTCFG.MPCMASK PORTA.PIN0CTRL PORTCFG.MPCMASK PORTA.PIN4CTRL = 0; = 0x0B; = 0x0F; = 0xF0; = 0x0F; = 0x02; = 0xF0; = 0x01; // configure PORTA for input // place INT1, INT0 at high, medium level // assign pin 3~0 as source of INT0 // assign pin 7~4 as source of INT1 // let pin 3~0 to be configured simultaneously // configure pin 3~0 to interrupt on falling edge // let pin 7~4 to be configured simultaneously // configure pin 7~4 to interrupt on rising edge ▲ Example 9.5 ▼ Write an assembly main program and the service routine for the INT0 interrupt associated with PORTF. The main program assigns the pin 0~3 of PORTF as a source of INT0 and configures it to interrupt on the rising edge and also configures PORTC pin 7, 5, 3, and 1 for output. INT0 is placed at highlevel priority. The INT0 service routine for PORTF simply toggles the PORTC odd pins and returns. Solution: The following program performs the specified operations: .include .def .cseg .org jmp .org jmp .org start: ldi out ldi out call ldi sts ldi sts ldi sts ldi sts ldi sts ldi sts ldi <ATXMega128A1def.inc> tmp = r16 0x00 start PORTF_INT0_vect PF_INT0_ISR 0xF6 tmp,low(RAMEND) CPU_SPL,tmp tmp,high(RAMEND) CPU_SPH,tmp setCPUclkto32Mwith16Mcrystal tmp,0xAA PORTC_DIR,tmp tmp,0xAA PORTC_OUT,tmp tmp,0 PORTF_DIR,tmp tmp,0x0F PORTF_INT0MASK,tmp tmp,0x03 PORTF_INTCTRL,tmp tmp,0x07 PMIC_CTRL,tmp tmp,0x0F ; PORTF INT0 interrupt vector ; initialize the SP ; " ; " ; " ; configure PORTC pins 7, 5, 3, and 1 for output ; " ; set PORTC pins 7, 5, 3, and 1 to high initially ; " ; configure PORTF pin 0~3 for input ; " ; place pin 0~3 as a source of INT0 ; " ; place INT0 at high-level priority ; " ; enable high-, medium-, and low-priority interrupts ; configure pin 0~3 Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 282 Chapter 9 ■ Interrupt Handling, Resets, and Power Management sts PORTCFG_MPCMASK,tmp ldi tmp,0x01 ; configure PORTF pin 3~0 to interrupt sts PORTF_PIN0CTRL,tmp ; on the rising edge sei ; enable interrupt globally again: rjmp again ; wait for INT0 interrupt to occur ; -------------------------------------------------------------------------------------------------------------; PORTF INT0 interrupt service routine toggles all PORTC pins and returns. ; -------------------------------------------------------------------------------------------------------------PF_INT0_ISR: ldi tmp,0x01 ; clear the INT0IF flag sts PORTF_INTFLAGS,tmp ; " ldi tmp,0xAA sts PORTC_OUTTGL,tmp ; toggle pins PC7, PC5, PX3, and PC0 reti .include "sysClock_XMega.asm" ▲ Example 9.6 ▼ Write the C language version of the main function and interrupt service routine described in Example 9.5. Solution: The C language version of the main function and the service routine for the PORTF INT0 interrupt are as follows: #include <avr\io.h> #include <avr\interrupt.h> #include "sysClock_XMega.h" void main (void) { setCPUclkto32Mwith16MCrystal(); PORTC.DIR = 0xAA; // configure PORTC pins 7, 5, 3, and 1 for output PORTC.OUT = 0xAA; // turn on PORTC odd pins PORTF.DIR = 0; // configure PORTF pin 0~3 for input PORTF.INT0MASK = 0x0F; // include PORTF pin 0~3 as sources of INT0 PORTF.INTCTRL = 0x03; // disable INT1, enable INT0 and place it at high-priority level PORTCFG.MPCMASK = 0x0F; // configure PORTF pins 0~3 at the same time PORTF.PIN0CTRL = 0x01; // configure PORTF pins 3~0 to interrupt on the rising edge PMIC.CTRL = 0x07; // enable high-, medium-, and low-level interrupts sei(); // enable interrupt globally while(1); } // ----------------------------------------------------------------------------------------------------------------// PORTF INT0 interrupt service routine clears INT0IF flag and toggles PORTC pins. // ----------------------------------------------------------------------------------------------------------------ISR (PORTF_INT0_vect) { PORTF.INTFLAGS = 0x01; // clear INT0IF flag PORTC.OUTTGL = 0xAA; // toggle PORTC pins 7, 5, 3, and 1 } ▲ Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 9.6 ■ 283 AVR Mega Reset 9.6 AVR Mega Reset During reset, all I/O registers are set to their default values, and the program starts execution from the reset vector. The ATMega640/1280/2560 has five sources of reset: • Power-on reset. The MCU is reset when the supply voltage is below the power-on reset threshold (VPOT). A power-on reset (POR) circuit ensures that the device is reset when the power is turned on. After VCC reaches VPOT, the POR circuit starts a delay counter which determines the amount of time that the MCU remains in reset state. • External reset. The MCU is reset when a low level is present on the RESET pin for longer than the minimum pulse width (the minimum interval that the voltage on the RESET pin is below VRST). • Brown-out reset. The MCU is reset when the supply voltage VCC is lower than the brown-out reset threshold (VBOT–) and the brown-out detector is enabled. When the power supply drops below the acceptable level, the MCU cannot execute instructions correctly without corrupting the nonvolatile memory. The solution is to reset the MCU. The reset state in this situation is called brown-out reset. The MCU gets out of brown-out reset when VCC rises above a level (VBOT+) slightly higher than VBOT−. • JTAG AVR reset. The MCU is reset as long as there is a logic 1 in the reset register, one of the scan chains of the JTAG system. • Watchdog reset. The MCU is reset when the watchdog timer overflows and the watchdog is enabled. 7 6 5 4 3 2 1 0 — — — JTRF WDRF BORF EXTRF PORF R R R R/W R/W R/W R/W R/W JTRF: JTAG reset flag 0 = Reset is not caused by JTAG reset. 1 = Reset is caused by a logic 1 in the JTAG reset register selected by the JTAG instruction AVR_RESET. This bit is cleared by a power-on reset or writing a 0 to it. WDRF: Watchdog reset flag 0 = Reset is not caused by watchdog time out. 1 = Reset is caused by watchdog time out (timer overflow). This bit is cleared by a power-on reset or writing a 0 to it. BORF: Brown-out reset flag 0 = Reset is not caused by brown out. 1 = Reset is caused by brown-out reset. This bit is cleared by a power-on reset or writing a 0 to it. EXTRF: External reset flag 0 = Reset is not caused by RESET pin. 1 = Reset is caused by RESET pin. This bit is cleared by a power-on reset or writing a 0 to it. PORF: Power-on reset flag 0 = Reset is not caused by power-on reset. 1 = Power-on reset occurred. This bit is cleared by a power-on reset or writing a 0 to it. Figure 9.21 ■ Source: Atmel Corporation, The Atmel AVR Microcontroller The reset service routine finds out the cause of reset by examining the MCU status register (MCUSR). The contents of MCUSR are shown in Figure 9.21. MCU status register (MCUSR) Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 284 Chapter 9 ■ Interrupt Handling, Resets, and Power Management 9.7 AVR Mega Watchdog Timer ATMega640/1280/2560 has a watchdog timer that derives its clock signal from an on-chip 128-kHz oscillator. The WDT triggers an interrupt or reset when the counter overflows. To prevent the WDT from timing out, execute the WDR instruction to restart the WDT. In interrupt mode, the WDT generates an interrupt when the timer overflows. This interrupt is used to wake up the MCU from sleep mode, and also as a general system timer. One example is to limit the maximum time allowed for certain operations, by requesting an interrupt when the operation has run longer than expected. In system reset mode, the WDT resets the MCU when the timer expires. This is often used to prevent a system from hanging-up in case of runaway code. The third mode, interrupt and system reset mode, combines the other two modes by first requesting an interrupt and then switch to system reset mode. This mode allows a safe shutdown by saving critical parameters before a system reset. The WDT can be forced to operate in system reset mode by programming the Watchdog-always-on fuse (WDTON bit cleared to 0). The operation of WDT is controlled by the Watchdog timer control register (WDTCSR). When the Watchdog-always-on fuse is programmed, the system reset mode bit (WDE) and interrupt mode bit (WDIE) is locked to 1 and 0, respectively, which forces the WDT to operate in system reset mode. The contents of the WDTCSR register are shown in Figure 9.22. 6 5 4 3 2 1 0 WDIE WDP3 WDCE WDE WDP2 WDP1 WDP0 R/W R/W R/W R/W R/W R/W R/W R/W Reset value = 0b0000 x 000 WDIF: Watchdog interrupt flag 0 = WDT did not time out since last time it was cleared. 1 = WDT was configured in interrupt mode and a WDT time-out has occurred. This bit is cleared by writing a 1 to it or when its service routine is entered. WDIE: Watchdog interrupt enable See Table 9.6. WDCE: WDT change enable This bit is used in timed sequences for changing WDE and prescaler bits. To clear the WDE bit, and/or change the prescaler bits, WDCE must be set. WDE: Watchdog system reset enable. See Table 9.6. WDE is overridden by WDRF in MCUSR. To clear WDE, WDRF must be cleared first. WDP3~0: Watchdog timer prescaler 3, 2, 1, and 0. This four bits determine the Watchdog timer prescaling when the Watchdog timer is running. The possible prescale factors are listed in Table 9.7. Figure 9.22 ■ Source: Atmel Corporation, The Atmel AVR Microcontroller 7 WDIF Watchdog timer control register (WDTCSR) WDCE WDE WDIE Mode Action on time-out 1 0 0 Stopped None 1 0 1 Interrupt mode Interrupt 1 1 0 System reset mode Reset 1 1 1 Interrupt and system reset mode Interrupt, then go to system reset mode 0 x x System reset mode Reset Source: Atmel Corporation, The Atmel AVR Microcontroller Table 9.6 ■ Watchdog timer configuration Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 9.7 ■ 285 AVR Mega Watchdog Timer WDP3 WDP2 WDP1 WDP0 Number of WDT oscillator cycles Typical time-out at VCC = 5.0 V 0 0 0 0 2 k cycles 16 ms 0 0 0 1 4 k cycles 32 ms 0 0 1 0 8 k cycles 64 ms 0 0 1 1 16 k cycles 0.125 ms 0 1 0 0 32 k cycles 0.25 ms 0 1 0 1 64 k cycles 0.5 s 0 1 1 0 128 k cycles 1.0 s 0 1 1 1 256 k cycles 2.0 s 1 0 0 0 512 k cycles 4.0 s 1 0 0 1 1024 k cycles 8.0 s 1 0 1 0 1 0 1 1 1 1 0 0 1 1 0 1 1 1 1 0 1 1 1 1 Reserved Source: Atmel Corporation, The Atmel AVR Microcontroller Table 9.7 ■ Watchdog timer prescale select To ensure program security, the user is required to follow a timed sequence to change the WDT configuration: 1. In the same operation, write a logic 1 to the Watchdog change enable (WDCE) and WDE. A logic 1 must be written to WDE regardless of the previous value of the WDE bit. 2. Within the next four clock cycles, write the WDE and watchdog prescaler bits (WDP) as desired, but with the WDCE bit cleared. This must be done in one operation. Example 9.7 ▼ Write an assembly subroutine to disable Watchdog timer. Solution: The following subroutine disables the Watchdog timer: disableWDT: cli wdr in ori out lds ori sts ; disable global interrupt ; reset WDT r16, MCUSR r16,(1 << WDRF) MCUSR,r16 r16,WDTCSR r16,(1<<WDCE)|(1<<WDE) WDTCSR,r16 ; clear WDRF bit by writing a 1 to WDRF flag ; " ; get a copy of WDTCSR ; sets WDCE and WDE bits ; enable WDT change Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 286 Chapter 9 ■ ldi sts sei ret Interrupt Handling, Resets, and Power Management r16,0 WDTCSR,r16 ; clear WDE and WDCE bits ; " ; turn on global interrupt ▲ Example 9.8 ▼ Write a C function to disable the Watchdog timer. Solution: The following C function disables the Watchdog timer: #include <avr\wdt.h> // include WDT definition #include <avr\interrupt.h> // include interrupt definitions void disableWDT (void) { cli(); // disable global interrupt wdt_reset(); // execute wdt instruction to reset WDT MCUSR |= (1 << WDRF); // clear the WDRF flag by writing a 1 to it WDTCSR |= (1<<WDCE) | (1 << WDE); // allow WDCE to change WDTCSR = 0x00; // disable WDT timer sei(); // turn on global interrupt } ▲ 9.8 XMega Reset The XMega devices have seven reset sources: • • • • • • • Power-on reset Brown-out reset Spike detection reset (not available in Mega devices) Software reset (not available in Mega devices) External reset pin reset Watchdog reset Program and debug interface (PDI) reset (similar to JTAG reset of Mega device) If more than one reset source is active, the device is kept in reset until all reset sources have released their reset. After reset is released from all reset sources, the default oscillator is started and calibrated before the internal reset is released and the device starts running. The XMega reset system has a status register (shown in Figure 9.23) with individual flags for each reset source. The status register is cleared at power-on reset; hence this register shows which source that has issued a reset since the last power-on. A software reset feature makes it possible to issue a system reset from the user software in case of severe program bugs. The software reset is triggered by writing a 1 to the bit 0 (SWRST) of the reset control register (RST. CTRL). Only the bit 0 of this register is implemented. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. ■ 287 XMega Reset 7 6 5 4 3 2 1 0 — SDRF SRF PDIRF WDRF BORF EXTRF PORF R R/W R/W R/W R/W R/W R/W R/W Initial value = 0x00 SDRF: Spike detection reset flag 0 = No power-spike reset occurred 1 = Power-spike reset has occurred since last power-on reset. SRF: Software reset flag 0 = No software reset occurred 1 = Software reset has occurred since last power-on reset. PDIRF: Program and debug interface reset flag 0 = Program and Debug interface reset didn’t occur. 1 = Program and Debug interface reset has occurred. WDRF: Watchdog reset flag 0 = Watchdog timer didn’t time out since last power-on reset. 1 = Watchdog timer has time out (timer overflow). This bit is cleared by a power-on reset or writing a 0 to it. BORF: Brown-out reset flag 0 = Reset is not caused by brown out. 1 = Reset is caused by brown-out reset. This bit is cleared by a power-on reset or writing a 0 to it. EXTRF: External reset flag 0 = Reset is not caused by RESET pin. 1 = Reset is caused by RESET pin. This bit is cleared by a power-on reset or writing a 0 to it. PORF: Power-on reset flag 0 = Reset is not caused by power-on reset. 1 = Power-on reset occurred. This bit is cleared by a power-on reset or writing a 0 to it. Figure 9.23 ■ XMega reset status register (STATUS) 9.8.1 XMega Brown-Out Reset The operation of the XMega brown-out detection circuit is similar to that of the Mega devices with two exceptions: • XMega devices have a programmable brown-out level. The brown-out reset trigger level can be set to from 1.6 up to 3.2 V by programming the fuse BODLEVEL[2:0] using the AVR Studio IDE. Possible brown-out voltage levels are given in Table 9.8. BOLDLEVEL[2:0] VBOT (V) 111 1.6 110 1.8 101 2.0 100 2.2 011 2.4 010 2.7 001 2.9 000 3.2 Source: Atmel Corporation, The Atmel AVR Microcontroller Table 9.8 ■ Programmable BODLEVEL setting Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. Source: Atmel Corporation, The Atmel AVR Microcontroller 9.8 288 Chapter 9 • ■ Interrupt Handling, Resets, and Power Management The brown-out circuit of the XMega device has three modes of operation: sampled, enabled, and disabled. The mode of operation is selected by programming the BODACT and BODDS fuses. The settings of these two sets of fuses are shown in Table 9.9. BODACT[1:0]/ BODDS[1:0] Mode 00 Reserved 01 Sampled 10 Enabled 11 Disabled Source: Atmel Corporation, The Atmel AVR Microcontroller Table 9.9 ■ BOD setting fuse decoding 9.8.2 Spike Detector Reset tSD VCC VDROP tTOUT Time-out Internal reset Figure 9.24 ■ Source: Atmel Corporation, The Atmel AVR Microcontroller The spike detection (SD) circuit detects negative spikes on VCC. When enabled the spike detection circuit continuously monitors the VCC level and triggers a reset if there is a negative spike on the VCC level. For a spike to be detected, the VCC fall must be significant and last for longer than a minimum time. The voltage drop, VDROP, and the minimum, tSD, is dependent on each other. A large voltage drop requires a shorter minimum time to generate a reset and vice versa. The operation of spike detection is illustrated in Figure 9.24. Spike detection reset 9.8.3 XMega Watchdog Timer Unlike Mega devices, the Watchdog timer of the XMega device can only reset the MCU. The WDT of the XMega device operates in normal mode or window mode. In normal mode, a single time-out period is set for the WDT. If the WDT is not reset from the application code before the time out occurs the WDT triggers a system reset. There are 11 possible WDT time-out periods selectable from 8 ms to 8 s. The normal mode WDT time-out period is defined by bit 5~2 of the Watchdog control register (WDT.CTRL). The contents of WDT.CTRL are shown in Figure 9.25. The default time-out period is controlled by fuses. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. ■ 289 XMega Reset 7 6 — — 5 R R/W 4 3 2 PER[3:0] R/W R/W R/W 1 0 ENABLE CEN R/W R/W R/W Reset value = 0b00xxxxx0 PER[3:0]: Watchdog time-out period These bits determine the Watchdog time-out period as a number of 1-kHz ultra-low-power oscillator cycles. The different typical time-out periods are given in Table 9.10. The initial values of these bits are set by the Watchdog time-out period (WDP) fuses. ENABLE: Watchdog enable 0 = Watchdog timer disabled 1 = Watchdog timer enabled. The CEN bit must be set in order to change this bit. CEN: Watchdog change enable This bit enables the possibility to change the configuration of the CTRL register. When writing a new value to this register, this bit must be written to one at the same time for the changes to take effect. Figure 9.25 ■ XMega Watchdog timer control register (WDT.CTRL) PER[3:0] Group configuration Typical time-out periods 0000 8 CLK 8 ms 0001 16 CLK 16 ms 0010 32 CLK 32 ms 0011 64 CLK 64 ms 0100 125 CLK 0.125 ms 0101 250 CLK 0.25 ms 0110 500 CLK 0.5 s 0111 1 kCLK 1.0 s 1000 2 kCLK 2.0 s 1001 4 kCLK 4.0 s 1010 8 kCLK 8.0 s 1011 1100 1101 Reserved 1110 1111 Source: Atmel Corporation, The Atmel AVR Microcontroller Table 9.10 ■ Watchdog time-out periods In window mode, the WDT uses two different time-out periods, a closed window time-out period (TOWDTW) and the normal time-out period (TOWDT). The closed window time-out period defines a duration from 8 ms to 8 s, during which the WDT cannot be reset: If the WDT is reset in this period the WDT issues a system reset. The normal WDT time-out period, which is also 8 ms to 8 s, defines the duration of the open period, in which the WDT can be reset. The open period follows the closed period, so the total duration of the time-out period is the sum of the closed window and the open window time-out periods. The default closed window time-out period is controlled by fuses. The closed window time-out period is defined by the window mode control register (WDT.WINCTRL). The contents of WDT.WINCTRL are given in Figure 9.26. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. Source: Atmel Corporation, The Atmel AVR Microcontroller 9.8 Chapter 9 ■ Interrupt Handling, Resets, and Power Management 7 6 5 — — R R/W 4 3 2 WPER[3:0] R/W R/W R/W R/W 1 0 WEN WCEN R/W R/W Reset value = 0b00xxxxx0 WPER[3:0]: Watchdog window mode time-out period These bits determine the closed window period as a number of 1-kHz ultra-low-power oscillator cycles in window mode operation. The different typical time-out periods are given in Table 9.11. The initial values of these bits are set by the Watchdog window time-out period (WDWP) fuses. WEN: Watchdog window mode enable 0 = Watchdog window mode disabled 1 = Watchdog window mode enabled. The WCEN bit must be set in order to change this bit. WCEN: Watchdog window mode change enable This bit enables the possibility to change the configuration of the WINCTRL register. When writing a new value to this register, this bit must be written to one at the same time for the changes to take effect. Figure 9.26 ■ Source: Atmel Corporation, The Atmel AVR Microcontroller 290 XMega Window mode control register (WDT.WINCTRL) WPER[3:0] Group configuration Typical closed window periods 0000 8 CLK 8 ms 0001 16 CLK 16 ms 0010 32 CLK 32 ms 0011 64 CLK 64 ms 0100 125 CLK 0.125 ms 0101 250 CLK 0.25 ms 0110 500 CLK 0.5 s 0111 1 kCLK 1.0 s 1000 2 kCLK 2.0 s 1001 4 kCLK 4.0 s 1010 8 kCLK 8.0 s 1011 1100 1101 Reserved 1110 1111 Source: Atmel Corporation, The Atmel AVR Microcontroller Table 9.11 ■ Watchdog closed window periods The WDT is clocked from the 1-kHz output from the internal 32-kHz ultra-low-power oscillator. To avoid unintentional changes of the WDT settings, the WDT is designed with two security mechanisms. The first mechanism is the configuration change protection mechanism, employing a timed write procedure for changing the WDT control registers. In addition, for the new configuration to be written to the control registers, the register’s change enable bit must Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 9.8 ■ 291 XMega Reset be written at the same time. The second mechanism is to lock the configuration by setting the WDT lock fuse. When this fuse is set, the watchdog time control register cannot be changed; hence the WDT cannot be disabled from software. When the WDT lock fuse is programmed the window mode time-out period cannot be changed, but the window mode itself can still be enabled or disabled. When writing to the WDT.CTRL or WDT.WINCTRL registers, the WDT needs to be synchronized to other clock domains. During synchronization the SYNCBUSY bit of the watchdog status register is read as one. This bit is automatically cleared after the synchronization is finished. Synchronization only takes place when the ENABLE bit for the Watchdog Timer is set. The contents of the STATUS register are shown in Figure 9.27. 7 6 5 4 3 2 1 — — — — — — — 0 Reset value SYNCBUSY = 0x00 SYNCBUSY: Watchdog busy synchronization bit 0 = WDT is synchronized to other clock domain already. 1 = WDT is synchronizing to other clock domain. Source: Atmel Corporation, The Atmel AVR Microcontroller Figure 9.27 ■ WDT status register (WDT.STATUS) 9.8.4 XMega WDT Programming When accessing WDT-associated registers, the user needs to refer to the WDT module. For example, the WDT control register can be accessed by referring to the name WDT.CTRL. The available module names for the XMega devices are listed in Appendix D. Example 9.9 ▼ Write a function to enable Watchdog timer to normal mode, a function to enable watchdog timer to normal mode and also set its time-out period, and a function to disable the Watchdog timer. Solution: The C function that enables the Watchdog without changing the time-out period is as follows: #define WDT_IsSyncBusy() (WDT.STATUS & WDT_SYNCBUSY_bm) void WDT_Enable(void) { unsigned char temp = WDT.CTRL | WDT_ENABLE_bm | WDT_CEN_bm; CCP = CCP_IOREG_gc; // signature for accessing protected registers WDT.CTRL = temp; /* Wait for WD to synchronize with new settings. */ while(WDT_IsSyncBusy()); } Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 292 Chapter 9 ■ Interrupt Handling, Resets, and Power Management The C function that enables the Watchdog and also changes its time-out period is as follows: void EnableWDTAndSetTimeout (WDT_PER_t period) { unsigned char temp; temp = WDT_ENABLE_bm | WDT_CEN_bm | period; CCP = CCP_IOREG_gc; // signature for accessing protected registers WDT.CTRL = temp; /* Wait for WD to synchronize with new settings. */ while(WDT_IsSyncBusy()); } The function that disables the Watchdog timer is as follows: void WDT_Disable(void) { unsigned char temp; temp = (WDT.CTRL & ~WDT_ENABLE_bm) | WDT_CEN_bm; CCP = CCP_IOREG_gc; // signature for accessing protected register WDT.CTRL = temp; } ▲ Example 9.10 ▼ Write a function to enable the Watchdog to window mode without changing its time-out period, a function to enable the Watchdog to window mode and also set its time-out period, and also a function to disable window mode. Solution: The C function that enables the Watchdog timer to window mode without changing the time-out period is as follows: // The WDT must be enabled before enabling window mode and a true value is returned if this condition // is met. #define WDT_IsSyncBusy() (WDT.STATUS & WDT_SYNCBUSY_bm) unsigned char WDT_EnableWindowMode(void) { unsigned char wd_enable = WDT.CTRL & WDT_ENABLE_bm; unsigned char temp = WDT.WINCTRL | WDT_WEN_bm | WDT_WCEN_bm; CCP = CCP_IOREG_gc; // signature for accessing protected register WDT.WINCTRL = temp; while (WDT_IsSyncBusy()); // Wait for WDT to synchronize with new settings. return wd_enable; } The C function that enables the Watchdog timer to window mode and also sets the timeout period is as follows: // The WDT must be enabled before enabling window mode and a true value is returned if this condition // is met. WDT_WPER_t is an enumeration type that defines all the possible values for window mode // period. unsigned char EnableWDTWindowModeAndSetTimeout(WDT_WPER_t period) Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 9.9 ■ Power Management and Sleep Modes 293 { unsigned char wd_enable = WDT.CTRL & WDT_ENABLE_bm; unsigned char temp = WDT_WEN_bm | WDT_WCEN_bm | period; CCP = CCP_IOREG_gc; // signature for accessing protected register WDT.WINCTRL = temp; while(WDT_IsSyncBusy()); // Wait for WDT to synchronize with new settings. return wd_enable; } The following function disables the WDT window mode: void DisableWDTWindowMode(void) { unsigned char temp = (WDT.WINCTRL & ~WDT_WEN_bm) | WDT_WCEN_bm; CCP = CCP_IOREG_gc; // signature for accessing protected register WDT.WINCTRL = temp; } ▲ 9.9 Power Management and Sleep Modes Most microcontrollers/microprocessors (including AVR) are fabricated using the CMOS technology. When the CMOS transistors are not switching, they consume no power. This principle is used to reduce the power consumption of microprocessors/microcontrollers. Because embedded systems are often powered by batteries, it is crucial to reduce the power consumption of their controllers—microcontrollers so that the user does not need to change batteries frequently. Both the AVR Mega and XMega devices provide several sleep modes to save power consumption. Since the switching of modules within the MCU is controlled by the clock signal, the sleep mode cuts down power consumption by turning off clock input to the appropriate modules. Sleep mode is entered by setting the SE bit of the SMCR register of the Mega device (or the SEN bit of the SLEEP.CTRL register of the XMega device) and execute the SLEEP instruction. A sleeping MCU is woken up by an enabled interrupt or a reset. The available interrupt wakeup sources are dependent on the selected sleep mode. When an enabled interrupt occurs, the device wakes up and executes the interrupt service routine before continuing normal program execution from the first instruction after the SLEEP instruction. After waking up, the CPU is halted for four clock cycles in addition to the system clock startup time before executing instructions. If a reset occurs during sleep mode, the MCU wakes up and executes from the reset vector. Because the sleep mode of the Mega and XMega are slightly different, they are described in separate sections. 9.9.1 Mega Sleep Modes The Mega device has six sleep modes as summarized in Table 9.12. The sleep mode is selected by the SMCR register. The contents of the SMCR register are shown in Figure 9.28. The SE bit of this register should be written to one just before the execution of the SLEEP instruction and cleared immediately after waking up. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. Interrupt Handling, Resets, and Power Management clkASY Main clock source enabled Timer OSC enabled INT7:0 and pin change TWI address match ADT interrupt Other I/O X X X X X(1) X X X X X X X X X X X(1) X(2) X X(1) X X X X(2) X X(2) X (2) X X X(2) X ADCNRM Power-down Power-save Standby Wakeup sources clkADC Idle Oscillators clkIO clkCPU Sleep mode clkFLASH Active clock domain (1) X (3) X X Extended standby X(1) X(1) X ADC ■ SPM/EEPROM ready Chapter 9 Timer2 294 X X X X X X Notes: 1. If Timer/Counter2 is running in asynchronous mode. 2. For INT7:4, only level interrupt 3. Only recommended with external crystal or resonator selected as clock source Source: Atmel Corporation, The Atmel AVR Microcontroller ■ Summary of Mega device sleep modes 7 6 5 4 3 2 1 0 — — — — SM2 SM1 SM0 SE R R R R R/W R/W R/W R/W Reset value = 0x00 SM2~SM0: Sleep mode select bits 000 = Idle mode 001 = ADC noise reduction 010 = Power-down 011 = Power save 110 = Standby (recommended for external crystals or oscillators) 111 = Extended standby (recommended for external crystals or oscillators) 100~101 = Reserved SE: Sleep enable 0 = Disable sleep mode 1 = Enable sleep mode Figure 9.28 ■ Sleep mode control register (SMCR) IDLE MODE In this mode, the CPU is stopped, and the clock inputs (clkCPU and clkFLASH) to the CPU and flash memory are disabled. Other modules, including the SPI, USART, Analog comparator, ADC, TWI, Timer/Counters, Watchdog, and the interrupt system, continue to operate. In this mode, the CPU is woken up by resets, external triggered interrupts, and internal ones like timer overflow and USART transmit complete interrupts. ADC NOISE REDUCTION MODE This sleep mode halts clkI/O, clkCPU, and clkFLASH while allowing the other clocks to run; hence the associated peripheral modules are allowed to operate. This mode improves the noise Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. Source: Atmel Corporation, The Atmel AVR Microcontroller Table 9.12 9.9 ■ Power Management and Sleep Modes 295 environment for the ADC, enabling higher resolution measurements. If the ADC is enabled, a conversion starts automatically when this mode is entered. Apart from the ADC conversion complete interrupt, an external reset, a TWI interrupt, a Timer/Counter2 interrupt, an SPM/ EEPROM ready interrupt, an external-level interrupt on INT7~4, or a pin change interrupt wakes up the MCU from the ADC noise reduction mode. POWER-DOWN MODE In this mode, the external oscillator is stopped, while the external interrupts, TWI, and the Watchdog continue to operate (if enabled). In this mode, the MCU is awakened by an external reset, a watchdog reset, a brown-out reset, a TWI address match, an external level interrupt on INT7~4, an external interrupt on INT3~0, or a pin change interrupt. This mode halts all generated clocks, allowing operation of asynchronous modules only. When waking up from this mode, a delay from the wake-up condition occurs until the wake-up becomes effective. This allows the clock to restart and become stable after having been stopped. The wake-up period is defined by the same CLSEL fuses that define the reset time-out period explained earlier. POWER-SAVE MODE This mode is identical to power-down mode with one exception: If Timer/Counter2 is enabled, it keeps running during sleep. The device wakes up from either Timer overflow or output compare match from Timer2 if these two interrupts are enabled (global interrupt enable bit must be set too). If Timer/Counter2 is not running, then power-down mode is recommended instead of this mode. The Timer/Counter2 can be clocked both synchronously and asynchronously in powersave mode. If the Timer/Counter2 is not using the asynchronous clock, the Timer/Counter oscillator is stopped during sleep. If the Timer/Counter2 is not using the synchronous clock, then it is stopped during sleep. S TA N D B Y M O D E This mode is identical to the power-down mode with the exception that the oscillator is kept running. From this mode, the MCU wakes up in six clock cycles. E X T E N D E D S TA N D B Y M O D E This mode should only be chosen when an external oscillator/oscillator is selected as the system clock source. This mode is identical to the power-save mode with the exception that the oscillator is kept running. From this mode, the device wakes up in six clock cycles. POWER REDUCTION REGISTER In addition to the appropriate sleep mode, the user can also disable the clock input to modules that are not needed in the application via one of the Power Reduction Registers (PRR0 and PPR1) to reduce power consumption. Disabling clock inputs to an idle module is done in the normal mode. The contents of PRR0 and PRR1 are shown in Figure 9.29 and Figure 9.30, respectively. It is easy to enable the sleep mode. For example, the following instruction sequence enables the Mega MCU to standby mode: ldi sts sleep r16,0x0D SMCR,r16 ; enable standby sleep mode ; " ; put the MCU in standby sleep mode The following C statements achieve the same setting: SMCR = 0x0D; __asm__ __volatile__ ("sleep"); // there are two underscore characters before and after Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. ■ Interrupt Handling, Resets, and Power Management 7 6 5 4 3 2 1 0 PRTWI PRTIM2 PRTIM0 — PRTIM1 PRSPI PRUSART0 PRADC R R R R R/W R/W R/W R/W Reset value = 0x00 PRTWI: Power reduction TWI Writing a logic 1 to this bit shuts down the TWI by stopping the clock to the module. When waking up the TWI again, the TWI should be reinitialized to ensure proper operation. PRTIM2: Power reduction Timer/Counter2 Writing a logic 1 to this bit shuts down the Timer/Counter2 module in synchronous mode (AS2 is 0). When the Timer/Counter2 is re-enabled, operation will continue like before the shutdown. PRTIM0: Power reduction Timer/Counter0 Writing a logic 1 to this bit shuts down the Timer/Counter0 module. When the Timer/Counter0 is re-enabled, operation will continue like before the shutdown. PRTIM1: Power reduction Timer/Counter1 Writing a logic 1 to this bit shuts down the Timer/Counter1 module. When the Timer/Counter1 is re-enabled, operation will continue like before the shutdown. PRSPI: Power reduction SPI Writing a logic 1 to this bit shuts down the SPI module by stopping the clock to the module. When waking up the SPI again, the SPI should be reinitialized to ensure proper operation. PRUSART0: Power reduction USART0 Writing a logic 1 to this bit shuts down the USART0 by stopping the clock to the module. When waking up the USART0 again, the USART0 should be reinitialized to ensure proper operation. PRADC: Power reduction ADC Writing a logic 1 to this bit shuts down the ADC. The ADC must be disabled before shut down. The analog comparator cannot use the ADC input MUX when the ADC is shut down. Figure 9.29 ■ Power reduction register 0 (PRR0) 7 6 5 4 3 — — PRTIM5 PRTIM4 PRTIM3 R R R R R/W 2 1 0 Reset value PRUART3 PRUSART2 PRUSART1 = 0x00 R/W R/W R/W PRTIM5: Power reduction Timer/Counter5 Writing a logic 1 to this bit shuts down the Timer/Counter5 module. When the Timer/Counter5 is re-enabled, operation will continue like before the shutdown. PRTIM4: Power reduction Timer/Counter4 Writing a logic 1 to this bit shuts down the Timer/Counter4 module. When the Timer/Counter4 is re-enabled, operation will continue like before the shutdown. PRTIM3: Power reduction Timer/Counter3 Writing a logic 1 to this bit shuts down the Timer/Counter3 module. When the Timer/Counter3 is re-enabled, operation will continue like before the shutdown. PRUSART3: Power reduction USART3 Writing a logic 1 to this bit shuts down the USART3 module. When the USART3 is re-enabled, the USART3 must be reinitialized to ensure proper operation. PRUSART2: Power reduction USART2 Writing a logic 1 to this bit shuts down the USART2 module by stopping clock input to the module. When waking up the USART2 again, the USART2 should be reinitialized to ensure proper operation. PRUSART1: Power reduction USART0 Writing a logic 1 to this bit shuts down the USART1 by stopping the clock to the module. When waking up the USART1 again, the USART1 should be reinitialized to ensure proper operation. Figure 9.30 ■ Source: Atmel Corporation, The Atmel AVR Microcontroller Chapter 9 Source: Atmel Corporation, The Atmel AVR Microcontroller 296 Power reduction register 1 (PRR1) Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 9.9 ■ 297 Power Management and Sleep Modes 9.9.2 XMega Sleep Modes The XMega MCU has a sleep module to control the sleep mode operation. There are five sleep modes. A summary of these sleep modes is given in Table 9.13. The sleep mode is enabled and selected via the control register (CTRL) in the SLEEP module. The contents of the CTRL register are shown in Figure 9.31. X Power-down Power-save X Standby(1) X X Extended standby X X All interrupts X Real-time clock interrupt X TWI address match interrupt RTC clock source X X X X X X X X X X X X X Asynchronous PORT interrupt System clock source Idle Wake-up sources RTC clock Sleep mode Oscillators Peripheral clock CPU clock Active clock domain X X X Source: Atmel Corporation, The Atmel AVR Microcontroller Table 9.13 ■ Summary of XMega device sleep modes 7 6 5 4 — — — — R R R R 3 2 1 R/W R/W 0 SEN SMODE[2:0] R/W Reset value = 0x00 R/W SMODE[2:0] SEN Group configuration Description xxx 0 OFF No sleep mode enabled 000 1 IDLE Idle mode 010 1 PDOWN Power-down mode 011 1 PSAVE Power-save mode 110 1 STDBY Standby mode 111 1 ESTDBY Extended standby mode Others 1 — Reserved SEN: Sleep enable This bit must be set to make the MCU enter the selected sleep mode when the SLEEP instruction is executed. Figure 9.31 ■ Sleep control register (SLEEP .CTRL) Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. Source: Atmel Corporation, The Atmel AVR Microcontroller SMODE[2:0]: Sleep mode selection 298 Chapter 9 ■ Interrupt Handling, Resets, and Power Management IDLE MODE In this mode, the CPU and flash memory are disabled, but all peripheral modules, including the interrupt controller, event system, and DMA controller, are running. The device is woken up by any interrupt and reset. POWER-DOWN MODE In this mode, all system clock sources, including the real-time counter (RTC) clock source are stopped. This allows operation of asynchronous modules only. The only interrupts that can wake up the MCU are the TWI interface address match interrupts and asynchronous PORT interrupts. POWER-SAVE MODE The power-save mode is identical to the power-down mode with one exception: If the RTC is enabled, it keeps running during sleep, and the device can also wake up from either RTC overflow or compare match interrupt. S TA N D B Y M O D E This mode is identical to the power-down mode, with the exception that the enabled system clock sources are kept running, whereas the CPU, peripheral and RTC clocks are stopped. This reduces the wake-up time. E X T E N D E D S TA N D B Y M O D E This mode is identical to the power-save mode, with the exception that the enabled system clock sources are kept running while the CPU clocks are stopped. This reduces the wake-up time. The user further reduces power consumption by disabling the appropriate peripheral modules by programming the general power reduction register (PRGEN) and the power reduction PORT register (PRPx) associated with PORTs A, B, C, D, E, and F in the power reduction module (PR). The contents of these registers are shown in Figure 9.32, Figure 9.33, and Figure 9.34. 6 5 4 3 2 1 0 — — AES EBI RTC EVSYS DMA R R R R/W R/W R/W R/W R/W Reset value = 0x00 AES: AES module Setting this bit stops the clock to the AES module. When the bit is cleared, the peripheral should be reinitialized to ensure proper operation. EBI: External bus interface Setting this bit stops the clock to the external bus interface. When the bit is cleared, the peripheral should be reinitialized to ensure proper operation. RTC: Real-time counter Setting this bit stops the clock to the real-time counter. When the bit is cleared, the module continues like before the shutdown. EVSYS: Event system Setting this bit stops the clock to the event system. When the bit is cleared, the module continues like before the shutdown. DMA: DMA controller Setting this bit stops the clock to the DMA controller. This bit can only be set if the DMA controller is disabled. Figure 9.32 ■ Source: Atmel Corporation, The Atmel AVR Microcontroller 7 — General power reduction register (PR.PRGEN) Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 299 Power Management and Sleep Modes 7 6 5 4 3 2 1 0 — — — — — DAC ADC AC R R R R R R/W R/W R/W Reset value = 0x00 DAC: Power reduction DAC Setting this bit stops the clock to the DAC. The DAC should be disabled before shutdown. ADC: Power reduction ADC Setting this bit stops the clock to the ADC. The ADC should be disabled before shutdown. AC: Power reduction analog comparator Setting this bit stops the clock to the analog comparator. The AC should be disabled before shutdown. Figure 9.33 ■ Power reduction PORTA/B register (PR.PRPA, PR.PRPB) 7 6 5 4 3 2 1 0 — TWI USART1 USART0 SPI HIRES TC1 TC0 R R R R R R/W R/W R/W Reset value = 0x00 TWI: Two-wire interface Setting this bit stops the clock to the TWI interface. When the bit is cleared, the TWI should be reinitialized to ensure proper operation. USART1: Setting this bit stops the clock to the USART1. When this bit is cleared, the USART1 should be reinitialized to ensure proper operation. USART0: Setting this bit stops the clock to the USART0. When this bit is cleared, the USART0 should be reinitialized to ensure proper operation. SPI: Serial peripheral interface Setting this bit stops the clock to the SPI. When this bit is cleared, the SPI should be reinitialized to ensure proper operation. HIRES: Hi-resolution extension Setting this bit stops the clock to the hi-resolution extension for the Timer/Counters. When the bit is cleared, the HIRES should be reinitialized to ensure proper operation. TC1: Timer/Counter1 Setting this bit stops the clock to the Timer/Counter1. When the bit is cleared, the TC1 will continue like before the shutdown. TC0: Timer/Counter0 Setting this bit stops the clock to the Timer/Counter0. When the bit is cleared, the TC0 will continue like before the shutdown. Figure 9.34 ■ Power reduction PORTC/D/E/F register (PR.PRPC~PR.PRPF) The following instruction sequence enables the XMega MCU to standby mode: ldi sts sleep Source: Atmel Corporation, The Atmel AVR Microcontroller ■ r16,0x0D SLEEP_CTRL,r16 ; enable standby sleep mode ; " ; put the MCU in standby sleep mode The following C statements achieve the same setting: SLEEP_CTRL = 0x0D; __asm__ __volatile__ ("sleep"); // there are two underscore characters before and after Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. Source: Atmel Corporation, The Atmel AVR Microcontroller 9.9 300 Chapter 9 ■ Interrupt Handling, Resets, and Power Management There are many ways to use the sleep mode. One way is to use timer interrupt to trigger the entering of sleep mode and then use interrupt to exit sleep mode. An outline for using the sleep mode to save power is shown in Figure 9.35. Embedded system software is often written as an infinite loop. After power-on reset, the MCU starts to perform system initialization. After system initialization, the embedded system is waiting for the user to request the execution of an application. If the user requests the execution of a certain application, the MCU stops the idle timer and identifies the operation to perform. Whenever the MCU finishes execution of the selected application, it starts the idle timer and waits for new requests. If the idle timer times out due to the lack of user requests, the MCU executes the idle timer interrupt service routine. The idle timer interrupt service routine enables the sleep mode and the MCU enters sleep state. If the user requests the embedded system to perform an operation when the MCU is sleeping, the MCU wakes up and executes the associated interrupt service routine which disables the sleep mode and returns to identify an application to execute. The whole process repeats. Start Idle timer interrupt service routine User request for application? t rrup Inte Start the idle timer No Stop idle timer Identify the application requested by the user Figure 9.35 ■ Perform application 2 Enable sleep mode Sleep mode Yes Perform application 1 Start Interrupt Start Perform application n Disable sleep mode Source: Atmel Corporation, The Atmel AVR Microcontroller System initialization after power on Outline for using sleep mode in embedded system 9.10 Summary In computing, an interrupt is an asynchronous signal indicating the need for attention or a synchronous event in software indicating the need for a change in execution. Interrupts make I/O activity more efficient, because the CPU no longer needs to poll the input device to find out if new data is available nor to poll the output device to find out whether it can accept more data. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 9.10 ■ Summary 301 In addition, interrupts also allow emergency events to be handled in time. The handling of routine works is also facilitated by using the timer interrupt. Most microcontrollers support multiple interrupt sources. The microcontroller prioritizes interrupt sources so that whenever there are two or more interrupts occur at the same time, the pending interrupt at the highest priority receives service first. Interrupts are not always desirable. The CPU should disable certain interrupts when they are not needed. This is implemented by using an enable bit to allow or disallow the interrupt to occur. An interrupt that can be enabled or disabled is called a maskable interrupt. Otherwise, it is referred to as a nonmaskable interrupt. To handle interrupts, the CPU needs to identify the source of interrupt and also to locate the starting address of the service routine that handles the interrupt. The starting address of the interrupt service routine is referred to as an interrupt vector. Interrupt vectors may be predefined or stored in a table. The AVR interrupt vectors are predefined. Different Mega and XMega devices have different number of interrupt sources. Four bytes are allocated to each interrupt source starting from location 0x02 (word address) in flash memory. This table can be relocated to the boot sector. A Mega device may have up to 57 interrupt sources whereas an XMega device may have up to 86 interrupt sources. The Mega device has only maskable interrupts. Each interrupt has a static priority. The interrupt with the smallest interrupt vector has the highest priority whereas the interrupt with the highest interrupt vector has the lowest priority. The XMega device has both nonmaskable (only one) and maskable interrupts. An XMega interrupt may be placed at high, medium, or low priority. The priority of a high- or medium-level interrupt is static. However, the priority of a low-level interrupt may be programmed to be round-robin. There are three steps in the AVR interrupt programming in assembly language: Step 1 Write the interrupt service routine. Step 2 Place a jump instruction in the memory location at the predefined interrupt vector so that it jumps to the actual interrupt service routine. Step 3 Enable interrupt locally and globally. There are two steps in the AVR interrupt programming in C language: Step 1 Write the interrupt service routine with the first line written as ISR (interrupt vector number). The user can use the symbolic name corresponding to the particular interrupt to replace the interrupt vector number so that he or she does not need to memorize the actual vector number. Step 2 Enable interrupt locally and globally. All microprocessors and microcontrollers have the reset mechanism. A reset provides default values to registers and flip-flops and initializes all I/O interface modules so that processors can execute a program correctly. The Mega has five reset sources: • • • • • Power-on Reset pin Brown-out JTAG Debug interface Watchdog timer time-out Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 302 Chapter 9 ■ Interrupt Handling, Resets, and Power Management In addition to all of these reset sources, the XMega devices also have spike and software reset. The Watchdog timer is mainly used to detect software errors. A Watchdog timer needs to be reset before it times out (overflows). Otherwise, it resets the CPU. When using the watchdog timer, the application must be written in a way that it restarts the Watchdog timer before it overflows to prevent the CPU from being reset. A CMOS transistor consumes power when it is switching. The MCU can be designed to use clock signals to control the switching of transistors. AVR MCUs implement several sleep modes which turn off certain modules (by disabling their clock inputs) while at the same time keep other modules working to match the needs of applications. By doing this, power consumption is minimized. 9.11 Exercises E9.1 What is interrupt? E9.2 Write an instruction sequence to configure the ATMega1280 odd interrupt pins to interrupt the CPU on the rising edge and the even interrupt pins to interrupt the CPU on the falling edge. E9.3 Write a sequence of C statements to configure the ATMega1280 interrupt pins 7, 5, 2, and 0 to interrupt on the falling edge and pins 6 and 1 to interrupt on both edges. E9.4 Write a sequence of C statements to configure PCINT0, PCINT1, PCINT4, PCINT8, PCINT9, PCINT14, PCINT18, PCINT20, and PCINT23 to interrupt the Mega CPU. E9.5 Write an instruction sequence to enable INT0 and INT1 interrupt of PORTB and place pins 0, 1, and 2 in INT0 and place pins 3, 6, and 7 in INT1 group for the XMega128A1 device. Pins 0, 1, and 2 interrupt the MCU on the rising edge whereas pins 3, 6, and 7 interrupt the MCU on the falling edge. E9.6 Write a sequence of C statements to enable INT0 and INT1 interrupt of PORTB and place pins 0, 3, and 7 in INT0 and place pins 1, 2, and 5 in INT1 group for the XMega128A1 device. Pins 7, 3, and 0 interrupt on the falling edge whereas pins 5, 2, and 1 interrupt on both edges. Configure INT0 to interrupt at high level whereas INT1 interrupt at medium level. E9.7 Write a sequence of instructions to configure the Watchdog timer of the Mega device so that it resets the CPU if it is not restarted in 2 s. E9.8 Write a sequence of C statements to configure the Watchdog timer of the XMega device so that it resets the CPU if it is not restarted in 1 s. 9.12 Lab Assignments L9.1 INT0 and INT1 Interrupt Experiment. Connect debounced switches (or use those available on the demo board) to INT0 and INT1 pins, respectively. Write a main program that performs the following operations: • • • Enables INT0 and INT1 pin to interrupt on the rising edge. Initializes two variables cnt1 and cnt2 to 0. Configures a PORT (e.g., PORTC) for output and connects it to eight LEDs. Write a service routine for INT0 interrupt that increments cnt0, clears the interrupt flag, and outputs cnt0 to LEDs (driven by PORTC). Write a service routine for INT1 interrupt that increments cnt1, clears the interrupt flag, and output cnt2 to LEDs driven by PORTC. Assemble (or compile) the program and download it onto the demo board for execution. Press INT0 and INT1 randomly and observe the change of LED patterns. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 9.12 ■ 303 Lab Assignments L9.2 Connect a 2-Hz periodical signal (taken from a function generator) to the INT0 pin. The circuit connection is shown in Figure L9.2. Use an I/O PORT of your choice to drive eight LEDs. Write a main program that initializes a variable (unsigned char) cnt to 0 and enables INT0 interrupt to high priority (required for XMega device). Write the interrupt service routine that clears the INT0 flag, increments cnt by 1, and outputs cnt to LEDs. XMega128A1 INT0 Source: Atmel Corporation, The Atmel AVR Microcontroller Figure L9.2 ■ XMega (or Mega) INT0 pin interrupt circuit Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 10 Advanced Parallel I/O 10.1 Objectives After completing this chapter, you will be able to • Perform keypad and keyboard scanning, debouncing, and ASCII code lookup. • Use a hardware debouncing circuit to perform key switch debouncing. • Configure the LCD. • Write programs to display information on the LCD. • Explain the principles of operation of stepper motors. • Write programs to drive stepper motors. • Write programs to generate waveforms using a D/A converter. • Explain the operation of the XMega DMA controller. • Write programs to perform data transfer using direct memory access (DMA). Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 306 Chapter 10 ■ Advanced Parallel I/O 10.2 Interfacing a Parallel PORT to a Keypad A keypad is another commonly used input device. Like a keyboard, a keypad is arranged as an array of switches, which could be mechanical, membrane, capacitive, or Hall effect in construction. In mechanical switches, two metal contacts are brought together to complete an electric circuit. In membrane switches, a plastic or rubber membrane presses one conductor onto another; this type of switch can be made very thin. Capacitive switches comprise two plates of a parallel plate capacitor; pressing the key cap effectively increases the capacitance between two plates. A special circuit is needed to detect this change in capacitance. In the Hall effect key switches, the motion of the magnetic flux lines of a permanent magnet perpendicular to a crystal is detected as voltage appearing between the two faces of the crystal; it is this voltage that registers a switch closure. Mechanical keypads and keyboards are most popular due to their low cost and strength of construction. However, mechanical switches have a common problem called contact bounce. Instead of producing a single, clean pulse output, pressing a mechanical switch generates a series of pulses because the switch contacts do not come to rest immediately. This phenomenon is illustrated in Figure 10.1. VCC 5 to 20 ms To MCU Source: Atmel Corporation, The Atmel AVR Microcontroller Figure 10.1 ■ Key switch contact bounce When the key is not pressed, the voltage output to the computer is at VCC. To detect which key has been pressed, the microcontroller has to scan every key switch of the keypad. A human being cannot press and release a key switch in less than 20 ms. During this interval, the microcontroller can scan the same key switch closure tens or even hundreds of thousand times, interpreting each low signal as a new input when in fact only one input should be sent. Because of the contact bounce and the disparity in speed between the microcontroller and human key pressing, a debouncing process is needed. A keypad input program can be divided into three stages: 1. Keypad scanning. This step is to find out which key was pressed. 2. Key switch debouncing. This step is to make sure a key is indeed pressed. 3. Table lookup. This step is to look up the ASCII code of the pressed key. 10.2.1 Keypad Scanning Keypad scanning is usually performed row by row and column by column. A 16-key keypad can easily be interfaced with any available I/O PORT. Figure 10.2 shows a 16-key keypad organized into four rows with each row consisting of four switches. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 10.2 ■ 307 Interfacing a Parallel PORT to a Keypad PJ7 PJ6 PJ5 PJ4 3 2 1 0 PJ3 PJ2 PJ1 PJ0 10kΩ XMega128A1 VCC Figure 10.2 ■ 7 6 5 4 B A 9 8 0 E D C Source: Atmel Corporation, The Atmel AVR Microcontroller For the keypad input application, the upper four pins (PJ7~PJ4) of PORTJ should be configured for output, whereas the lower four pins (PJ3~PJ0) of PORTJ should be configured for input. Sixteen-key keypad connected to the XMega128A1 The rows and columns of a keypad are simply conductors. In Figure 10.2, PORTJ pins PJ3~PJ0 are pulled up to high by pull-up resistors. Whenever a key switch is pressed, the corresponding row and column are shorted together. To distinguish the row being scanned from those not being scanned, the row being scanned is driven low, whereas the other rows are driven high. The row selection of the 16-key keypad is shown in Table 10.1. PJ7 PJ6 PJ5 PJ4 Selected keys 1 1 1 0 0, 1, 2, and 3 1 1 0 1 4, 5, 6, and 7 1 0 1 1 8, 9, A, and B 0 1 1 1 C, D, E, and F Source: Atmel Corporation, The Atmel AVR Microcontroller Table 10.1 ■ Sixteen-key keypad row selection 10.2.2 Keyboard Debouncing Contact bounce is due to the dynamics of a closing contact. The signal falls and rises a few times within a period of about 5 ms as a contact bounces. Because a human being cannot press and release a switch in less than 20 ms, a debouncer recognizes that the switch is closed after the voltage is low for about 10 ms and recognizes that the switch is open after the voltage is high for about 10 ms. Both hardware and software solutions to the key bounce problem are available. Hardware solutions to contact bounce include an analog circuit that uses a resistor and a capacitor to smooth the voltage, and two digital solutions that use set–reset latches or CMOS buffers and double-throw switches. Dedicated scanner chips that perform keypad scanning and debouncing are also available. National Semiconductor 74C922 and 74C923 are two examples. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 308 Chapter 10 ■ Advanced Parallel I/O HARDWARE DEBOUNCING TECHNIQUES The following are hardware debouncing techniques: • Set–reset latches. A key switch is debounced by using the set–reset latch shown in Figure 10.3a. Before being pressed, the key is touching the set input, and the Q voltage is high. When pressed, the key moves toward the reset position. When the key touches the reset position, the Q voltage goes low. When the key is bouncing and touching neither the set nor the reset input, both set and reset inputs are pulled low by the pull-down resistors. Because both set and reset are low, the Q voltage remains low and the key is recognized as pressed. • Noninverting CMOS buffer with high input impedance. The CMOS buffer output is identical to its input. When the switch is pressed, the input of the buffer chip 4050 is grounded and hence VOUT is forced to low. When the key switch is bouncing (not touching the input), the resistor R keeps the output voltage low. This is due to the high input impedance of 4050, which causes a negligible voltage drop on the feedback resistor. Thus the output is debounced. This solution is shown in Figure 10.3b. • Integrated debouncers. The RC constant of the integrator determines the rate at which the capacitor charges up toward the supply voltage once the ground connection via the switch has been removed. As long as the capacitor voltage does not exceed the logic 0 threshold value, the VOUT signal continues to be recognized as a logic 0. This solution is shown in Figure 10.3c. VDD Set Q R Q Reset Reset R Set (a) Set–reset latch VDD 4050B Vout (b) CMOS buffer gate VDD VOUT R X Vout C Threshold level Time Switch closed (c) Integrating RC circuit Figure 10.3 ■ Source: Atmel Corporation, The Atmel AVR Microcontroller R Hardware debouncing techniques Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 10.2 ■ Interfacing a Parallel PORT to a Keypad 309 SOFTWARE DEBOUNCING TECHNIQUES A simple software debouncing method is wait-and-see; that is, wait for 10 ms and reexamine the same key to see whether it is still pressed. A key is considered pressed if its output voltage is still low 10 ms after it is detected low. If the output voltage is high, the program considers the signal as noise or the key still bouncing. In either case, the program continues to perform keypad scanning. For most applications, this simple wait-and-see method is adequate. 10.2.3 ASCII Code Lookup For an application that needs a keyboard, the easiest way to find out the ASCII code of the pressed key is to perform a table lookup. However, table lookup is not necessary for the keypad because ASCII code lookup can be embedded in the program that performs the scanning and debouncing. Example 10.1 ▼ Write an assembly language subroutine and a C function to perform keypad scanning and debouncing and return the ASCII code of the pressed key in r22 (assembly) to the caller. Solution: ; ----------------------------------------------------------------------------------------------------------------------------------------------; The following subroutine performs keypad scanning, debouncing, and returns ; the ASCII code of the pressed key in r22. ; ----------------------------------------------------------------------------------------------------------------------------------------------.def temp 5 r16 .def maskc 5 r18 ; the mask to scan a column .def maskr 5 r19 ; the mask to scan a row .def column 5 r20 ; the column being scanned .def row 5 r21 ; the row being scanned .def temp1 5 r17 ; total columns and rows getkey: ldi temp1,3 ; set up loop limit comparator ldi temp,0xF0 ; configure PORTJ upper 4 pins for output sts PORTJ_DIR,temp ; lower 4 pins for input gkloope: clr row ; start from row 0 ldi maskr,0xEF ; mask for selecting row 0 nextrow: clr column ; start from column 0 ldi maskc,0x01 ; mask for scanning column 0 sts PORTJ_OUT,maskr ; select a row to scan gkloopi: lds temp,PORTJ_IN ; select a column to check and temp,maskc ; " breq debounce scan_next: cp column,temp1 ; reach the end of a row? brne inc_col ; if not yet, increment the column number cp row,temp1 ; scan all the rows? brne inc_row ; if not yet, scan next row. rjmp gkloope ; start from row 0 again inc_col: inc column ; increment the column number rol maskc ; update column mask rjmp gkloopi Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 310 Chapter 10 ■ inc_row: debounce: getcode: isdeci: Advanced Parallel I/O inc rol rjmp call lds and breq rjmp mov rol rol add ldi cp brlt ldi add ret ldi add ret row maskr nextrow delay10ms temp,PORTJ_IN temp,maskc getcode scan_next temp,row temp temp temp,column temp1,10 temp,temp1 isdeci r22,0x37 r22,temp ; increment the row number ; update the row number r22,0x30 r22,temp ; the pressed key is between 0 and 9 ; wait for 10 ms ; recheck the same key ; " ; if still pressed, get the ASCII code ; go to scan next key ; compute row * 4 1 column ; " ; " ; " ; compare key number with 10 ; " ; the key is between A and F ; ----------------------------------------------------------------------------------------------------------------------------------------------; insert the delay10ms subroutine here. ; ----------------------------------------------------------------------------------------------------------------------------------------------The C function that performs key scanning, debouncing, and ASCII code lookup is as follows: void delay10ms (void); #define keypad_dir PORTJ_DIR #define keyscan PORTJ_OUT #define keycheck PORTJ_IN unsigned char getkey(void) { char rmask, cmask, row, col; unsigned char keycode; keypad_dir 5 0xF0; while(1){ rmask 5 0xEF; for (row 5 0; row , 4; row11) { cmask 5 0x01; keyscan 5 keycheck & rmask; for (col 5 0; col , 4; col11) { if(!(keycheck & cmask)) { // check whether a key is pressed delay10ms(); if(!(keycheck & cmask)) { // recheck the same key keycode 5 row * 4 1 col; // compute the key value if(keycode , 10) return(0x30 1 keycode); else Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 10.3 ■ 311 Driving the Stepper Motor return (0x37 1 keycode); } } cmask 5 cmask ,, 1; } rmask 5 (rmask ,, 1) | 0x0F; } } } ▲ 10.3 Driving the Stepper Motor Stepper motors are digital motors. They are convenient for applications where a high degree of positional control is required. Printers, tape drives, disk drives, and robot joints, for example, are typical applications of stepper motors. 10.3.1 Principles of Rotation In its simplest form, a stepper motor has a permanent magnet rotor and a stator consisting of two coils. The rotor aligns with the stator coil that is energized. By changing the coil being energized, as illustrated in Figure 10.4a~d, the rotor is turned. C L O C K W I S E F U L L - S T E P R O TAT I O N C4 Current flow 1st N S S N C1 C2 C3 2nd Figure 10.4a ■ N S Source: Atmel Corporation, The Atmel AVR Microcontroller In Figure 10.4a~d, the permanent magnet rotor lines up with the coil pair that is energized. The direction of current determines the polarity of the magnetic field and thus the angular position of the rotor. With the energizing current in Figure 10.4a, the rotor aligns with coil pair C1 and C2. Energizing coil pair C3 and C4 and de-energizing C1 and C2 cause the rotor to align with coil pair C3 and C4. In this example, the direction of the current causes the rotor to rotate in a clockwise direction, as shown in Figure 10.4b. Stepper motor full step 1 Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 312 Chapter 10 ■ Advanced Parallel I/O Source: Atmel Corporation, The Atmel AVR Microcontroller S C4 N 1st S N C2 C1 S Current flow C3 2nd N ■ Stepper motor full step 2 C4 Current flow 1st N S N S N S C1 C2 C3 2nd Figure 10.4c ■ Source: Atmel Corporation, The Atmel AVR Microcontroller Figure 10.4b Stepper motor full step 3 C4 S 1st N C2 S Current flow C3 2nd Figure 10.4d C1 N S ■ Source: Atmel Corporation, The Atmel AVR Microcontroller N Stepper motor full step 4 Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 10.3 ■ 313 Driving the Stepper Motor Next, coils C1~C2 are energized again, but with a current opposite to that in step 1. The rotor moves 90 degrees in a clockwise direction, as shown in Figure 10.4c. The last full step moves the rotor another 90 degrees in a clockwise direction. Note that again the coil pair C3~C4 is energized, but with a current opposite to that in step 2. C O U N T E R C L O C K W I S E F U L L - S T E P R O TAT I O N The stepper motor can also be rotated in a counterclockwise manner. This is achieved by reversing the polarities of coils of C3 and C4 in Figure 10.4a~d. Figure 10.5 shows the counterclockwise sequence. N S C4 Rotor C4 Rotor N C1 N Step 1 N N C3 S S N S C2 S N S C1 C3 Step 2 C4 Rotor C4 Rotor S N C2 C1 S N C2 S Step 3 Figure 10.5 N ■ C3 Step 4 S N C3 S N C1 Source: Atmel Corporation, The Atmel AVR Microcontroller S C2 Full-step counter clockwise operation of step motor H A L F - S T E P O P E R AT I O N A half-step occurs when the rotor (in a four-pole step) is moved to eight discrete positions (45 degrees). To operate the stepper motor in half steps, sometimes both coils have to be energized at the same time. When two coils in close proximity are energized, there is a resultant field whose center depends on the relative strengths of the two magnetic fields. Figure 10.6 illustrates the half-stepping sequence. The step sizes of stepper motors vary from approximately 0.72° to 90°. However, the most common step sizes are 1.8°, 7.5°, and 15°. The steps of 90° or 45° are too crude for many applications. The actual stator (the stationary electromagnets) of a real motor has more segments on it than previously indicated. One example is shown in Figure 10.7. The rotor is also a little bit different and is also shown in Figure 10.7. In Figure 10.7, the stator has eight individual sections (coils) on it, and hence the angle between two adjacent sections is 45°. The rotor has six sections on it and hence there are 60° between two adjacent sections. Using the principle of a Vernier mechanism, the actual movement of the rotor for each step would be 60° – 45°, or 15°. Interested reader should try to Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. Chapter 10 ■ Advanced Parallel I/O S N S C4 Rotor S S Step 1 N C1 N N S S N N C2 S S Step 2 C3 N N N S C1 N C3 Step 3 N S S C2 N S C1 C3 S N C4 Rotor Rotor C4 S N C1 N S S C2 N C3 C4 N S S S Step 5 Rotor N Step 4 N C2 C4 S N S Rotor S N S C1 C2 C3 C4 N S C2 Rotor C4 N N Step 6 S Rotor S N N C1 C3 Rotor C4 S N S S N S C1 C2 N N S Step 7 Figure 10.6 ■ Step 8 N C1 S C3 S N C2 N C3 Source: Atmel Corporation, The Atmel AVR Microcontroller 314 Half-step operation of the stepper motor figure out how these sections are energized to rotate the motor in the clockwise and counterclockwise directions. Driving a stepper motor involves applying a series of voltages to the coils of the motor. A subset of coils is energized at the same time to cause the motor to rotate one step. The pattern of coils energized must be followed exactly for the motor to work correctly. The pattern varies depending on the mode used on the motor. A microcontroller can easily time the duration that the coils are energized and hence controls the speed of the stepper motor in a precise manner. The user can use discrete transistors or a dedicated integrated stepper driver chip to drive a stepper motor. These two approaches are described in the following sections. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 10.3 ■ 315 Driving the Stepper Motor C1 S Rotor N C7 S S N N N C3 S S N C4 C6 C5 Figure 10.7 ■ Source: Atmel Corporation, The Atmel AVR Microcontroller C2 C8 Actual internal construction of stepper motor 10.3.2 Discrete Stepper Motor Drivers The circuit in Figure 10.8 shows how the transistors are used to switch the current to each of the four coils of the stepper motor. The diodes in Figure 10.8 are called fly-back diodes and are used to protect the transistors from reverse bias. The transistor loads are the windings in the stepper motor. The windings are inductors, storing energy as a magnetic field. When the current is cut off, the inductor dispenses its energy in the form of an electric current. This current attempts to flow through the transistor, reverse biasing its collector-emitter pair. The diodes are placed to prevent this current from going through the transistors. VCC R R Q4 PA3 R PA2 R Q3 VCC PA1 R PA0 R Step motor VCC Q2 VCC R Figure 10.8 ■ R VCC Q1 Source: Atmel Corporation, The Atmel AVR Microcontroller VCC Driving a stepper motor Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 316 Chapter 10 ■ Advanced Parallel I/O For higher-torque applications, the normal full-step sequence is used, as shown in Table 10.2. For lower-torque applications, the half-step mode is used, and its sequence is shown in Table 10.3. To control the motor, the microcontroller must output the values in the table in the sequence shown. Table 10.2 and Table 10.3 are circular in that after the last step, the next output must be the first step. The values may be output in the order shown to rotate the motor in one direction, or in reverse order to rotate in the reverse direction. It is essential that the order be preserved even if the motor is stopped for a while. The next step to restart the motor must be the next sequential step following the last step used. The mechanical inertia of the motor requires a short delay (usually 5 to 20 ms) between two steps to prevent the motor from missing steps. Step Q4 PA3 Q3 PA2 Q2 PA1 Q1 PA0 1 on on off off 1100 2 off on on off 0110 3 off off on on 0011 4 on off off on 1001 Value Source: Atmel Corporation, The Atmel AVR Microcontroller Table 10.2 ■ Full-step sequence for clockwise rotation Step Q4 PA3 Q3 PA2 Q2 PA1 Q1 PA0 Value 1 on off off off 1000 2 on on off off 1100 3 off on off off 0100 4 off on on off 0110 5 off off on off 0010 6 off off on on 0011 7 off off off on 0001 8 on off off on 1001 Source: Atmel Corporation, The Atmel AVR Microcontroller Table 10.3 ■ Half-step sequence for clockwise rotation Example 10.2 ▼ Suppose that the pins PA3~PA0 are used to drive the four transistors, as shown in Figure 10.8. Write a subroutine (or function) to rotate the stepper motor clockwise one cycle in full step and a subroutine to rotate in half-step, respectively. These two subroutines are to be run by the Mega devices. Solution: The assembly language subroutines are as follows: .equ .equ .equ .equ .equ FSTEP1 5 0x0C FSTEP2 5 0x06 FSTEP3 5 0x03 FSTEP4 5 0x09 HSTEP1 5 0x08 ; values to rotate a full step ; " ; " ; " ; values to rotate a half-step Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 10.3 ■ 317 Driving the Stepper Motor .equ .equ .equ .equ .equ .equ .equ HSTEP2 5 0x0C HSTEP3 5 0x04 HSTEP4 5 0x06 HSTEP5 5 0x02 HSTEP6 5 0x03 HSTEP7 5 0x01 HSTEP8 5 0x09 ; ; ; ; ; ; ; " " " " " " " ; ----------------------------------------------------------------------------------------------------------------------------------------------; This subroutine rotates the stepper motor clockwise in full-step sequence. The lower 4 pins ; of PORTA must be configured for output before calling this subroutine. ; ----------------------------------------------------------------------------------------------------------------------------------------------.def temp 5 r20 FScw: ldi temp,FSTEP1 ; output the first step pattern out PORTA,temp ; " rcall wait10ms ; provide time for motor to react ldi temp,FSTEP2 out PORTA,temp rcall wait10ms ldi temp,FSTEP3 out PORTA,temp rcall wait10ms ldi temp,FSTEP4 out PORTA,temp rcall wait10ms ret ; ----------------------------------------------------------------------------------------------------------------------------------------------; This subroutine rotates the stepper motor clockwise in half-step sequence. The lower 4 pins ; of PORTA must be configured for output before calling this subroutine. ; ----------------------------------------------------------------------------------------------------------------------------------------------.def temp1 5 r21 HScw: ldi temp1,HSTEP1 ; send out the first step pattern out PORTA,temp1 ; " rcall wait10ms ; provide time for motor to react ldi temp1,HSTEP2 out PORTA,temp1 rcall wait10ms ldi temp1,HSTEP3 out PORTA,temp1 rcall wait10ms ldi temp1,HSTEP4 out PORTA,temp1 rcall wait10ms ldi temp1,HSTEP5 out PORTA,temp1 rcall wait10ms ldi temp1,HSTEP6 out PORTA,temp1 rcall wait10ms ldi temp1,HSTEP7 out PORTA,temp1 Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 318 Chapter 10 ■ Advanced Parallel I/O rcall wait10ms ldi temp1,HSTEP8 out PORTA,temp1 rcall wait10ms ret .include “delays_Mega.asm” The C language versions of the functions are straightforward and hence are left as exercise problems. ▲ 10.3.3 Integrated Stepper Motor Driver IN1 1 16 OUT1 IN2 2 15 OUT2 IN3 3 14 OUT3 IN4 4 13 OUT4 IN5 5 12 OUT5 IN6 6 11 OUT6 IN7 7 10 OUT7 9 Common (VCC) GND 8 ■ The ULN2003 Darlington array chip 5V Common Mega2560 PA3 IN1 OUT1 PA2 IN2 OUT2 PA1 IN3 OUT3 PA0 In4 OUT4 8 Figure 10.10 ■ 9 Step motor VCC GND VCC Source: Atmel Corporation, The Atmel AVR Microcontroller Figure 10.9 Source: Atmel Corporation, The Atmel AVR Microcontroller A direct replacement to the discrete transistors described in Figure 10.8 is the Darlington array chip ULN2003. The pin assignment of the ULN2003 is shown in Figure 10.9. The inverters in Figure 10.9 are Darlington pairs, whereas the diodes protect the Darlington pairs from reverse bias. A circuit that uses the ULN2003 to drive the step motor shown in Figure 10.8 is illustrated in 10.10. The program in Example 10.2 can drive the stepper motor in Figure 10.10 without any modification. Driving a stepper motor using the ULN2003 Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 10.4 ■ Direct Memory Access (DMA) Transfer 319 There are other types of stepper driver chips, for example, the EDE1200. Readers are encouraged to explore the use of these chips. 10.4 Direct Memory Access (DMA) Transfer Direct memory access (DMA) transfer is a type of data transfer in which the CPU is responsible for the setup but does not get involved during the data transfer phase. The actual data transfer is carried out by the DMA controller. Data transfer is an indispensable operation performed by any embedded system software. A data transfer operation may involve one byte or multiple bytes. So far we only have learned the CPU-controlled data transfer operation. To transfer a byte during a multiple-byte transfer, the CPU is required to perform the following operations: 1. Read from the source (may update the source address pointer). 2. Write to the destination (may update the destination address pointer). 3. Update the byte count. 4. Decide whether to continue. As a result, a byte transfer may take four to five clock cycles for the AVR MCU. Therefore, the CPU-controlled data transfer is not efficient. In addition, the CPU cannot carry out any other operation when performing a data transfer. The direct memory access (DMA) supported by the XMega is introduced to improve data transfer efficiency. In addition, the CPU may be able to execute instruction in parallel with a DMA transfer if the instruction being executed does not need to use data bus. 10.4.1 Overview of the XMega DMA Controller The XMega DMA controller can transfer data from one memory area to another, from a memory area to a peripheral, from a peripheral to a memory area, and from a peripheral to another peripheral. The DMA controller contains four channels with separate transfer triggers, interrupt vectors, and addressing modes. A complete DMA read and write operation between memories and/or peripherals is called a DMA transaction. A single DMA transaction can transfer from 1 to 16 million bytes of data. A DMA transaction is divided into a number of block transfers. The size of a block transfer can be from 1 to 64 kB. Each block transfer is further divided into smaller burst transfers. A burst transfer can transfer 1, 2, 4, or 8 bytes. Whenever the DMA controller occupies the data bus, it does so until all bytes in the burst are transferred before it yields the data bus if there is a pending bus request with higher priority. The source address and destination address of a DMA transfer must be specified before it starts. During a DMA transaction, the source address and destination address may be static, incrementing, or decrementing. At the end of a burst, block, or transaction, source and destination addresses may be reloaded. An interrupt may be requested at the end of a DMA transaction. 10.4.2 DMA Registers The DMA controller has a control register (CTRL), a status register (STATUS), an interrupt flag register (INTFLAGS), and a 16-bit temporary register (TEMP) to control the overall operation. The contents of the CTRL register are shown in Figure 10.11. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. Chapter 10 ■ Advanced Parallel I/O 7 6 ENABLE RESET R/W 5 4 — — R R R/W 3 2 DBUFMODE[1:0] R/W R/W 1 0 PRIMODE[1:0] R/W Reset value = 0x00 R/W ENABLE: DMA enable 0: DMA controller is disabled. 1: DMA controller is enabled. RESET: DMA software reset Setting this bit enables software reset. This bit is automatically cleared when reset is completed. This bit can only be set when the DMA controller is disabled (ENABLE=0). DBUFMODE[1:0]: DMA double buffer mode 00 = Double buffer disabled 01 = CH01 – double buffer enabled on channel 0/1 10 = CH23 – double buffer enabled on channel 2/3 11 = CH01CH23 – double buffer enabled on channel 0/1 and channel 2/3 PRIMMODE[1:0]: DMA channel priority settings 00 = RR0123: Round robin 01 = CH0RR123: Channel 0 > round robin (channel 1, 2, and 3) 10 = CH01RR23: Channel 0 > Channel 1 > round robin (channel 2 and 3) 11 = CH0123: channel 0 > channel 1 > channel 2 > channel 3 Figure 10.11 ■ Source: Atmel Corporation, The Atmel AVR Microcontroller 320 DMA control register (DMA_CTRL) 7 6 5 4 3 2 1 0 CH3ERRIF CH2ERRIF CH1ERRIF CH0ERRIF CH3TRNFIF CH2TRNFIF CH1TRNFIF CH0TRNFIF R/W R/W R/W R/W R/W R/W R/W R/W CHnERRIF[3:0]: DMA Channel n error interrupt flag (n = 0, 1, 2, or 3) This flag will be set to 1 when an error condition on DMA channel n is detected. Writing a 1 to this bit will clear the flag. CHnTRNFIF[3:0]: DMA channel n transaction complete interrupt flag (n = 0, 1, 2, or 3) This flag will be set to 1 when a transaction on channel n is completed. If unlimited repeat count is enabled, this flag is read as one after each block transfer. Writing a 1 to this bit location will clear the flag. Figure 10.12 ■ Reset value = 0x00 Source: Atmel Corporation, The Atmel AVR Microcontroller Setting the ENABLE bit allows the user to use DMA transfer to send data between memories and peripherals. DMA reset clears all DMA registers and can only be done when the DMA controller is disabled. To allow for continuous transfer, two channels can be interlinked so that the second takes over the transfer when the first is finished and vice versa. This is called double buffering. When the transmission in the first channel is completed, the second channel is enabled. When a request is detected on the second channel, the transfer starts; and when this is completed, the first channel is enabled again. Because the DMA controller has four channels, it is possible that several channels may request data transfer at the same time. However, only one DMA channel is allowed to perform DMA data transfer at a time. The relative priorities of DMA channels determine which channel can control the data bus for data transfer. The DMA controller allows the application software to decide whether one or more channels should have a fixed priority or if a round-robin scheme should be used. A round-robin scheme means that the channel that last transferred data has the lowest priority. The INTFLAGS register contains DMA error flags and the channel transaction complete flags. These flags could interrupt the CPU if they are enabled. The contents of this register are shown in Figure 10.12. DMA interrupt flag register (DMA_INTFLAGS) Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 10.4 ■ 321 Direct Memory Access (DMA) Transfer The STATUS register contains information regarding whether a channel is busy and whether there is a pending request on each DMA channel. The contents of the STATUS register are shown in Figure 10.13. 6 5 4 3 2 1 0 R R R R R R R Reset value = 0x00 R CHnBUSY[3:0]: DMA Channel n busy flag (n = 0, 1, 2, or 3) This flag will be set to 1 when channel n starts a DMA transaction. This flag is automatically cleared when the DMA channel is disabled, when the channel n transaction complete interrupt flag is set, or if the DMA channel n error flag is set. CHnPEND[3:0]: DMA channel n pending (n = 0, 1, 2, or 3) This flag will be set to 1 when a block transfer is pending on channel n. This flag is automatically cleared when the block transfer starts, or if the transfer is aborted. Figure 10.13 ■ Source: Atmel Corporation, The Atmel AVR Microcontroller 7 CH3BUSY CH2BUSY CH1BUSY CH0BUSY CH3PEND CH2PEND CH1PEND CH0PEND DMA status register (DMA_STATUS) The TEMP register is a WORD register (16-bit) to support 24-bit read and write in the DMA controller. The TEMP register consists of two 8-bit registers: TEMPH and TEMPL. 10.4.3 DMA Channel Operation Each DMA channel has a set of registers to support its operation. These registers are listed in Table 10.4. Before a channel can perform DMA data transfer, appropriate registers listed in Table 10.4 must be programmed accordingly. Name Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 CTRLA CHEN CHRST REPEAT TRFREQ -- SINGLE CTRLB CHBUSY CHPEND ERRIF TRNIF ADDCTRL SRCRELOAD[1:0] SRCDIR[1:0] TRIGSRC Bit 1 Bit 0 BURSTLEN[1:0] ERRINTLVL[1:0] TRNINTLVL[1:0] DESTRELOAD[1:0] DESTDIR[1:0] TRIGSRC[7:0] TRFCNTL TRFCNT[7:0] TRFCNTH TRFCNT[15:8] REPCNT REPCNT[7:0] SRCADDR0 SRCADDR[7:0] SRCADDR1 SRCADDR[15:8] SRCADDR2 SRCADDR[23:16] DESTADDR0 DESTADDR[7:0] DESTADDR1 DESTADDR[15:8] DESTADDR2 DESTADDR[23:16] Source: Atmel Corporation, The Atmel AVR Microcontroller Table 10.4 ■ DMA channel register summary The source address of the DMA transfer must be set up in registers SRCADDR0~SRCADDR2, with SRCADDR0 holding the least significant 8 bits of the address. The destination address is set up using the DESTADDR0~DESTADDR2 registers, with DESTADDR0 holding the least Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 322 Chapter 10 ■ Advanced Parallel I/O significant 8 bits of the address. When a DMA transaction transfers no more than 64 kB, it can be carried out in one block transfer. The number of bytes to be transferred in one block transfer is specified using the TRFCNTL~TRFCNTH registers. When there are more than 64 kB of data to be transferred, the DMA transaction is divided into several block transfers. All except the last block transfer will transfer the same number of bytes, whereas the number of block transfers is specified as the repetition count using the REPCNT register. To allow the transfer of more than 64 kB, the REPEAT bit of the channel control register A (CTRLA) must be set to 1. Please note that when 0 is loaded into both the TRFCNTL and TRFCNTH registers, the block transfer count is set to 64 kB. A block transfer is further divided into a sequence of burst transfers. The length of a burst transfer sets the duration of time that the DMA controller holds the data bus. The burst length can be 1, 2, 4, or 8 bytes. The contents of the CTRLA register are shown in Figure 10.14. The operation and error conditions, interrupt flags, and interrupt priority setting are captured in the channel control register B (CTRLB) shown in Figure 10.15. After transferring a byte in a DMA operation, the source and destination addresses are updated. The source and destination address may stay the same, incremented, or decremented. At the end of a DMA transaction, a block transfer, or even a burst transfer, the source and destination addresses may have to be reloaded with their initial values. All of these controls are programmed via the address control register (ADDRCTRL) shown in Figure 10.16. 6 5 4 CHRST REPEAT TRFREQ 3 — SINGLE 2 R/W R/W R/W R/W R/W R/W 1 0 BURSTLEN[1:0] R/W Reset value = 0x00 R/W CHEN: DMA channel enable Setting this bit enables the DMA channel. This bit is automatically cleared when the transaction is completed. If the DMA channel is enabled and this bit is written to 0, the CHEN bit is not cleared before the internal buffer is empty and the DMA transfer is aborted. CHRST: DMA channel software reset Setting this bit enables the channel reset. This bit is automatically cleared when reset is completed. This bit can only be set when DMA channel is disabled (CHEN = 0). REPEAT: DMA channel repeat mode Setting this bit enables repeat mode. In repeat mode, this bit is cleared by hardware at the beginning of the last block transfer. The REPCNT register should be configured before setting this bit. TRFREQ: DMA transfer request Setting this bit requests a data transfer on the DMA channel. This bit is automatically cleared at the beginning of the data transfer. SINGLE: DMA single shot data transfer Setting this bit enables the single shot mode. The channel will then do a burst transfer of BURSTLEN bytes on the transfer trigger. This bit cannot be changed if the channel is busy. BURSTLEN: DMA channel burst mode 00 = 1 byte burst mode (group configuration is 1BYTE) 01 = 2 byte burst mode (group configuration is 2BYTE) 10 = 4 byte burst mode (group configuration is 4BYTE) 11 = 8 byte burst mode (group configuration is 8BYTE) Figure 10.14 ■ Source: Atmel Corporation, The Atmel AVR Microcontroller 7 CHEN DMA channel control register A (CTRLA) DMA transfers can only be started when a DMA transfer request is detected. A transfer request is triggered from software, from an external trigger source (peripheral module), or from an event. Each DMA channel has its own trigger source selections. The available trigger sources vary Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. ■ 323 Direct Memory Access (DMA) Transfer 7 6 5 4 CHBUSY CHPEND ERRIF TRNIF R R R/W R/W 3 2 1 0 ERRINTLVL[1:0] TRNINTLVL[1:0] R/W R/W R/W R/W CHBUSY: DMA channel busy 0 = DMA channel is disabled, channel transaction is completed, or there is an DMA error. 1 = A new DMA transaction is started and not completed. CHPEND: DMA channel pending 0 = There is no pending transfer request on the channel. 1 = A block transfer is pending on the DMA channel. ERRIF: DMA channel error interrupt flag 0 = There is no DMA error. 1 = An DMA error condition has occurred. Writing a one to this flag will clear this flag. TRNIF: DMA channel n transaction complete interrupt flag. 0 = The current DMA transaction is not completed. 1 = A DMA transaction has completed. When unlimited repeat is enabled the TRNIF is set after each block transfer. This flag can be cleared by writing a 1 to it. This interrupt share the same vector with the ERRIF interrupt. ERRINTLVL[1:0]: DMA channel error interrupt level 00 = DMA channel error interrupt disabled 01 = DMA channel error interrupt is enabled at low level. 10 = DMA channel error interrupt is enabled at medium level. 11 = DMA channel error interrupt is enabled at high level. TRNINTLVL[1:0]: DMA transaction complete interrupt level 00 = DMA transaction complete interrupt disabled 01 = DMA transaction complete interrupt is enabled at low level. 10 = DMA transaction complete interrupt is enabled at medium level. 10 = DMA transaction complete interrupt is enabled at high level. Figure 10.15 ■ Reset value = 0x00 Source: Atmel Corporation, The Atmel AVR Microcontroller 10.4 DMA channel control register B (CTRLB) from device to device, depending on the modules or peripherals that exist in the device. Using a transfer trigger for a module or peripherals that do not exist has no effect. The DMA trigger source is selected by programming the TRIGSRC register shown in Figure 10.17. The value to be written into the TRIGSRC register is equal to the sum of the base value of the module to which the source belongs and the offset value of the trigger source. For example, the trigger value for channel 3 of the analog-to-digital converter A (ADCA) is equal to 0x10 (base value of ADCA) 1 0x03 (offset of channel 3) 5 0x13. When channel 3 of the ADCA is selected as the trigger source, the DMA transfer is triggered whenever the A/D conversion on channel 3 of ADCA is completed. Please note that the data transferred by the DMA operation need not be related to the trigger source. By default, a transfer trigger starts a block transfer operation. The transaction continues until the whole block is transferred. When a block is transferred, the channel waits for the next trigger to arrive before it starts transferring the next block. It is possible to select the trigger to start a burst transfer instead of a block transfer. This is called a single shot transfer. A new trigger then starts a new burst transfer. When the repeat mode is enabled, the start of transfer of the next block does not require a transfer trigger. It starts as soon as the previous block is done. The transfer request generated by the trigger source during an ongoing transfer is kept pending, and the transfer starts when the ongoing one is done. Only one pending transfer request can be kept. If the trigger source generates more transfer requests when one is already pending, these additional requests will be lost. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 324 Chapter 10 ■ Advanced Parallel I/O 7 6 5 SRCDIR[1:0] SRCRELOAD[1:0] R/W 4 R/W R/W R/W 3 2 1 DESTRELOAD[1:0] R/W 0 DESTDIR[1:0] R/W R/W Reset value = 0x00 R/W SRCRELOAD[1:0]: DMA channel source address reload SRCRELOAD Group configuration 00 01 10 11 NONE BLOCK BURST TRANSACTION Description No reload performed DMA source address reload with initial value at end of block transfer. DMA source address reload with initial value at end of burst transfer. DMA source address reload with initial value at end of each transaction. SRCDIR[1:0]: DMA channel source address mode SRCDIR Group configuration 00 01 10 11 FIXED INC DEC Description Fixed Increment Decrement Reserved — 00 01 10 11 NONE BLOCK BURST TRANSACTION Source: Atmel Corporation, The Atmel AVR Microcontroller DESTRELOAD[1:0]: DMA channel destination address reload DESTRELOAD Group configuration Description No reload performed DMA desti. address reload with initial value at end of block transfer. DMA desti. address reload with initial value at end of burst transfer. DMA desti. address reload with initial value at end of each transaction. DESTDIR[1:0]: DMA channel destination address mode DESTDIR Group configuration 00 01 10 11 FIXED INC DEC — ■ 7 DMA channel address control register (ADDRCTRL) 6 5 4 3 2 1 0 Reset value = 0x00 TRIGSRC[7:0] R/W R/W R/W R/W R/W R/W R/W R/W TRIGSRC[7:0]: DMA channel trigger source select These bits select which trigger source is used for triggering a transfer on the DMA channel. A zero value means that the trigger source is disabled. For each trigger source the value to put in the TRIGSRC register is the sum of the module or peripheral’s base value, and the offset value for the trigger source in the module or peripherals. For modules or peripheral which does not exist for a device, the transfer trigger does not exist. Table 10.5 shows the base value for all module and peripherals. Table 10.6 through Table 10.9 shows the offset value for the trigger sources in the different modules and peripheral types. Figure 10.17 ■ Source: Atmel Corporation, The Atmel AVR Microcontroller Figure 10.16 Description Fixed Increment Decrement Reserved DMA channel trigger source register (TRIGSRC) Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 10.4 ■ 325 Direct Memory Access (DMA) Transfer TRIGSRC base value Group configuration 0x00 OFF Software triggers only 0x01 SYS System DMA triggers base value 0x10 ADCA ADCA DMA triggers base value 0x15 DACA DACA DMA triggers base value 0x20 ADCB ADCB DMA triggers base value 0x25 DACB DACB DMA triggers base value 0x40 TCC0 Timer/Counter C0 DMA triggers base value 0x46 TCC1 Timer/Counter C1 DMA triggers base value SPIC DMA triggers base value Description 0x4A SPIC 0x4B USARTC0 USART C0 DMA triggers base value 0x4E USARTC1 USART C1 DMA triggers base value 0x60 TCD0 Timer/Counter D0 DMA triggers base value 0x66 TCD1 Timer/Counter D1 DMA triggers base value SPID DMA triggers base value 0x6A SPID 0x6B USARTD0 USART D0 DMA triggers base value 0x6E USARTD1 USART D1 DMA triggers base value 0x80 TCE0 Timer/Counter E0 DMA triggers base value 0x86 TCE1 Timer/Counter E1 DMA triggers base value 0x8A SPIE SPIE DMA triggers base value 0x8B USARTE0 USARTE0 DMA triggers base value 0x8E USARTE1 USARTE1 DMA triggers base value 0xA0 TCF0 Timer/Counter F0 DMA triggers base value 0xA6 TCF1 Timer/Counter F1 DMA triggers base value 0xAA SPIF SPIF DMA triggers base value 0xAB USARTF0 USART F0 DMA triggers base value 0xAE USARTF1 USART F1 DMA triggers base value Source: Atmel Corporation, The Atmel AVR Microcontroller Table 10.5 ■ DMA trigger sources base value for all modules and peripherals TRIGSRC offset value Group configuration 0x00 CH0 Event channel 0 0x01 CH1 Event channel 1 0x02 CH2 Event channel 2 Description Source: Atmel Corporation, The Atmel AVR Microcontroller Table 10.6 ■ DMA trigger sources, offset values for the event system triggers Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 326 Chapter 10 ■ Advanced Parallel I/O TRIGSRC offset value Group configuration Description 0x00 CH0 ADC/DAC channel 0 0x01 CH1 ADC/DAC channel 1 0x02 CH2(1) ADC channel 2 0x03 CH3 ADC channel 3 0x04 CH4(2) ADC channel 0, 1, 2, and 3 Notes: 1. For DAC only, Channel 0 and 1 exists and can be used as triggers. 2. Channel 4 equals ADC 0 to 3 OR’ed together. Source: Atmel Corporation, The Atmel AVR Microcontroller Table 10.7 ■ DMA trigger sources, offset values for DAC and ADC triggers TRIGSRC offset value Group configuration Description 0x00 OVF Overflow/underflow 0x01 ERR Error 0x02 CCA Compare or capture channel A 0x03 CCB Compare or capture channel B 0x04 CCC(1) Compare or capture channel C 0x05 CCD Compare or capture channel D Note: 1. CC channel C and D triggers are only available for Timer/Counter0 Source: Atmel Corporation, The Atmel AVR Microcontroller Table 10.8 ■ DMA trigger sources, offset values for Timer/Counter triggers TRIGSRC offset value Group configuration Description 0x00 RXC Receive complete 0x01 DRE Data register empty Source: Atmel Corporation, The Atmel AVR Microcontroller Table 10.9 ■ DMA trigger sources, offset values for USART triggers The group configuration for a source is written as base_offset. For example, the transfer-trigger value for the Timer/Counter C1 channel A (CCA) is written as TCC1_CCA. The transfer-trigger value for the USARTC0 receive complete is USARTC0_RXC. To access the register within a DMA channel (0~3), precede the register name with the prefix of DMA_CHn_ (n 5 0~3). For example, the CTRLA register of the DMA channel 0 can be accessed by using the name of DMA_CH0_CTRLA in assembly language (or DMA.CH0. CTRLA in C language). Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 10.4 ■ 327 Direct Memory Access (DMA) Transfer Example 10.3 ▼ Write a program to copy a block of 128 bytes of data starting from data memory location at 0x2000 to 0x2800, using DMA transfer. Solution: We set block size to 2 kB, set the burst length to 8 bytes, and start DMA transfer manually. The assembly program that performs the specified DMA transfer is as follows: start: .include <ATXMega128A1def.inc> .def temp 5 r16 .def lpCnt 5 r20 .cseg .org 0x00 rjmp start .org 0xF6 ldi temp,low(RAMEND) out CPU_SPL,temp ldi temp,high(RAMEND) out CPU_SPH,temp call setCPUclkto32Mwith16MCrystal ; initialize the SP ; " ; " ; " ; ----------------------------------------------------------------------------------------------------------------------------------------------; Copy test data from program memory to data memory. ; ----------------------------------------------------------------------------------------------------------------------------------------------ldi lpCnt,128 ldi ZL,low(tstDat,,1) ldi ZH,high(tstDat,,1) ldi XL,low(0x2000) ldi XH,high(0x2000) cpLoop: lpm temp,Z1 st X1,temp dec lpCnt brne cpLoop ; ----------------------------------------------------------------------------------------------------------------------------------------------lds temp,DMA_CTRL ; enable DMA ori temp,DMA_ENABLE_bm ; " sts DMA_CTRL,temp ; " ldi temp,0x83 ; enable DMA channel 0 and set burst length to 8 bytes sts DMA_CH0_CTRLA,temp ; " ldi temp,0x11 ; no reload on source and destination address sts DMA_CH0_ADDRCTRL,temp ; increment source and destination address ldi temp,0 ; select manual trigger source sts DMA_CH0_TRIGSRC,temp ; " ldi temp,128 ; set transfer block size to 128 bytes sts DMA_CH0_TRFCNT,temp ; " ldi temp,0 ; " sts DMA_CH0_TRFCNT11,temp ; " ldi temp,0x00 ; set source address to 0x2000 sts DMA_CH0_SRCADDR0,temp ; " ldi temp,0x20 ; " Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 328 Chapter 10 dmalp: tstDat: ■ Advanced Parallel I/O sts DMA_CH0_SRCADDR1,temp ; " ldi temp,0x00 ; sts DMA_CH0_SRCADDR2,temp ; " ldi temp,0 ; set destination address to 0x2800 sts DMA_CH0_DESTADDR0,temp ; " ldi temp,0x28 ; " sts DMA_CH0_DESTADDR1,temp ; " clr temp ; " sts DMA_CH0_DESTADDR2,temp ; " lds temp,DMA_CH0_CTRLA ; start the DMA transfer manually ori temp,DMA_CH_TRFREQ_bm ; " sts DMA_CH0_CTRLA,temp ; " lds temp,DMA_CH0_CTRLB ; wait until transfer is completed sbrs temp,DMA_CH_TRNIF_bp ; skip if transaction complete rjmp dmalp nop .include “sysClock_XMega.asm” .db 1,2,3,4,5,6,7,8,9,10 .db 11,12,13,14,15,16,17,18,19,20 .db 21,22,23,24,25,26,27,28,29,30 .db 31,32,33,34,35,36,37,38,39,40 .db 41,42,43,44,45,46,47,48,49,50 .db 51,52,53,54,55,56,57,58,59,60 .db 61,62,63,64,65,66,67,68,69,70 .db 71,72,73,74,75,76,77,78,79,80 .db 81,82,83,84,85,86,87,88,89,90 .db 91,92,93,94,95,96,97,98,99,100 .db 101,102,203,104,105,106,107,108,109,110 .db 111,112,113,114,115,116,117,118,119,120 .db 121,122,123,124,125,126,127,128 The C language version of the program is as follows: #include <avr/io.h> #include “sysClock_XMega.h” char tstDat[128] 5 {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20, 21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40, 41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60, 61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80, 81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100, 101,102,103,104,105,106,107,108,109,110,111,112,113,114, 115,116,117,118,119,120,121,122,123,124,125,126,127,128}; void main (void) { setCPUclkto32Mwith16MCrystal(); DMA.CTRL |5 DMA_ENABLE_bm; DMA.CH0.CTRLA |5 DMA_CH_ENABLE_bm; // enable DMA channel 0 DMA.CH0.CTRLA 5 0x83; // set DMA channel 0 burst length to 8 bytes DMA.CH0.ADDRCTRL 5 0x11; // no reload on source and destination DMA.CH0.TRIGSRC 5 0; // manual trigger DMA transfer DMA.CH0.TRFCNT 5 128; // block transfer count set to 128 bytes Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 10.5 ■ 329 Liquid Crystal Displays (LCDs) DMA.CH0.SRCADDR0 5 0; DMA.CH0.SRCADDR1 5 0x20; DMA.CH0.SRCADDR2 5 0; DMA.CH0.DESTADDR0 5 0; DMA.CH0.DESTADDR1 5 0x28; DMA.CH0.DESTADDR2 5 0; DMA.CH0.CTRLA |5 DMA_CH_TRFREQ_bm; while(!(DMA.CH0.CTRLB & DMA_CH_TRNIF_bm)); while(1); // set source address to 0x2000 // set destination address to 0x2800 // start the DMA transfer // wait for DMA transfer to complete } DMA transfers related to peripherals can be performed similarly. ▲ 10.5 Liquid Crystal Displays (LCDs) Although seven-segment displays are easy to use, they are bulky and quite limited in the set of characters that they can display. When more than a few characters are to be displayed, seven-segment displays become inadequate. Liquid crystal displays (LCDs) come in handy when the application requires the display of many characters. A liquid crystal display has the following advantages: • • • • High contrast Low-power consumption Small footprint Ability to display both characters and graphics The basic construction of an LCD is shown in Figure 10.18. The most common type of LCD allows light to pass through when activated. A segment is activated when a low-frequency bipolar signal in the range of 30 to 1000 Hz is applied to it. The polarity of the voltage must alternate, or the LCD cannot change very quickly. When a voltage is applied across the segment, an electrostatic field is set up that aligns the crystals in the liquid. This alignment allows light to pass through the segment. If no voltage is applied across a segment, the crystals appear to be opaque because they are randomly aligned. Random alignment is assured by the AC excitation voltage applied to each segment. In a digital watch, the segments appear darker when they are activated because light passes through the segment to a black cardboard backing that absorbs all light. The area surrounding the activated segment appears to grow brighter in color because the randomly aligned crystals reflect much of the light. In a backlit computer display, the segment appears to grow brighter because of a light placed behind the display; the light is allowed to pass through the segment when it is activated. In recent years, the price of LCD displays has dropped to such an acceptable level that all PC vendors bundle LCD displays instead of CRT displays with their PC systems. Notebook computers used LCD as displays right from the beginning. Because of the price reduction of LCDs, the prices of notebook computers also have dropped sharply, and more and more computer users have switched from desktop to notebook computers. Although LCDs can display graphics and characters, only character-based LCDs are discussed in this text. LCDs are often sold in a module that consists of the LCD and its controller. The Hitachi HD44780 is one of the most popular LCD display controllers in use today. Because of the popularity of this LCD controller, many semiconductor vendors produce HD44780compatible LCD controllers. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. Chapter 10 ■ Advanced Parallel I/O Segment Frontplane Glass Liquid crystal Figure 10.18 ■ Backplane Black cardboard backing Source: Atmel Corporation, The Atmel AVR Microcontroller 330 A liquid crystal display (LCD) 10.6 The HD44780 LCD Controller The LCD is often sold as a kit that incorporates an LCD controller, an LCD panel, and some other supporting chips. The block diagram of an LCD kit that uses the HD44780 as the driver is shown in Figure 10.19. LCDP (FRD7069) DB0 E R/ W RS VEE VCC VSS Figure 10.19 CONTROLLER LSI HD44780U S1~S40 SEG 160 V1~V5 SEGMENT DRIVER × 4 ■ Source: Atmel Corporation, The Atmel AVR Microcontroller C1~16 DB7 Block diagram of a HD44780-based LCD kit The DB7~DB0 pins are used to exchange data with the microcontroller. The E pin is an enable signal to the kit. The R/Wsignal determines the direction of data transfer. The RS signal selects the register to be accessed. When the RS signal is high, the data register is selected. Otherwise, the instruction register is selected. An LCD module can be used as a memory-mapped device and be enabled by an address decoder. The E signal is normally connected to the address decoder output qualified by other control signals to meet the timing requirement. The R/W signal can be connected to the same pin of the microcontroller. This approach is applicable only for those microcontrollers that support external memory. The LCD programming in this approach is generally easier and more straightforward. An LCD module can also be interfaced directly with an I/O PORT. In this configuration, the designer needs to use I/O pins to control the signal E, R/W, and RS. Programming is Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 10.6 ■ 331 The HD44780 LCD Controller slightly more cumbersome than it is with the memory-mapped approach because of the need to manipulate these three signals. The HD44780 provides a set of instructions for the user to set up the LCD parameters. The operations performed by these instructions are summarized in Table 10.10. The meanings of certain programmable bits are explained in Table 10.11. Code Instruction Clear display Cursor home R/W B7 B6 B5 B4 B3 B2 B1 B0 0 0 0 0 0 0 0 0 0 1 Clears display and set DDRAM address to 0×00 from address counter AC 1.64 ms * Returns cursor to home position without changing DDRAM contents Also returns display being shifted to the original position. 1.64 ms 40 µs 0 0 0 0 0 0 0 0 1 Description Execution time RS Entry mode set 0 0 0 0 0 0 0 1 I/D S Sets cursor move direction (I/D); specifies to shift the display (S). These operations are performed during data read write. Display on/off control 0 0 0 0 0 0 1 D C B Turns on/off of display (D), cursor on/off (c), and blink of cursor position character (B). 40 µs Cursor/display shift 0 0 0 0 0 1 S/C R/L * * Sets cursor-move or display-shift (S/C), shift direction (R/L) without changing DDRAM data 40 µs Function set 0 0 0 0 1 DL N F * * Sets interface data length (DL), number of display line (N), and character font (F). 40 µs Set CGRAM address 0 0 0 1 Sets the CGRAM address. CGRAM data are sent and received after this setting. 40 µs Set CGRAM address 0 0 1 Sets the DDRAM address. DDRAM data are sent and received after this setting. 40 µs Reads busy flag (BF) indicating internal operation being performed and reads CGRAM or DDRAM address counter contents (depending on previous operation). 0 µs CGRAM address DDRAM address Read busy flag and address counter 0 1 Write CGRAM or DDRAM 1 0 write data Writes data to CGRAM or DDRAM 40 µs Read from CGRAM or DDRAM 1 1 read data Reads data from OGRAM or DDRAM 40 µs BF CGRAM/DDRAM address Source: Atmel Corporation, The Atmel AVR Microcontroller Table 10.10 ■ HD44780 LCD controller instruction set Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 332 Chapter 10 ■ Advanced Parallel I/O Bit name Settings I/D 0 5 Decrement cursor position 1 5 Increment cursor position S 0 5 No display shift 1 5 Display shift D 0 5 Display off 1 5 Display on C 0 5 Cursor off 1 5 Cursor on B 0 5 Cursor blink off 1 5 Cursor blink on S/C 0 5 Move cursor 1 5 Shift display R/L 0 5 Shift left 1 5 Shift right DL 0 5 4-bit interface 1 5 8-bit interface N 0 5 1/8 or 1/11 duty (1 line) 1 5 1/16 duty (2 lines) F 0 5 538 dots 1 5 5310 dots 0 5 Can accept instruction 1 5 Internal operation in progress BF Source: Atmel Corporation, The Atmel AVR Microcontroller Table 10.11 ■ LCD instruction bit names The HD44780 can be configured to control one-line, two-line, or four-line LCDs. The mappings of the character positions on the LCD screen and the DDRAM addresses are not sequential and are shown in Table 10.12. Because the HD44780 is so popular, there is an industrial standard for its pin assignment. This pin assignment is shown in Table 10.13. Visible Display size Character positions DDRAM addresses 1*8 00..07 0x00..0x07 1*16 00..15 0x00..0x0F 1*20 00..19 0x00..0x13 1*24 00..23 0x00..0x17 1*32 00..31 0x00..0x1F 1*40 00..39 0x00..0x27 Source: Atmel Corporation, The Atmel AVR Microcontroller Table 10.12a ■ DDRAM address usage for a 1-line LCD Visible Display size Character positions DDRAM addresses 2*16 00..15 0x00..0x0F10x40..0x4F 2*20 00..19 0x00..0x1310x40..0x53 2*24 00..23 0x00..0x1710x40..0x57 2*32 00..31 0x00..0x1F10x40..0x5F 2*40 00..39 0x00..0x2710x40..0x67 Source: Atmel Corporation, The Atmel AVR Microcontroller Table 10.12b ■ DDRAM address usage for a 2-line LCD Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 10.6 ■ 333 The HD44780 LCD Controller Visible Display size Character positions DDRAM addresses 4*16 00..15 0x00..0x0F10x40..0x4F10x14..0x2310x54..0x63 4*20 00..19 0x00..0x1310x40..0x5310x14..0x2710x54..0x67 4*40 00..39 on 1st controller and 00..39 on 2nd controller 0x00..0x2710x40..0x67 on 1st controller and 0x00..0x2710x40..0x67 on 2nd controller Source: Atmel Corporation, The Atmel AVR Microcontroller Table 10.12c ■ DDRAM address usage for a 4-line LCD Pin no. Symbol I/O 1 VSS -- Function Power supply (GND) 2 VCC -- Power supply (15V) 3 VEE -- Contrast adjust 4 RS | 0 5 instruction input, 1 5 data input 5 R/W | 0 5 write to LCD, 1 5 read from LCD 6 E | Enable signal 7 DB0 I/O Data busline 0 8 DB1 I/O Data busline 1 9 DB2 I/O Data busline 2 10 DB3 I/O Data busline 3 11 DB4 I/O Data busline 4 12 DB5 I/O Data busline 5 13 DB6 I/O Data busline 6 14 DB7 I/O Data busline 7 Note: Many users extend this connector to 16 pins by adding pin 15 and 16 and connect them to VCC and GND. Source: Atmel Corporation, The Atmel AVR Microcontroller Table 10.13a ■ Pin no. Symbol I/O 1 DB7 I/O Data busline 7 2 DB6 I/O Data busline 6 3 DB5 I/O Data busline 5 4 DB4 I/O Data busline 4 5 DB3 I/O Data busline 3 6 DB2 I/O Data busline 2 7 DB1 I/O Data busline 1 Table 10.13b ■ Pin assignment for displays with less than 80 characters Function (Continued) Pin assignment for displays with more than 80 characters Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 334 Chapter 10 ■ Advanced Parallel I/O Table 10.13b ■ (Continued) Pin no. Symbol I/O 8 DB0 I/O Function 9 E1 | Enable signal for row 0 and 1 10 R/W | 0 5 Write to LCD, 1 5 Read from LCD Data busline 0 11 RS | 0 5 Instruction input, 1 5 Data input 12 VEE -- Contrast adjust 13 VSS -- Power supply (GND) 14 VCC -- Power supply (15V) 15 E2 | Enable signal for row 2 and 3 16 N.C. -- Source: Atmel Corporation, The Atmel AVR Microcontroller 10.6.1 Display Data RAM Display data RAM (DDRAM) stores display data represented in 8-bit character codes. Its extended capacity is 80 3 8 bits, or 80 characters. The area in DDRAM that is not used for display can be used as general data RAM. The relationships between DDRAM addresses and positions on the LCD are shown in Table 10.12a~c. 10.6.2 Character Generator ROM (CGROM) The character generator ROM generates 5 3 8- or 5 3 10-dot character patterns from 8-bit character codes. CGROM can generate 208 five-by-eight characters and 32 five-by-ten characters from 8-bit character codes. 10.6.3 Character Generator RAM (CGRAM) The user can define his or her own character fonts. For 5 3 8 fonts, eight character patterns can be written, and for 5 3 10 fonts, four characters can be defined. By writing font data to CGRAM, user defined characters can be used. 10.6.4 LCD Controller Registers The HD44780 has two 8-bit registers, an instruction register (IR) and a data register (DR). The IR register stores instruction codes, such as display clear and cursor move, and address information for display data RAM (DDRAM) and character generator RAM (CGRAM). The microcontroller writes commands into this register to set up the LCD operation parameters. To write data into the DDRAM and CGRAM, the microcontroller writes data into the DR register. Data written into the DR register are automatically written into the DDRAM or the CGRAM by an internal operation. The DR register is also used for data storage when reading data from the DDRAM or the CGRAM. When address information is written into the IR register, data are read and then stored in the DR register from the DDRAM or the CGRAM by an internal operation. The microcontroller can then read data from the DR register. After a read operation, data in the DDRAM or the CGRAM at the next address are sent to the DR register, and the microcontroller does not need to send another address. The IR and DR registers are distinguished by the RS signal. The IR register is selected when the RS input is low. The DR register is selected when the RS input is high. Register selection is illustrated in Table 10.14. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 10.6 ■ 335 The HD44780 LCD Controller RS R/W Operation 0 0 IR write as an internal operation (display clear, etc.) 0 1 Read busy flag (DB7) and address counter (DB0 to DB6) 1 0 DR write as an internal operation (DR to DDRAM or CGRAM) 1 1 DR read as an internal operation (DDRAM or CGRAM to DR) Source: Atmel Corporation, The Atmel AVR Microcontroller Table 10.14 ■ Register selection BUSY FLAG The HD44780 has a busy flag (BF) to indicate whether the current internal operation is complete. When BF is 1, the HD44780 is still busy with an internal operation. When RS 5 0 and R/W is 1, the busy flag is output to the DB7 pin. The microcontroller can read this pin to find out whether the HD44780 is still busy. ADDRESS COUNTER (AC) The HD44780 uses a 7-bit address counter to keep track of the address of the next DDRAM or CGRAM location to be accessed. When an instruction is written into the IR register, the address information contained in the instruction is transferred to the AC register. The selection of the DDRAM or the CGRAM is determined by the instruction. After writing into (or reading from) the DDRAM or the CGRAM, the contents of the AC register are automatically incremented (decremented) by 1. The contents of the AC register are output to the DB6~DB0 pins when the RS signal is low and the R/W signal is high. 10.6.5 Instruction Description The functions of LCD instructions are discussed in this section. C L E A R D I S P L AY This instruction writes the space code (0x20) into all DDRAM locations. It then sets 0 into the address counter and returns the display to its original status if it was shifted. In other words, the display disappears, and the cursor or blinking goes to the upper left corner of the display. It also sets the I/D bit to 1 (increment mode) in entry mode. RETURN HOME This instruction sets DDRAM address 0 into the address counter and returns the display to its original status if it was shifted. The DDRAM contents are not changed. The cursor or blinking goes to the upper left corner of the display. ENTRY MODE SET The I/D bit of this instruction controls the incrementing (I/D 5 1) or decrementing (I/D 5 0) of the DDRAM address. The cursor or blinking is moved to the right or left, depending on whether this bit is set to 1 or 0. The same applies to writing and reading of the CGRAM. The S bit of this instruction controls the shifting of the LCD display. The display shifts if S 5 1. Otherwise, the display does not shift. If S is 1, it will seem as if the cursor does not move but the display does. The display does not shift when reading from DDRAM. Also, writing into or reading from CGRAM does not shift the display. D I S P L AY O N / O F F C O N T R O L This instruction has three bit parameters: D, C, and B. When the D bit is set to 1, the display is turned on; otherwise it is turned off. The cursor is turned on when the C bit is set to 1. The character indicated by the cursor blinks when the B bit is set to 1. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 336 Chapter 10 CURSOR ■ OR Advanced Parallel I/O D I S P L AY S H I F T This instruction shifts the cursor position to the right or left without writing or reading display data. The shifting is controlled by two bits, as shown in Table 10.15. This function is used to correct or search the display. When the cursor has moved to the end of a line, it is moved to the beginning of the next line. When the displayed data is shifted repeatedly, each line moves only horizontally. The second line of the display does not shift into the first row. The contents of the address counter do not change if the only action performed is a display shift. S/C R/L Operation 0 0 Shifts the cursor position to the left. (AC is decremented by 1) 0 1 Shifts the cursor position to the right. (AC is incremented by 1) 1 0 Shifts the entire display to the left. The cursor follows the display shift. 1 1 Shifts the entire display to the right. The cursor follows the display shift. Source: Atmel Corporation, The Atmel AVR Microcontroller Table 10.15 ■ LCD Shift function FUNCTION SET This instruction allows the user to set the interface data length, select the number of display lines, and select the character fonts. There are three bit variables in this instruction: • DL: Data are sent or received in 8-bit length (DB7 to DB0) when DL is set to 1, and in 4-bit length (DB7 to DB4) when DL is 0. When the pin count is at a premium for the application, the 4-bit data length should be chosen even though it is cumbersome to perform the programming. • N: This bit sets the number of display lines. When set to 0, one-line display is selected. When set to 1, two-line display is selected. • F: When set to 0, the 5 3 8 font is selected. When set to 1, the 5 3 10 font is selected. SET CGRAM ADDRESS This instruction contains the CGRAM address to be set into the address counter. SET DDRAM ADDRESS This instruction allows the user to set the address of the DDRAM in address counter. This instruction is used whenever the user wants to set the cursor to a certain position on the LCD screen. READ BUSY FLAG AND ADDRESS This instruction reads the busy flag (BF) and the address counter. The BF flag indicates whether the LCD controller is still executing the previously received instruction. 10.6.6 Interfacing the HD44780 to the AVR Microcontroller The data transfer between the HD44780 and the Atmel AVR can be done in 4 bits or 8 bits at a time. When in 4-bit mode, data are carried on the upper four data pins (DB7~DB4). The upper four bits are sent over DB7~DB4 first and followed immediately by the lower four bits. We have the choice of using I/O PORTs to interface with the LCD module or treating the LCD as a memory device. Unless our application requires external data memory, there is no reason to interface a LCD kit by treating it as a memory device. This chapter only treats the LCD as an I/O device. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 10.6 ■ 337 The HD44780 LCD Controller An example circuit connection of the LCD kit and the XMega AVR is shown in Figure 10.20 (the Mega device circuit connection is similar). In Figure 10.20, the XMega128A1 and the LCD kit use different power supply. The electrical compatibility is verified by comparing the VIH, VIL of the HD44780 and the VOH and VOL of the XMega128A1, respectively. PK3 PK2 PK1 DB7~DB4 PK7~PK4 GND Figure 10.20 ■ GND 5V Source: Atmel Corporation, The Atmel AVR Microcontroller HD44780 LCD Controller R/ W VCC RS E 3.3 V XMega128A1 LCD interface example (4-bit bus used) Certain timing parameters must be satisfied in order to access the LCD successfully. The read and write timing diagrams for the HD44780 are shown in Figure 10.21 and Figure 10.22, respectively. The values of timing parameters for the HD44780 are shown in Table 10.16. tH tSU R/W tW E tr DB7~DB0 tf tD tDH Valid data tC Figure 10.21 ■ Source: Atmel Corporation, The Atmel AVR Microcontroller RS HD44780 LCD controller read timing diagram tH tSU R/ W tW E tr DB0~DB7 tf tSU1 tH1 Valid data tC Figure 10.22 ■ Source: Atmel Corporation, The Atmel AVR Microcontroller RS HD44780 LCD controller write timing diagram Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 338 Chapter 10 ■ Advanced Parallel I/O Parameter Symbol Min Max Unit tC 500 -- ns Enable high pulse width tW 230 -- ns Enable rise/fall time tr/tf -- 20 ns RS, R/W set up time tSU 40 - ns RS, R/W hold time tH 10 - ns Enable cycle time Read data output delay tD -- 160 ns Read data hold time tDH 5 - ns Write data setup time tSU1 80 - ns Write data hold time tH1 10 - ns Source: Atmel Corporation, The Atmel AVR Microcontroller Table 10.16 ■ HD44780 LCD controller timing parameters 10.6.7 LCD Startup Sequence A startup sequence with specific timings is required to ensure proper LCD operation. The startup sequence for the HD44780 is shown in Figure 10.23. After power-on, at least 30 ms must elapse before the function-set instruction code can be written to set the bus width, number of lines, and character patterns (4-bit interface, 2 lines, and 5 3 8 dots are appropriate). After the function-set Power on Wait 30 ms Execute function set instruction Wait 40 ms Execute display control instruction Execute display clear instruction Wait 1.64 ms Execute entry mode set instruction Wait 40 ms OK Figure 10.23 ■ Source: Atmel Corporation, The Atmel AVR Microcontroller Wait 40 ms LCD controller startup sequence Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 10.6 ■ The HD44780 LCD Controller 339 instruction, at least 40 µs must elapse before the display-control instruction can be written (to turn on the display, turn the cursor on or off, and set the cursor to blink or no blink). After another 40 µs, the display-clear instruction can be issued. After another 1.64 ms, the entry mode set instruction can set address increment (or address decrement) mode, and display shift mode (on or off). After this sequence, data can be written into the DDRAM to cause information to appear on the display. 10.6.8 Writing LCD Programs To implement the startup sequence specified in Figure 10.23, we need to write a subroutine (or function) that can send a command (an LCD instruction) to the LCD controller. The procedure for sending a command to the IR register is as follows: Step 1 Pull the RS and the E signals to low. Step 2 Pull the R/W signal to low. Step 3 Pull the E signal to high. Step 4 Output the given LCD instruction to the I/O PORT attached to the LCD data bus. The I/O PORT connected to the LCD data bus must be configured for output before this can be done. Step 5 Pull the E signal to low, and make sure that the internal operation is completed. This is achieved by calling a delay subroutine. This procedure simulates the timing shown in Figure 10.22. This procedure needs to be repeated if a 4-bit data bus is used. Example 10.4 ▼ Write an assembly subroutine and a C function to send a command to the LCD controller shown in Figure 10.20. Call a delay function to wait for 50 µs to allow all except the first two instructions in Table 10.10 to complete execution. Solution: The assembly subroutine that sends a command to the LCD controller is as follows: .equ lcdPORT 5 PORTK_OUT ; LCD data bus and control signals .equ lcdPORT_DIR 5 PORTK_DIR ; LCD PORT direction control .def tmp 5 r20 .equ lcdE 5 0x02 ; mask for E signal .equ lcdRS 5 0x04 ; mask for RS signal .equ lcdRW 5 0x08 ; mask for R/W signal ; ----------------------------------------------------------------------------------------------------------------------------------------------; This subroutine outputs the command in r16 to the LCD controller and waits for 50 us to ; make sure most of the LCD instructions have finished execution. The “Clear display” and ; “cursor home” instructions will need extra time to complete execution. ; ----------------------------------------------------------------------------------------------------------------------------------------------cmd2LCD: lds tmp,lcdPORT andi tmp,~(lcdRW1lcdRS) ; select IR register and write operation sts lcdPORT,tmp ; " Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 340 Chapter 10 ■ Advanced Parallel I/O ori sts mov andi ori sts nop nop nop nop nop nop lds andi sts nop nop nop nop nop nop nop ori sts swap andi ori sts nop nop nop nop nop nop lds andi sts call ret tmp,lcdE lcdPORT,tmp tmp,r16 tmp,0xF0 tmp,lcdE lcdPORT,tmp tmp,lcdPORT tmp,~(lcdE) lcdPORT,tmp tmp,lcdE lcdPORT,tmp r16 r16,0xF0 r16,lcdE lcdPORT,r16 tmp,lcdPORT tmp,~(lcdE) lcdPORT,tmp delay50us ; pull E high ; " ; place cmd in tmp ; mask out the lower 4 bits ; combine cmd upper 4 bits, R/W, RS, and E ; output to LCD PORT ; extend E pulse to more than 250 us ; " ; " ; " ; " ; " ; pull E low ; to terminate write of upper 4 cmd bits ; extend E low time so that tC is longer than ; 500 us (see Figure 10.22) ; " ; " ; " ; " ; " ; pull E high ; " ; output lower 4 cmd bits, E, RS, and R/W bits ; " ; " ; " ; extend E pulse to more than 250 us ; " ; " ; " ; " ; " ; pull E low to terminate write of lower 4 cmd bits ; " ; " ; wait until command is completed ; ----------------------------------------------------------------------------------------------------------------------------------------------; insert the delay50us subroutine here. ; ----------------------------------------------------------------------------------------------------------------------------------------------The C function that sends a command to the LCD controller is as follows: #include #include #define #define #define #define <avrio.h> “delays_XMega.h” lcdPORT lcdPORT_DIR lcdE lcdRS PORTK.OUT PORTK.DIR 0x02 // bit mask for the LCD E signal 0x04 // bit mask for the LCD RS signal Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 10.6 ■ 341 The HD44780 LCD Controller #define lcdRW 0x08 // bit mask for the RW signal // -------------------------------------------------------------------------------------------------------------------------------------------// This function sends a command to the LCD controller. // -------------------------------------------------------------------------------------------------------------------------------------------void cmd2LCD(unsigned char cmd) { unsigned char temp; temp 5 cmd; cmd &5 0xF0; lcdPORT &5 ~(lcdRS1lcdRW); // select IR register & pull R/W low lcdPORT |5 lcdE; // pull E input high lcdPORT 5 cmd | lcdE; // output upper 4 command bits, E, and RS cmd 5 temp; // lengthen E signal cmd 5 cmd .. 3; // lengthen E signal lcdPORT &5 ~lcdE; // pull E low to terminate write of upper 4 bits cmd ..5 3; cmd 5 temp ,, 4; // extract lower 4 bits lcdPORT |5 lcdE; // pull E high lcdPORT 5 cmd | lcdE; // output lower 4 cmd bits, E, and RS cmd 5 temp; cmd 5 cmd .. 3; // length E signal lcdPORT &5 ~lcdE; // pull E low to terminate write of lower 4 bits delay50us(); } ▲ Example 10.5 ▼ Write a subroutine to configure the LCD in Figure 10.20 to operate with the following characteristics: • • • • • Move the cursor to the right after reading or writing a character to the LCD. Turn on display, cursor, and cursor blinking. Select two-row display, 5 3 8 fonts, and 4-bit interface. Clear display and move cursor to the upper left corner. The delay functions written in Chapter 12 are available for use for this subroutine. Solution: ; ----------------------------------------------------------------------------------------------------------------------------------------------; The following subroutine initializes the LCD controller to operate with 2-row display, 5 x 8 ; font, 4-bit interface, cursor move right, enable display, cursor, and cursor blinking. ; ----------------------------------------------------------------------------------------------------------------------------------------------openLCD: ldi sts ldi call ldi call ldi call tmp,0xFF lcdPORT_DIR,tmp r16,3 delayby100ms r16,0x33 cmd2LCD_XMega r16,5 delayby1ms ; configure PORTK for output ; " ; wait for LCD finish internal initialization ; " Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 342 Chapter 10 ■ Advanced Parallel I/O ldi call ldi call ldi call ldi call ldi call ldi call ldi call ret r16,0x32 cmd2LCD_XMega r16,2 delayby1ms r16,0x28 cmd2LCD_XMega r16,0x0F cmd2LCD_XMega r16,0x01 cmd2LCD_XMega r16,2 delayby1ms r16,0x06 cmd2LCD_XMega ; select 4-bit data, 2-line display, 5 x 8 font ; " ; turn on display, cursor, and cursor blinking ; " ; clear screen, move cursor to home position ; " ; wait for the last command to complete ; " ; move cursor right ; " The C function that performs the specified operation is as follows: // -------------------------------------------------------------------------------------------------------------------------------------------// This function configures LCD to select 4-bit data bus, 2-line display, 5x8 font, // turn on display, cursor, and cursor blinking, move cursor right, clear screen. // move cursor to upper left corner. // -------------------------------------------------------------------------------------------------------------------------------------------void openLCD(void) { lcdPORT_DIR 5 0xFF; // configure PORTK for output delayby100ms(3); // wait for LCD internal initialization to complete cmd2LCD(0x33); delayby1ms(5); cmd2LCD(0x32); delayby1ms(2); cmd2LCD(0x28); // select 4-bit data, 2-line display, 5 x 8 font cmd2LCD(0x0F); // turn on display, cursor, and cursor blinking cmd2LCD(0x06); // move cursor right cmd2LCD(0x01); // clear screen, move cursor to home position delayby1ms(2); // wait until “clear display” command is completed } To display information on the LCD, we need a subroutine (or function) that can output a character on the LCD screen. This subroutine is only a minor modification of the cmd2LCD subroutine. ▲ Example 10.6 ▼ Write a subroutine that can output the character passed in r16 to the LCD. Solution: The subroutine that output the character passed in r16 is as follows: ; ----------------------------------------------------------------------------------------------------------------------------------------------; The following subroutine outputs a character passed in r16 to the LCD screen. ; ----------------------------------------------------------------------------------------------------------------------------------------------- Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 10.6 ■ 343 The HD44780 LCD Controller putc2LCD: lds ori sts andi sts ori sts mov andi ori sts nop nop nop nop nop nop lds andi sts nop nop nop nop nop nop nop ori sts swap andi ori sts nop nop nop nop nop nop lds andi sts call ret tmp,lcdPORT tmp,lcdRS lcdPORT,tmp tmp,~lcdRW lcdPORT,tmp tmp,lcdE lcdPORT,tmp tmp,r16 tmp,0xF0 tmp,lcdRS1lcdE lcdPORT,tmp tmp,lcdPORT tmp,~lcdE lcdPORT,tmp tmp,lcdE lcdPORT,tmp r16 r16,0xF0 r16,lcdRS1lcdE lcdPORT,r16 r16,lcdPORT r16,~lcdE lcdPORT,r16 delay50us ; set RS signal high to select DR register ; " ; " ; pull R/W low to select write operation ; " ; pull E high ; " ; get a copy of data byte ; mask out lower 4 bits ; combine upper 4 data bits, RS, and E ; and output to LCD ; extend E pulse to more than 250 us ; " ; " ; " ; " ; " ; pull E low to terminate write of upper 4 data bits ; " ; " ; extend E low interval so that tC is longer than 500 us ; " ; " ; " ; " ; " ; " ; pull E high ; " ; swap upper and lower nibbles of data byte ; mask out the upper data nibble ; output lower 4 data bits, RS, and E ; " ; extend E pulse so that it is longer than 250 us ; " ; " ; " ; " ; " ; pull E low to terminate write of lower 4 data bits ; " ; " ; wait until data write is completed The C function that outputs a character to the LCD is as follows: // -------------------------------------------------------------------------------------------------------------------------------------------// This function sends a byte of data to the LCD controller to be displayed on the // LCD panel. // -------------------------------------------------------------------------------------------------------------------------------------------- Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 344 Chapter 10 ■ Advanced Parallel I/O void putc2LCD(unsigned char cx) { unsigned char temp; temp 5 cx; lcdPORT |5 lcdRS; lcdPORT &5 ~lcdRW; lcdPORT |5 lcdE; cx &5 0xF0; lcdPORT 5 cx | (lcdRS 1 lcdE); cx 5 temp; cx 5 cx .. 3; lcdPORT &5 ~lcdE; cx ..5 3; cx 5 temp ,, 4; lcdPORT |5 lcdE; lcdPORT 5 cx | (lcdRS 1 lcdE); cx 5 temp; cx 5 cx .. 3; lcdPORT &5 ~lcdE; delay50us(); } // select LCD data register // select write operation // pull E to high // clear lower 4 bits // output upper 4 data bits, RS, and E // lengthen E signal // lengthen E signal // terminate upper 4 bits write // make sure tC is longer than 500 us // extract lower 4 bits // pull E to high // output lower 4 data bits, RS, and E // lengthen E signal // " // pull E low to terminate write of lower 4 bits We also need a subroutine that can output a string. A string may be stored in the program memory or data memory. Here we need to have two versions of the subroutine. One version outputs a string in program memory and the other version outputs a string in data memory. ▲ Example 10.7 ▼ Write a subroutine to output a string stored in program memory and a subroutine to output a string stored in data memory. Solution: These two versions of the subroutine are as follows: ; ----------------------------------------------------------------------------------------------------------; The next subroutine outputs a string in program memory pointed to by Z ; ----------------------------------------------------------------------------------------------------------putSC2LCD: loopSC: lpm r16,z1 cpi r16,0 ; reach the end of the string? breq doneCS ; " call putc2LCD jmp loopSC doneCS: ret ; ---------------------------------------------------------------------------------------------------------; The next subroutine outputs a string in data memory pointed to by Z. ; ---------------------------------------------------------------------------------------------------------putSD2LCD: loopSD: ld r16,z1 cpi r16,0 ; reach the end of the string? Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 10.6 ■ 345 The HD44780 LCD Controller breq call jmp ret doneDS: doneDS putc2LCD loopSD ; " In C, the programmer only needs to write one version of the output string function. The C compiler chooses the appropriate instructions to carry out the output operation. The C language version of the function is as follows: void puts2LCD(unsigned char *ptr) { while(*ptr){ putc2LCD(*ptr); ptr11; } } ▲ Example 10.8 ▼ Write a program to output the following messages on the first and second row of the LCD: XMega is fast! LCD works fine! Solution: The assembly language version of the program is as follows: start: again: msg1: msg2: .include <ATXMega128A1def.inc> .cseg .org 0x00 jmp start .org 0xF6 ldi r16,low(RAMEND) out CPU_SPL,r16 ldi r16,high(RAMEND) out CPU_SPH,r16 call setCPUclkto32Mwith16MCrystal call openLCD ldi r16,0x80 call cmd2LCD_XMega ldi ZL,low(msg1,,1) ldi ZH,high(msg1,,1) call putsc2LCD_XMega ldi r16,0xC0 call cmd2LCD_XMega ldi ZL,low(msg2,,1) ldi ZH,high(msg2,,1) call putsc2LCD_XMega jmp again .db “XMega is fast!”,0,0 .db “LCD works fine!”,0 .include “delays_XMega.asm” ; set SYSCLK to 32 MHz ; initialize LCD parameters ; set LCD cursor position to first row, column 1 ; " ; use Z as a pointer to the string ; " ; output “XMega is fast!” ; set LCD cursor to second row, column 1 ; " ; use Z as a pointer to msg2 ; " ; output “LCD works fine!” Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 346 Chapter 10 ■ Advanced Parallel I/O .include “sysClock_XMega.asm” .include “lcdUtil_XMega.asm” ; this file contains all the previously written LCD subroutines The C language version of the program is as follows: #include <avrio.h> #include “sysClock_XMega.h” // include sysClock_XMega.c to project #include “lcdUtil_XMega.h” // include lcdUtil_XMega.c to project #include “delays_XMega.h” // include delays_XMega.c to project unsigned char *msg1 5 “XMega is fast!”; unsigned char *msg2 5 “LCD works fine!”; void main (void) { setCPUclkto32Mwith16MCrystal(); // select SYSCLK source openLCD(); puts2LCD(msg1); cmd2LCD(0xC0); puts2LCD(msg2); while(1); } The LCD functions for the Mega devices are similar and hence are left for you to do as exercise problems. An example of an LCD circuit and utility functions for the Mega device are given in Appendix G. ▲ 10.7 Summary Keypads and keyboards are among the most important input devices for all the embedded products. However, keypads and keyboards have a problem called key bouncing. In addition, there is a huge gap between the speed of human data input and the MCU instruction execution. A debouncing step is needed to address these two issues. There are three steps in keypad and keyboard input: key scanning, key debouncing, and ASCII code lookup. A stepper motor is a digital motor in the sense that each step of the rotation rotates a fixed number of degrees. It is most suitable for applications that require a high degree of positional control, such as plotters, disk drives, magnetic tape drives, robot joints, and so on. The resolution of one step of a stepper motor can be as small as 0.72oC and as large as 90oC. The simplest motor has two pairs of coils. Driving a stepper motor involves applying a series of voltages to the coils of the motor. A subset of coils is energized at a time to cause the motor to rotate one step. The pattern of coils energized must be followed exactly for the motor to work correctly. The pattern varies depending on the mode used on the motor. A microcontroller can easily time the duration during which the coils are energized and hence control the speed of the stepper motor in a precise manner. So far we have used CPU to control all the data transfer operation: the CPU reads a byte from the source and then writes it to the destination. Each byte transfer takes about five clock cycles, which is not very efficient. Direct memory access (DMA) is introduced to speed up data Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 10.8 ■ Exercises 347 transfer for microprocessors/microcontrollers. Using the DMA transfer, the MCU sets up the source address, destination address, the byte count to be transferred, and other parameters, and lets the DMA controller control the actual transfer of every byte. DMA transfer can improve the efficiency of data transfer when the amount of data to be transferred is very large. XMega devices support DMA transfer, whereas the Mega devices do not. LCD displays are used as the major output device by many embedded products because they can display large amounts of information with very low power consumption. An LCD needs a controller to generate the required control signals during the exchange of data between the MCU and the LCD. The most popular character-based LCD controller is the Hitachi HD44780. LCD is often sold as a kit. The LCD kit consists of a control chip, an LCD panel, and several supporting chips. The Hitachi HD44780 is the most popular LCD controller chip and has become the standard for character-based LCD kits. In this chapter, a set of utility functions has been written to simplify the use of LCD. 10.8 Exercises E10.1 Write a subroutine that rotates the stepper motor shown in Figure 10.8 counterclockwise in full steps and also a subroutine that rotates the motor in half steps, respectively. E10.2 Write an instruction sequence to configure the DMA transfer between the Timer/ Counter0 on PORTC and data memory. The destination address should be set to 0x2000, whereas the source address should be set to Timer/Counter0 capture channel A associated with PORTC. Set the block size to 64 bytes and the burst size to 2 bytes. Use Timer/Counter0 capture A associated with PORTC as the trigger source. E10.3 Write a sequence of C statements to configure the DMA transfer between the Timer/ Counter1 associated with PORTF and data memory. The destination address should be set to 0x2000, whereas the source address should be set to Timer/Counter1 capture channel B. Set the block size to 1 kB and the burst size to 2 bytes. Use Timer/Counter1 capture A as the trigger source. E10.4 Write an assembly program to display the following messages on the LCD from column 3 of both rows: Today is good. Class delayed. E10.5 Write a C program to display the following messages on the LCD from column 2 of both rows: Enter you SS# I forgot my SS# E10.6 Assume that we use eight pins of the PORTJ of the XMega128A1 to drive the LCD data bus and PH2, PH1, and PH0 pins to drive signals E, R/W, and RS, respectively. Write an 8-bit version of the cmd2LCD assembly subroutine and C function assuming that XMega128A1 is running with a 32 MHz system clock. E10.7 Use the same assumption as in problem E10.6, write an 8-bit version of the putc2LCD assembly subroutine and C function assuming that XMega128A1 is running with a 32 MHz system clock. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 348 Chapter 10 ■ Advanced Parallel I/O 10.9 Lab Assignments L10.1 Stepper Motor Experiment. Use the stepper motor miniboard from Futurlec (http:// www.futurlec.com) to perform the stepper motor experiment. The stepper motor miniboard implements the circuit shown in Figure 10.8. The IND, INC, INB, and INA signals must be connected from most significant to least significant pins of Table 10.2 and Table 10.3. Perform the following procedure: Step 1 Configure the selected PORT for output. Step 2 Use the lower four pins of the selected I/O PORT to drive the bases of four transistors. Step 3 Write a sequence of instructions or C statements to rotate the stepper motor clockwise for 5 seconds using the full-step sequence. Insert a 10 ms delay between two steps. Step 4 Repeat Step 3 but use the half-step sequence. Step 5 Write a sequence of instructions or C statements to rotate the stepper motor counterclockwise for 5 seconds using the full-step sequence. Insert a 10 ms delay between two steps. Step 6 Repeat step 5, but use the half-step sequence. Step 7 Repeat step 3 to 6, but use 5 ms as delay. Step 8 Repeat step 3 to 6, but use 15 ms as delay. L10.2 LCD Experiment. Enter the following C program as the main function of the project: #include <avrio.h> #include “lcdUtil_XMega.h” #include “sysClock_XMega.h” #include “delays_XMega.h” char *msg1 5 “Shift cursor”; void main (void) { setCPUclkto32Mwith16MCrystal(); openLCD(); cmd2LCD(0x85); cmd2LCD(0x1C); cmd2LCD(0x1C); cmd2LCD(0x1C); cmd2LCD(0x18); cmd2LCD(0x18); cmd2LCD(0x18); Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 10.9 ■ Lab Assignments 349 puts2LCD(msg1); while(1); } Perform the following procedure: Step 1 Set system clock to 32 MHz and also initialize the LCD. Step 2 Execute the command “cmd2LCD(0x85),” using the debug command “run to cursor”; Step 3 Execute the following C statements one at a time, using the debug command “run to cursor”: cmd2LCD(0x1C); cmd2LCD(0x1C); cmd2LCD(0x1C); Step 4 Execute the following C statements one at a time, using the debug command “run to cursor”: cmd2LCD(0x18); cmd2LCD(0x18); cmd2LCD(0x18); Step 5 Output the message “Cursor shift” on the LCD screen. L10.3 Keypad Input. Use the circuit shown in Figure 10.2 to perform keypad input practice. The procedure is as follows: Step 1 Configure the upper four pins of an I/O PORT that drives the keypad for output and the lower four pins for input. Step 2 Initialize the LCD properly. Step 3 Output the message Enter an integer: on the first row of the LCD. After seeing this message, you enter a number on the keypad. Use the F key to terminate the number. Your program reads the number, converts it into a binary, and saves it in a buffer. Step 4 Output the message Enter another integer: on the second row of the LCD. After seeing this message, you enter a number on the keypad. Use the key F to terminate the number. Your program reads in the number, converts it into a binary, and saves it in a buffer. Step 5 Compute the gcd of these two numbers and display it on the LCD screen as follows: The gcd of xxxx & yyyy is z z z z. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 11 Timer Functions of the Mega AVR 11.1 Objectives After completing this chapter, you will be able to • Explain the overall structure of the Mega device timer system. • Use the timer function to create time delays. • Use the input-capture function to measure signal parameters, including frequency, pulse width, period, and duty cycle. • Use the output-compare function to create time delays. • Use the output-compare function to generate waveforms with a specified duty cycle. • Use the timer force function to force the outputcompare pin to either high or low. • Configure the PWM function to generate periodic waveforms with a specified frequency and duty cycle. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 352 Chapter 11 ■ Timer Functions of the Mega AVR 11.2 Introduction to the Microcontroller Timer System A timer needs a clock input to count (increment or decrement). The clock input is generated from the MCU clock circuit or supplied from an I/O pin. When the clock is supplied from an I/O pin, the timer is also called a counter. When the clock signal is generated from the MCU clock circuit, the timer is said to operate in the timer mode. For this reason, many microcontroller vendors call the timer module a timer/counter module. Most microcontrollers provide timer functions including input capture, output compare, and pulse-width modulation (PWM). These functions are used to create time delays, measure signal parameters such as frequency, period, duty cycle, and pulse width, and generate periodic square waveforms. 11.2.1 Using a Timer to Create Time Delays A timer may have 8 bits, 16 bits, or even 32 bits. For an n-bit timer, the timer counts up from 0 and reaches 2n – 1. After counting up to 2n – 1, the timer overflows and then rolls back to 0 to repeat the same process. Some timers may also count down instead of counting up. In the countdown mode, the timer counts from 2n – 1 down to 0 and then repeats. A timer is often used to create time delays. Let the frequency of the timer clock input be fTC; then the timer count required to create a time delay tD (unit is second) is given by the following expression: TimerCount (tD) = tD × fTC (11.1) n By loading the value 2 – tD × fTC into the timer and letting the timer count up to overflow, the desired time delay tD is created. If the timer has a countdown mode, then the same delay is created by letting the timer count down from tD × fTC to 0. 11.2.2 Input Capture When the timer system is configured to operate in the input-capture mode, an external signal applied to an input-capture pin (ICP) is involved in the operation. The user chooses to trigger the capture operation using the signal rising edge, falling edge, or both edges. The value of the TCNT register is copied into the input-capture register (ICR) during this operation. The input-capture function can be used to measure the period of a periodic signal, the width of a pulse, and the duty cycle of a periodic digital waveform. To measure the period, we need to capture two consecutive rising or falling edges. The signal period is then equal to the difference of these two edges multiplied by the timer clock period. We may need to include the timer overflow count into the calculation if timer overflow occurs, which is detailed later. To measure the pulse width of a signal, we need to capture one rising and then the following falling edge of the signal. To measure the duty cycle of a digital periodic waveform, we need to capture three consecutive edges—a rising, a falling, and a rising edge. The signal parameter measurement is illustrated in Figure 11.1, Figure 11.2, and Figure 11.3. Source: Atmel Corporation, The Atmel AVR Microcontroller Source: Atmel Corporation, The Atmel AVR Microcontroller Figure 11.1a ■ Capture two rising edges to measure signal period Figure 11.1b ■ Capture two falling edges to measure signal period Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 11.2 ■ Introduction to the Microcontroller Timer System 353 Source: Atmel Corporation, The Atmel AVR Microcontroller Figure 11.2 ■ Capture one rising and the following falling edges to measure pulse width tHI Duty cycle = tHI ÷ TC TC Source: Atmel Corporation, The Atmel AVR Microcontroller Figure 11.3 ■ Duty cycle measurement 11.2.3 Output Compare Most microcontrollers have implemented the output-compare module in their timer systems. An output-compare module would have an output-compare register (OCR), one or more control registers, and one or more status registers, in addition to a base timer/counter (TCNT) register. A signal pin (called an output-compare [OC] pin) to be controlled by the outputcompare module is also provided. The output-compare module compares the OCR register with the TCNT register in every timer clock cycle. When the values of these two registers are equal, the output-compare module takes the following actions: • • It sets a flag to 1 (this may caused an interrupt to be requested). • • • Make a copy of the TCNT register. It optionally changes the OC pin signal level (pull to high, pull to low, or toggle). To use the output-compare function, we need to take the following actions: Add an appropriate delay count to this copy. Store the sum in the OCR register. These three steps are often repeated to achieve the desired result. The output-compare function is used to generate periodic interrupts, create time delays, trigger events, and generate waveforms to control other equipment or machinery. 11.2.4 Pulse-Width Modulation (PWM) Waveform generation using the output-compare function requires the CPU to restart the output-compare operation after each compare match. This requires frequent CPU involvement during the waveform generation process. For many applications, the frequency and duty cycles are not changed very often. A special circuitry is added to the timer system so that the CPU only has to set up the duty cycle and period once, and the waveform continues by itself until the duty cycle or period must be changed. This waveform is called pulse-width modulation (PWM). In general, a PWM module consists of an output pin, a timer/counter, a period register, a duty register, and other control circuitry. There are two types of PWM: single-slope and dual-slope PWM. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 354 Chapter 11 ■ Timer Functions of the Mega AVR up nt- u Co up nt- u Co Source: Atmel Corporation, The Atmel AVR Microcontroller Timer value The operation of a single-slope PWM is illustrated in Figure 11.4a. In this mode, a PWM waveform cycle starts with the counter counting up from 0 and the waveform outputting high. When the timer/counter counts up to equal the duty register, the output pin voltage drops to 0. The timer/counter continues to count up until it equals the value in the period register. At that point, the timer/counter resets to 0 and the process repeats. The dual-slope PWM operation is shown in Figure 11.4b. In the dual-slope mode, a PWM waveform cycle starts with the counter counting up from 0 and waveform outputting high. When the counter counts up to equal the duty register, the PWM output drops to low. The counter continues to count up until it matches the period register, and then it starts to count down. When the counter counts down to equal the duty register, the PWM output goes high again. The counter continues to count down until it becomes 0. At this point, the process repeats. The PWM is used to control the motor speed, the fan speed, the lamp brightness, and so on. Timer/Counter = Duty register PWM output Timer/Counter = Period register Single-slope PWM operation up nt- u Co Timer/Counter = Period register Co un t-d ow n Timer/Counter = Duty register PWM output Figure 11.4b ■ Source: Atmel Corporation, The Atmel AVR Microcontroller ■ Timer value Figure 11.4a Dual-slope PWM operation (one cycle) Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 11.3 ■ Overview of the Mega AVR Timer System 355 11.3 Overview of the Mega AVR Timer System The 100-pin ATMega640/1280/2560 devices provide the most timer functions of all Mega devices. The ATMega640/1280/2560 devices have six timers. Timer 0 and 2 are 8-bit timers, whereas Timer 1, 3, 4, and 5 are 16-bit timers. All timers except Timer 2 derive their clock input by dividing the internal clkI/O by a prescaler or receive their clock input from an external pin (Tn, n = 0, 1, 3, 4, or 5). Timer 2 derives its clock input by dividing one of the following three clock sources by a prescaler: • • • clkI/O The external 32.768 kHz crystal oscillator connected to the TOSC1 and TOSC2 pins The external clock signal connected to the TOSC1 pin The 8-bit Timer/Counter0 has two output-compare units (OC0A and OC0B). Each outputcompare unit generates PWM output. The 8-bit Timer/Counter0 (TCNT0) compares with the output-compare registers OCR0A and OCR0B in every timer clock cycle. Two output-compare pins, OC0A and OC0B, are associated with Timer/Counter0. Timer/Counter0 has three interrupt sources: Timer/Counter0 overflow (TOV0), output compare A (OCF0A), and output compare B (OCF0B). The 8-bit Timer/Counter2 is identical to the Timer/Counter0 in every aspect except that it may also select to use a clock source provided by a 32.768 kHz crystal oscillator connected to TOSC1 and TOSC2 pins (a prescaler is also applied to this clock source). The Timer/Counter2 also has two output pins (OC2A and OC2B). Each 16-bit timer has one input-capture unit (ICn, n = 1, 3, 4, or 5), three independent output-compare units (OCnA, OCnB, and OCnC, n = 1, 3, 4, or 5), and five interrupt sources (TOVn, ICFn, OCFnA, OCFnB, and OCFnC, n = 1, 3, 4, or 5). Each output-compare unit has an output-compare pin (OCnA, OCnB, and OCnC) and has the capability to generate PWM output. The input-capture unit has an input-capture pin (ICPn). To unify the description of timers/counters, we do the following: • Use MAX to refer to the maximum value that the timer/counter can count up to. MAX is 0×FF (8-bit) or 0×FFFF (16-bit). • • Use BOTTOM to refer to 0. • • Use letter n to refer to the timer unit which may be 0, …, 5. Use TOP to refer to the highest value of a count sequence. For the 8-bit timer, TOP is either 0×FF or the value stored in the OCRnA register. For the 16-bit timer, TOP is 0×00FF, 0×01FF, 0×03FF, the value stored in the OCRnA register, or the value stored in the ICRn register. Use letter x to refer to the output-compare unit associated with one timer module, which may be A, B, or C. 11.3.1 Timers Pin Assignment Timers share the use of signals with other peripheral signals and general I/O pins. The signal assignment of timer pins is given in Table 11.1. Table 11.1 shows that OC0A and OC1C cannot be used at the same time because they are assigned to the same pin. 11.3.2 8-Bit Timer Building Blocks An 8-bit timer is divided into three major components: count unit, output-compare unit, and compare match output unit. Because most of the descriptions applied to Timer 0 and Timer 2, we use the letter n to refer to either timer. The behaviors of output-compare unit A and B for both Timer 0 and Timer 2 are identical in most cases. We use the letter x to refer to outputcompare unit A or B. For example, the TCCR0A refers to Timer/Counter0 Control Register A. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 356 Chapter 11 ■ Timer Functions of the Mega AVR Module Signal pin assignment Timer/Counter0 T0/PD7, OC0A/OC1C/PCINT7/PB7, OC0B/PG5 Timer/Counter1 T1/PD6, ICP1/PD4, OC1A/PCINT5/PB5, OC1B/PCINT6/PB6, OC0A/OC1C/PCINT7/PB7 Timer/Counter2 OC2A/PCINT4/PB4, OC2B/PH6, TOSC1/PG4, TOSC2/PG3 Timer/Counter3 T3/INT6/PE6, CLKO/ICP3/INT7/PE7, OC3A/AIN1/PE3, OC3B/INT4/PE4, OC3C/INT5/PE5 Timer/Counter4 T4/PH7, ICP4/PL0, OC4A/PH3, OC4B/PH4, OC4C/PH5 Timer/Counter5 T5/PL2, ICP5/PL1, OC5A/PL3, OC5B/PL4, OC5C/PL5 Source: Atmel Corporation, The Atmel AVR Microcontroller Table 11.1 ■ Mega device timer pin assignment The block diagram of an 8-bit timer/counter is shown in Figure 11.5. In Figure 11.5, TOP is the value of the OCRnA register or the fixed value 0xFF. When the value 0×FF is chosen as the TOP value, both the OCnA and OCnB module are used to generate the pulse-width modulation (PWM) waveform. However, when the value of the OCRnA register is used as the TOP value, only Count Clear TOVn(int. req) Control logic Direction Clock select CLKTn Edge detector Tn TOP From prescaler BOTTOM Timer/Counter TCNTn = =0 OCFnA Int. Req Waveform generator Data bus OCRnA Fixed TOP values OCRnB TCCRnA Figure 11.5 ■ OCFnB Int. Req Waveform generator = TCCRnB OCnA OCnB Source: Atmel Corporation, The Atmel AVR Microcontroller = 8-Bit timer/counter block diagram Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 11.4 ■ 357 Timer Clock Source Selection the OCnB module is used to generate the PWM waveform. The clock select block shown in this figure is the clock select circuit of Timer 0. The clock circuit of Timer 2 is shown in Figure 11.9. 11.3.3 16-Bit Timer Building Blocks A 16-bit timer has four building blocks: count unit, input-capture unit, output-compare unit, and compare match output unit. Each 16-bit timer/counter may have two or three output-compare (OCnx, n = 1, 3, 4, or 5; x = A, B, or C) and one input-capture modules (ICPn). The block diagram of a 16-bit timer/counter is shown in Figure 11.6. Count Clear TOVn(int. req) Control logic Direction Clock select TCLK Edge detector TOP Tn From prescaler BOTTOM Timer/Counter TCNTn = =0 OCFnA Waveform generator = OCnA OCRnA Fixed TOP values Waveform generator = OCRnB OCFnC Waveform generator = OCRnC ICRn TCCRnA ■ Edge detector TCCRnB OCnC From analog comparator output ICFn Figure 11.6 OCnB Noise canceler ICPn TCCRnC Source: Atmel Corporation, The Atmel AVR Microcontroller Data bus OCFnB 16-Bit timer/counter block diagram 11.4 Timer Clock Source Selection A timer/counter requires a clock input to count. The clock source is selected by programming the Timer/Counter control register B (TCCRnB, n = 0, …, 5). The contents of Timer/ Counter control register B for Timer/Counter 0, 2, and 16-bit timers are shown in Figure 11.7a, 11.7b, and 11.7c, respectively. The clkT2S signal shown in Figure 11.7b is either clkI/O or TOSC1 Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 358 Chapter 11 ■ Timer Functions of the Mega AVR selected by the AS2 bit in the asynchronous status register (ASSR). The contents of the ASSR register are shown in Figure 11.8. Timer/Counter0 and all 16-bit counters receive their clock input from the clkI/O divided by a prescaler or the Tn pin. The clock source selection for Timer/ Counter2 is illustrated in Figure 11.9. W 4 — 3 WGM02 2 CS02 1 CS01 0 CS00 R R R/W R/W R/W R/W Reset value = 0 x 00 FOC0A: Force output compare A When a 1 is written to this bit in a non-PWM mode, an immediate compare match is forced on the waveform generation mode. The OCnA output is changed according to its COMnA1: 0 bits setting. No interrupt will be generated. This bit is read as 0. FOC0B: Force output compare B (n = 0 or 2) When a 1 is written to this bit in a non-PWM mode, an immediate compare match is forced on the waveform generation mode. The OCnB output is changed according to its COMnB1: 0 bits setting. No interrupt will be generated. This bit is read as 0. WGM02: Waveform generation mode bit 2 See Table 11.5. CS02~CS00: Clock select 000: No clock source (Timer/Counter stops) 001: clkI/O (no prescaling) 010: clkI/O /8 (from prescaler) 011: clkI/O /64 (from prescaler) 100: clkI/O /256 (from prescaler) 101: clkI/O /1024 (from prescaler) 110: External clock source on T0 pin. Clock on falling edge 111: External clock source on T0 pin. Clock on rising edge Figure 11.7a ■ Timer/Counter0 control register B(TCCR0B) 7 6 5 4 3 2 1 0 FOC2A FOC2B — — WGM22 CS22 CS21 CS20 W W R R R/W R/W R/W R/W FOC2A: Force output compare A When a 1 is written to this bit in a non-PWM mode, an immediate compare match is forced on the waveform generation mode. The OCnA output is changed according to its COMnA1:0 bits setting. No interrupt will be generated. This bit is read as 0. FOC2B: Force output compare B (n = 0 or 2) When a 1 is written to this bit in a non-PWM mode, an immediate compare match is forced on the waveform generation mode. The OCnB output is changed according to its COMnB1:0 bits setting. No interrupt will be generated. This bit is read as 0. WGM22: Waveform generation mode bit 2 See Table 11.5. CS22~CS20: Clock select 000: No clock source (Timer/Counter stops) 001: clkT2S (no prescaling) 010: clkT2S/8 (from prescaler) 011: clkT2S/32 (from prescaler) 100: clkT2S/64 (from prescaler) 101: clkT2S/128 (from prescaler) 110: clkT2S/256 (from prescaler) 111: clkT2S/1024 (from prescaler) Figure 11.7b ■ Reset value = 0 x 00 Source: Atmel Corporation, The Atmel AVR Microcontroller W 5 — Source: Atmel Corporation, The Atmel AVR Microcontroller 7 6 FOC0A FOC0B Timer/Counter2 control register B(TCCR2B) Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 359 Timer Clock Source Selection 7 ICNCn 6 ICESn 5 — R/W R/W R 4 3 WGMn3 WGMn2 R/W R/W 2 CSn2 1 CSn1 0 CSn0 R/W R/W R/W Reset value = 0 x 00 ICNCn: Input-capture noise canceler 0 = Disable input-capture noise canceler. 1 = Enable input-capture noise canceler. ICESn: Input-capture edge select 0 = Falling edge triggers input capture. 1 = Rising edge triggers input capture. (If ICRn is used as TOP value, then the ICPn is disconnected and input capture is disabled). WGMn3:2: Waveform generation mode bits 3 and 2 See Table 11.6 CSn2~CSn0: Clock select 000 = No clock source (Timer/Counter stopped) 001 = clkI/O (no prescaling) 010 = clkI/O /8 (from prescaler) 011 = clkI/O /64 (from prescaler) 100 = clkI/O /256 (from prescaler) 101 = clkI/O /1024 (from prescaler) 110 = External clock source on Tn pin. Clock on falling edge 111 = External clock source on Tn pin. Clock on rising edge Figure 11.7c ■ Timer/Counter n control register B(TCCR1B, TCCR3B, TCCR4B, TCCR5B) 7 6 5 4 — EXCLK AS2 TCN2UB 3 2 1 OCR2AUB OCR2BUB TCR2AUB 0 Reset value TCR2BUB = 0 x 00 R R R/W R/W R R R R EXCLK: Enable external clock input 0: Crystal oscillator (32,768 Hz) is selected. 1: Asynchronous clock (from TOSC1 pin) instead of the crystal oscillator is selected. AS2: Asynchronous Timer/Counter2 0: Timer/Counter2 is clocked from the I/O clock, clkI/O. 1: Timer/Counter2 is clocked from the TOSC1 pin (can be a crystal oscillator or an external clock). TCN2UB: Timer/Counter2 update busy 0: TCNT2 is ready to be updated with a new value. 1: Timer/Counter2 operates asynchronously and TCNT2 is written. OCR2xUB: Output-compare register 2 update busy (x = A or B) 0: OCR2x is ready to be updated with a new value. (x = A or B) 1: Timer/Counter2 operates asynchronously and OCR2A is written but hasn’t received the new value from the temporary storage register. TCR2xUB: Timer/Counter control register 2 update busy (x = A or B) 0: TCCR2x is ready to be updated with a new value. 1: When Timer/Counter2 operates asynchronously and TCCR2A is written, this bit becomes set. ■ Timer/Counter2 asynchronous status register (ASSR) TOSC1 T/C oscillator TOSC2 Prescaler clkI/O Figure 11.9 ■ clkT2 Source: Atmel Corporation, The Atmel AVR Microcontroller Figure 11.8 Timer/Counter2 clock source selection Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. Source: Atmel Corporation, The Atmel AVR Microcontroller ■ Source: Atmel Corporation, The Atmel AVR Microcontroller 11.4 360 Chapter 11 ■ Timer Functions of the Mega AVR 11.5 Timer/Counter Operation Modes A timer/counter (8-bit or 16-bit) has five operation modes (normal, CTC, fast PWM, phasecorrect PWM, and phase-and-frequency-correct PWM). Some operation modes may have several possible TOP values. 11.5.1 8-Bit Timer/Counter Operation Modes 7 6 5 4 3 2 1 0 COMnA1 COMnA0 COMnB1 COMnB0 — — WGMn1 WGMn0 R/W R/W R/W R/W R R R/W R/W Reset value = 0 x 00 COMnx1:COMnx0: Compare match output mode (n = 0 or 2; x = A or B) The behavior of the output-compare pin (OCnx) is controlled by these two bits together with the waveform generation mode bits (WGMn2:0). The compare match output pin behavior in non-PWM, fast-PWM, and phase-correct-PWM modes are given in Tables 11.2, 11.3, and 11.4, respectively. WGMn1:0: Waveform generation mode bits Combined with the WGMn2 bit in the TCCRnB register, these bits control the counting sequence of the counter, the source for maximum (TOP) counter value, and what type of waveform generation to be used as shown in Table 11.5. Modes supported by the timer/counter includes normal mode (counter), clear timer on compare match (CTC) mode, fast PWM mode, and phase- correct-PWM modes. Figure 11.10 ■ Source: Atmel Corporation, The Atmel AVR Microcontroller The operation mode of a timer is selected by the Timer/Counter control register A (TCCRnA, n = 0, …, 5) and one or two bits in the Timer/Counter control register B (TCCRnB, n = 0, …, 5 shown in Figure 11.7). The contents of the Timer/Counter control register A are shown in Figure 11.10. For the 8-bit timer/counter, the WGMn1:WGMn0 bits of the TCCRnA register (n = 0 or 2) and the WGMn2 bit of the TCCRnB register select the operation mode, as shown in Table 11.5. The 8-bit timer/counter (TCNTn, n = 0 or 2) is compared with the output-compare register (OCRnA and OCRnB, n = 0 or 2) in each timer clock cycle. Whenever the value in the TCNTn counter equals that of the OCRnx register, the voltage level of the associated pin may change (pin voltage level change is also called pin action), and the associated outputcompare match flags are set. The output-compare pin actions associated with the normal and CTC (non-PWM), fast PWM, and phase-correct PWM modes are shown in Table 11.2 through Table 11.4, respectively. The output-compare match flags and the time overflow flags are contained in Timer/Counter interrupt flag register 0 and 2 shown in Figure 11.11. Interrupts are requested if they are enabled. Timer/Counter2 output-compare match and overflow interrupts are enabled/disabled by programming the Timer/Counter2 interrupt mask register shown in Figure 11.12. Timer/Counter control register A(TCCR0A and TCCR2A) COMnx1 COMnx0 Description 0 0 Normal PORT operation, OCnx flip-flop disconnected from OCnx pin 0 1 Toggle OCnx signal on compare match 1 0 Clear OCnx signal on compare match 1 1 Set OCnx signal on compare match Source: Atmel Corporation, The Atmel AVR Microcontroller Table 11.2 ■ Compare match output behavior in non-PWM mode (8-bit timer) Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 11.5 ■ 361 Timer/Counter Operation Modes COMnx1 COMnx0 Description 0 0 1 0 1 1 Normal PORT operation, OCnA flip-flop disconnected from OCnA pin 1 0 Clear OCnx signal on compare match, set OCnx at BOTTOM (non-inverting mode) 1 1 Set OCnx signal on compare match, clear OCnx at BOTTOM (inverting mode) Normal PORT operation, OCnx flip-flop disconnected from OCnx pin Note: 1. This option is not available for OCnB (n = 0 or 2) module. Source: Atmel Corporation, The Atmel AVR Microcontroller ■ Table 11.3a (8-bit timer) Compare match output behavior in Fast-PWM mode (WGMn2:0 = 011, TOP = 0xFF) COMnx1 COMnx0 0 0 Description 01 11 Toggle OCnA on compare match 1 0 Set OCnx at BOTTOM (non-inverting mode) 1 1 Clear OCnx at BOTTOM (inverting mode) Normal PORT operation, OCnx flip-flop disconnected from OCnx pin Note: 1. This option is not available for OCnB (n = 0 or 2) module. Source: Atmel Corporation, The Atmel AVR Microcontroller Table 11.3b ■ Compare match output behavior in Fast-PWM mode (WGMn2:0 = 111, TOP = OCRnA) (8-bit timer) COMnx1 COMnx0 Description 0 0 Normal PORT operation, OCnx flip-flop disconnected from OCnx pin 02 12 WGMn2=0: normal PORT operation, OCnA flip-flop disconnected from OCnA pin 1 0 1 1 WGMn2=1: Toggle OCnA on compare match Clear OCnx flip-flop on compare match during up-counting Set OCnx flip-flop on compare match during down-counting Set OCnx flip-flop on compare match during up-counting Clear OCnx flip-flop on compare match during down-counting Notes: 1. A special case occurs when OCRnx equals TOP and COMnx1 is set to 1. In this case, the compare match is ignored, but the set or clear is done at the TOP. 2. This option is not available for OCnB (n = 0 or 2) module. Source: Atmel Corporation, The Atmel AVR Microcontroller ■ Compare match output behavior in Phase-Correct-PWM mode1 (8-bit timer) 7 6 5 4 3 2 1 0 — — — — — OCFnB OCFnA TOVn R R R R R R R R Reset value = 0 x 00 OCFnB: Timer/Counter n output compare match B flag 0 = Compare match between Timer n and OCRnB did not occur. 1 = Compare match between Timer n and OCRnB has occurred. OCFnA: Timer/Counter n output compare match A flag 0 = Compare match between Timer n and OCRnA did not occur. 1 = Compare match between Timer n and OCRnA has occurred. TOVn: Timer/Counter n overflow interrupt enable 0 = Timer/Counter n hasn’t overflown since this flag was last cleared. 1 = Timer/Counter n has overflown since this flag was last cleared. Figure 11.11 ■ Timer/Counter n interrupt flag register (TIFR0, TIFR2) Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. Source: Atmel Corporation, The Atmel AVR Microcontroller Table 11.4 Chapter 11 ■ Timer Functions of the Mega AVR 7 6 5 4 3 2 1 0 — — — — — OCIEnB OCIEnA TOIEn R R R R R R /W R/W R/W Reset value = 0 x 00 OCIEnB: Timer/Counter n output compare match B interrupt enable 0 = Disable the OCnB match interrupt 1 = Enable the OCnB match interrupt OCIEnA: Timer/Counter n output compare match A interrupt enable 0 = Disable the OCnA match interrupt 1 = Enable the OCnA match interrupt TOIEn: Timer/Counter n overflow interrupt enable 0 = Disable Timer/Counter n overflow interrupt 1 = Enable Timer/Counter n overflow interrupt Figure 11.12 ■ Source: Atmel Corporation, The Atmel AVR Microcontroller 362 Timer/Counter n interrupt mask register (TIMSK0 and TIMSK2) In Table 11.5, Mode WGM2 • The TOP value refers to the maximum value that the 8-bit timer/counter can count up to. • The Update of OCRx at column refers to the time that the output-compare register is updated. • The timer overflow flag (TOV) can be set when the timer/counter counts to the MAX, BOTTOM, or TOP value, depending upon the operation mode. WGM1 WGM0 Timer/Counter mode of operation TOP Update of OCRx at TOV flag set on(1)(2) 0 0 0 0 Normal 0xFF immediate MAX 1 0 0 1 PWM, phase correct 0xFF TOP BOTTOM 2 0 1 0 CTC OCRnA immediate MAX 3 0 1 1 Fast PWM 0xFF TOP MAX 4 1 0 0 Reserved — — — 5 1 0 1 PWM, phase correct OCRnA TOP BOTTOM 6 1 1 0 Reserved — — — 7 1 1 1 Fast PWM OCRnA BOTTOM TOP Notes: 1. MAX = 0xFF. 2. BOTTOM = 0x00. Source: Atmel Corporation, The Atmel AVR Microcontroller Table 11.5 ■ 8-Bit timer/counter waveform generation mode bit description 11.5.2 16-Bit Timer/Counter Operation Modes A 16-bit timer/counter has five operation modes, as listed in Table 11.6. These operation modes are selected by programming the WGMn3:WGMn2 bits of the Timer/Counter control register B (TCCRnB, n = 1, 3, 4, or 5) together with the WGMn1:WGMn0 bits of the Timer/ Counter control register A (TCCRnA, n = 1, 3, 4, 5). The contents of the TCCRnA (n = 1, 3, 4, or 5) are shown in Figure 11.13. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 11.5 ■ 363 Timer/Counter Operation Modes Mode WGMn3 WGMn2 WGMn1 WGMn0 Timer/Counter mode of operation TOP Update of OCRx at TOV flag set on 0 0 0 0 0 Normal 0xFFFF Immediate MAX 1 0 0 0 1 PWM, phase correct, 8-bit 0x00FF TOP BOTTOM 2 0 0 1 0 PWM, phase correct, 9-bit 0x01FF TOP BOTTOM 3 0 0 1 1 PWM, phase correct, 10-bit 0x03FF TOP BOTTOM 4 0 1 0 0 CTC OCRnA Immediate MAX 5 0 1 0 1 Fast PWM, 8-bit 0x00FF BOTTOM TOP 6 0 1 1 0 Fast PWM, 9-bit 0x01FF BOTTOM TOP 7 0 1 1 1 Fast PWM, 10-bit 0x03FF BOTTOM TOP 8 1 0 0 0 PWM, phase and frequency correct ICRn BOTTOM BOTTOM 9 1 0 0 1 PWM, phase and frequency correct OCRnA BOTTOM BOTTOM 10 1 0 1 0 PWM, phase correct ICRn TOP BOTTOM 11 1 0 1 1 PWM, phase correct OCRnA TOP BOTTOM 12 1 1 0 0 CTC ICRn Immediate MAX 13 1 1 0 1 (Reserved) – – – 14 1 1 1 0 Fast PWM ICRn BOTTOM TOP 15 1 1 1 1 Fast PWM OCRnA BOTTOM TOP Source: Atmel Corporation, The Atmel AVR Microcontroller ■ 16-Bit timer waveform generation mode bit description 7 6 5 4 3 2 1 0 COMnA1 COMnA0 COMnB1 COMnB0 COMnC1 COMnC0 WGMn1 WGMn0 R/W R/W R/W R/W R/W R/W R/W R/W Reset value = 0 x 00 COMnA1:0: Compare output mode for channel A (n = 1, 3, 4, or 5) COMnB1:0: Compare output mode for channel B COMnC1:0: Compare output mode for channel C COMnA1:0, COMnB1:0, COMnC1:0 control the output pins (OCnA, OCnB, and OCnC, respectively) behavior. If one or both of the COMnA1:0 bits are written to 1, the OCnA output overrides the normal port functionality of the I/O pin it is connected to. If one or both of the COMnB1:0 bits are written to 1, the OCnB output overrides the normal port functionality of the I/O pin it is connected to. If one or both of the COMnC1:0 bits are written to 1, the OCnC output overrides the normal port functionality of the I/O pin it is connected to. When the OCnA, OCnB, or OCnC is connected to the pin, the function of the COMnx1:0 bits is dependent of the WGM3:0 bits setting. Tables 11.7, 11.8, and 11.9 show the COMnx1:0 bit functionality for different WGMn3:0 settings. WGMn1:0: Waveform generation mode bits Combined with the WGMn3:2 bits in TCCRnB register, these bits control the counting sequence of the counter, the source for maximum (TOP) counter value, and what type waveform generation to be used. Modes of operations supported by the Timer/Counter unit are listed in Table 11.6. Figure 11.13 ■ Source: Atmel Corporation, The Atmel AVR Microcontroller Table 11.6 Timer/Counter n control register A (TCCR1A, TCCR3A, TCCR4A, TCCR5A) Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 364 Chapter 11 ■ Timer Functions of the Mega AVR Once enabled, the 16-bit timer/counter (TCNTx, x = 1, 3, 4, or 5) is compared with the 16-bit output-compare register (OCRnx, 1, 3, 4, or 5, x = A, B, or C) in each timer clock cycle. When these two registers are equal, the output-compare pin (OCnx, n = 1, 3, 4, or 5, x = A, B, or C) voltage level may be changed. The pin action (i.e., the OCnx pin voltage-level change) on compare match depends on the operation modes and is defined in Table 11.7 (normal and CTC modes), Table 11.8, and Table 11.9, respectively. COMnx1 COMnx0 Description 0 0 Normal PORT operation, OCnA/OCnB/OCnC disconnected 0 1 Toggle OCnA/OCnB/OCnC on compare match 1 0 Clear OCnA/OCnB/OCnC (pull low) on compare match 1 1 Set OCnA/OCnB/OCnC (pull high) on compare match Source: Atmel Corporation, The Atmel AVR Microcontroller Table 11.7 ■ Compare match output behavior in non-PWM mode (16-bit timer) COMnx1 COMnx0 0 0 Normal PORT operation, OCnA/OCnB/OCnC disconnected Description 0 1 WGMn 3:0 = 14 or 15: toggle OCnA on compare match, OCnB and OCnC disconnected (normal PORT operation). For all other PWM WGMn settings, normal PORT operation, OCnA/OCnB/OCnC disconnected. 1 0 Clear OCnA/OCnB/OCnC (pull low) on compare match, set OCnA/OCnB/OCnC at BOTTOM (non-inverting mode) 1 1 Set OCnA/OCnB/OCnC (pull high) on compare match, clear OCnA/OCnB/OCnC at BOTTOM (inverting mode) Source: Atmel Corporation, The Atmel AVR Microcontroller Table 11.8 ■ Compare match output behavior in Fast-PWM mode (16-bit timer) COMnx1 COMnx0 Description 0 0 Normal PORT operation, OCnA/OCnB/OCnC disconnected 0 1 WGMn 3:0 = 9 or 11: toggle OCnA on compare match, OCnB and OCnC disconnected (normal PORT operation). For all other PWM WGMn settings, normal PORT operation, OCnA/OCnB/OCnC disconnected. 1 0 Clear OCnA/OCnB/OCnC (pull low) on compare match when up-counting, set OCnA/OCnB/OCnC on compare match when down-counting 1 1 Set OCnA/OCnB/OCnC (pull high) on compare match when up-counting. Clear OCnA/OCnB/OCnC on compare match when down-counting. Source: Atmel Corporation, The Atmel AVR Microcontroller Table 11.9 ■ Compare output mode, Phase Correct and Phase-and-Frequency-Correct PWM mode (16-bit) The 16-bit timer/counter also supports the input-capture operation. The input-capture operation is triggered by the falling edge or the rising edge of the associated input-capture pin (ICPn pin). The capture edge is selected by the bit 6 of the Timer/Counter control register B (shown in Figure 11.7c). The occurrence of input-capture and output-compare match causes the Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. ■ 365 Timer/Counter Operation Modes 7 6 5 4 3 2 1 0 — — ICFn — OCFnC OCFnB OCFnA TOVn R R R/W R R/W R/W R/W R/W Reset value = 0 x 00 Figure 11.14 ■ Timer/Counter n interrupt flag register (TIFR1, TIFR3, TIFR4, TIFR5) 7 6 5 4 3 2 1 0 — — ICIEn — OCIEnC OCIEnB OCEnA TOIEn R/W R/W R R R/W R R/W R/W ICIEn: Timer/Counter n, input-capture interrupt enable 0 = Disable Timer/Counter n input-capture interrupt 1 = Enable Timer/Counter n input-capture interrupt OCIEnC: Timer/Counter n output compare C match interrupt enable 0 = Disable Timer/Counter n output compare C match interrupt 1 = Enable Timer/Counter n output compare C match interrupt OCIEnB: Timer/Counter n output compare B match interrupt enable 0 = Disable Timer/Counter n output compare B match interrupt 1 = Enable Timer/Counter n output compare B match interrupt OCIEnA: Timer/Counter n output compare A match interrupt enable 0 = Disable Timer/Counter n output compare A match interrupt 1 = Enable Timer/Counter n output compare A match interrupt TOIEn: Timer/Counter n, overflow interrupt enable 0 = Disable Timer/Counter n overflow interrupt 1 = Enable Timer/Counter n overflow interrupt Figure 11.15 ■ Source: Atmel Corporation, The Atmel AVR Microcontroller ICFn: Timer/Counter n, input-capture flag 0 = No capture event occurred on the ICPn pin. 1 = A capture event has occurred on the ICPn pin. OCFnC: Timer/Counter n output compare C match flag 0 = TCNTn has not matched the OCRnC register since this flag was last cleared. 1 = TCNTn has matched the OCRnC register. OCFnB: Timer/Counter n output compare B match flag 0 = TCNTn has not matched the OCRnB register since this flag was last cleared. 1 = TCNTn has matched the OCRnB register. OCFnA: Timer/Counter n output compare A match flag 0 = TCNTn has not matched the OCRnA register since this flag was last cleared. 1 = TCNTn has matched the OCRnA register. TOVn: Timer/Counter n, overflow interrupt flag 0 = TCNTn has not overflowed since this flag was last cleared. 1 = TCNTn has overflowed. Note: All of these flags will be cleared when their interrupt service routines are entered. The user can also write a 1 to each individual flag to clear it. Reset value = 0 x 00 Source: Atmel Corporation, The Atmel AVR Microcontroller 11.5 Timer/Counter n interrupt mask register (TIMSK1, TIMSK3, TIMSK4, TIMSK5) associated flag bits in the interrupt flag register (TIFRn, n = 1, 3, 4, or 5) shown in Figure 11.14 to be set. Interrupts may be requested if they are enabled. The timer/counter interrupts are enabled by programming the timer/counter interrupt mask register (TIMSKn, n = 1, 3, 4, or 5) shown in Figure 11.15. The 16-bit timer and output-compare registers are divided into high byte (TCNTnH, OCRnxH) and low byte (TCNTnL, OCRnxL). Like any other 16-bit register, the read access of the TCNTn and OCRnx registers should start from the low byte, whereas the write access of the TCNTn and OCRnx registers should start from the high byte. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 366 Chapter 11 ■ Timer Functions of the Mega AVR 7 6 5 4 3 2 1 0 FOCnA FOCnB FOCnC — — — — — R/W R/W R/W R R R R R Reset value = 0 x 00 FOCnA: Force output compare for channel A FOCnB: Force output compare for channel B FOCnC: Force output compare for channel C These bits are active only when WGMn3:0 bits specify a non-PWM mode. When writing a logical one to the FOCnA/FOCnB/FOCnC bit, an immediate compare match is forced on the waveform generation unit. The OCnA/OCnB/OCnC output is changed according to its COMnx1:0 setting. No interrupt is generated. Nor will timer be cleared in CTC mode using OCRnA as TOP. Figure 11.16 ■ Source: Atmel Corporation, The Atmel AVR Microcontroller The output-compare pin can be forced to either high or low by programming the Timer/ Counter control register C as shown in Figure 11.16. Timer/Counter n control register C(TCCR1C, TCCR3C, TCCR4C, TCCR5C) 11.6 Applications of Each Timer/Counter Operation Mode A timer/counter may be used to create time delay, generate waveforms, and measure signal parameters. The applications of a timer depend on its operation mode. We describe the applications of the AVR timer based on its application modes. 11.7 Using the Timer Normal Mode In this mode, the timer counts up from 0 to the TOP value (0×FF for 8-bit timers and 0×FFFF for 16-bit timers), rolls over to 0, and then counts up again. The timer/counter overflow flag (TOVn) is set to 1 when the timer/counter rolls over to 0. This flag is cleared whenever the timer/counter overflow interrupt service routine is entered. It is also cleared by writing a 1 to it. A timer (8-bit and 16-bit) in normal mode is used to create time delays and generate digital waveforms. The 16-bit timer in normal mode is also used to measure signal parameters such as period, pulse width, frequency, and duty cycle because it supports input-capture function (not supported by an 8-bit timer). 11.7.1 Using the Normal Mode in Creating Time Delays Although all timers can be used to generate a time delay, we do not use 8-bit timers in this application because the counting range of an 8-bit timer is quite limited. The user can use two methods to create a time delay: • Timer overflow: Let the timer count up from certain value until it overflows. Using this method, we calculate the timer count (TC) required to create the desired time delay (tD). Place the value 2n – TC in the timer, let it count up, and wait until it overflows. • Output-compare match: Using this method, we calculate the timer count required to create the desired delay, add this count to the current timer value, place the sum in an appropriate output-compare register (OCRnx), and let the timer to count up until its value matches that of the OCRnx register. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 11.7 ■ Using the Timer Normal Mode 367 Example 11.1 ▼ Write a function to create a time delay that is a multiple of 100 ms using the Timer/ Counter1, assuming that fclkI/O = 16 MHz. Solution: By choosing clkI/O as the clock input and setting the prescaler to 64, the timer count required to create a 100 ms delay is 25,000 (= 100 × 1023 × 16 × 106 ÷ 64). The subroutine that uses the timer overflow method to create a time delay that is a multiple of 100 ms is as follows: ; ----------------------------------------------------------------------------------------------------------------------------------------------; The following subroutine creates a time delay that is a multiple of 100 ms ; using the Timer 1 overflow. The multiple is passed in register R16. ; ----------------------------------------------------------------------------------------------------------------------------------------------.def tmp1 = r20 delayby100ms: ldi tmp1,0 ; configure Timer 1 to normal mode sts TCCR1A,tmp1 ; with clock source set to ldi tmp1,0x03 ; clk_I/O/64 sts TCCR1B,tmp1 ; " wp100: ldi tmp1,high(40536) ; Let Timer 1 count up from 40536 (2**16 – 25000) so that it sts TCNT1H,tmp1 ; overflows in 25000 clock cycles ldi tmp1,low(40536) ; " sts TCNT1L,tmp1 ; " ldi tmp1,1<<TOV1 ; clear TOV1 flag sts TIFR1,tmp1 ; " wt100: lds tmp1,TIFR1 ; wait until TOV1 flag is set to 1 sbrs tmp1,TOV1 ; " rjmp wt100 ; " dec r16 brne wp100 ret The C function that creates the same delay is as follows: void delayby100ms(unsigned char cx) { TCCR1A = 0; // configure Timer 1 to normal mode with clock source TCCR1B = 0x03; // set to clkI/O/64 while(cx){ TCNT1 = 40536; // load 40536 into TCNT1 so that it overflows in 25000 clock cycles TIFR1 = 1 << TOV1; // clear TOV1 flag while(!(TIFR1 & (1<<TOV1))); // wait until TOV1 is set to 1 cx– –; } } The subroutine that uses the output-compare function to create a delay that is a multiple of 100 ms is as follows: ; ----------------------------------------------------------------------------------------------------------------------------------------------; The following subroutine uses Timer 1 OC1A to create a time delay that is a multiple of ; 100 ms. The multiple is passed in R16. ; ----------------------------------------------------------------------------------------------------------------------------------------------.def tmp1 = r8 .def tmp2 = r20 .def tmp3 = r21 Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 368 Chapter 11 ■ Timer Functions of the Mega AVR dlyby100msOC: ldi sts ldi sts wp100: lds lds ldi add ldi adc sts sts ldi sts wt100: lds sbrs rjmp dec brne ret tmp2,0 TCCR1A,tmp2 tmp2,0x03 TCCR1B,tmp2 tmp1,TCNT1L tmp2,TCNT1H tmp3,low(25000) tmp1,tmp3 tmp3,high(25000) tmp2,tmp3 OCR1AH,tmp2 OCR1AL,tmp1 tmp2,1 << OCF1A TIFR1,tmp2 tmp1,TIFR1 tmp1,OCF1A wt100 r16 wp100 ; configure timer 1 to normal mode ; with clock source set to ; clkI/O /64 ; " ; make a copy of Timer 1 ; " ; add a delay count of 25000 to this copy ; " ; " ; " ; start an output compare operation ; " ; clear OCF1A flag ; " ; wait until OCF1A flag is set to 1 ; " ; " ; is the multiple decremented to 0 yet? The C language version of the function is as follows: // -------------------------------------------------------------------------------------------------------------------------------------------// The next function creates a time delay that is a multiple of 100 ms using OC1A function. // -------------------------------------------------------------------------------------------------------------------------------------------void dlyby100msOC (unsigned char cx) { TCCR1A = 0; // configure Timer 1 to operate in normal mode TCCR1B = 0x03; // using clkI/O /64 as its clock source while(cx){ OCR1A = TCNT1 + 25000; // start Timer 1 OC1A compare operation TIFR1 = 1 << OCF1A; // clear the OCF1A flag while(!(TIFR1 & (1<<OCF1A))); // wait until OCF1A flag is set cx– –; } } ▲ A set of time delay functions and subroutines for the Mega MCUs have been created and stored in files delays_Mega.asm and delays_Mega.c and saved in the complimentary CD. 11.7.2 Using the Timer Normal Mode in Waveform Generation To use the timer normal mode to generate waveform, the OCnx pin of interest must be configured for output. The pin action of compare match toggle (COMnx1:COMnx0 = 01) of normal mode is used to generate periodic square wave with any duty cycle. The CPU needs to involve frequently in the waveform generation process. For example, the procedure to generate a waveform with 50% duty cycle and period equal to 2*N timer clock cycles is as follows: Step 1 Configure OCnx to operate in normal mode and set the COMnx1:COMnx0 bits to 01 (toggle). Choose appropriate clock source for the Timer/Counter n. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 11.7 ■ 369 Using the Timer Normal Mode Step 2 Make a copy of the timer/counter value (TCNTn, n = 0, …, 5). Step 3 Add N to this copy and store the sum in the output-compare register x (OCRnx). Step 4 Enable OCnx interrupt and write an interrupt service routine for OCnx that performs the operations described in Step a and b. Step a Clear the OCFnx flag (n = 0, …, 5 and x = A, …, C). Step b Add N to the OCRnx register and return from interrupt. Step 5 The MCU continues to perform other operations. Example 11.2 ▼ Write a program to generate a 5 kHz square wave with a 50% duty cycle from the OC0A pin, assuming that the frequency of clkI/O is 16 MHz. Solution: The period of a 5 kHz square wave is 0.2 ms. To generate a 5 kHz square wave, the OC0A pin must be toggled every 0.1 ms. By setting the prescaler to 8, the timer count required to toggle OC0A pin every 0.1 ms is 0.1 ms × 16 × 106/8 = 200. The following assembly program implements the previous procedure and generates a 50% duty cycle 5 kHz square waveform: start: .include <m2560def.inc> .def tmp = r16 .def tmp1= r17 .equ NN = 200 .cseg .org 0x00 jmp start .org OC0AAddr jmp oc0AISR .org 0xF6 ldi tmp,low(RAMEND) out SPL,tmp ldi r16,high(RAMEND) out SPH,tmp ldi tmp,0x80 out DDRB,tmp ldi tmp,0x40 out TCCR0A,tmp ldi tmp,0x02 out TCCR0B,tmp ldi tmp,0x02 sts TIMSK0,tmp out TIFR0,tmp in tmp,TCNT0 ; delay count for output compare operation ; initialize the SP ; " ; " ; " ; configure PORTB pin 7 (OC0A pin) for output ; " ; OC0A pin toggle on compare match ; " ; select normal mode and set clock source ; to clk_I/O/8 ; enable OC0A compare match interrupt ; " ; clear OCF0A interrupt flag ; start the first OC0A compare operation with Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 370 Chapter 11 again: ■ Timer Functions of the Mega AVR ldi add out sei jmp tmp1,NN tmp,tmp1 OCR0A,tmp again ; delay equal to NN ; " ; " ; enable interrupt globally ; wait for OC0A interrupt ; ----------------------------------------------------------------------------------------------------------------------------------------------; The following instruction sequence is the OC0A compare match interrupt service routine. ; ----------------------------------------------------------------------------------------------------------------------------------------------oc0AISR: in ldi add out ldi out reti tmp,OCR0A tmp1,NN tmp,tmp1 OCR0A,tmp tmp,0x02 TIFR0,tmp ; start the next OC0A compare operation ; with NN as its delay count ; " ; " ; clear OCF0A interrupt flag ; " The C language version of the program is as follows: #include <avr\io.h> #include <avr\interrupt.h> #define NN 200 void main (void) { DDRB |= 0x80; TCCR0A = 0x40; TCCR0B = 0x02; TIMSK0 = 0x02; TIFR0 = 0x02; OCR0A = TCNT0 + NN; sei(); while(1); } // delay count to be used in OC0A compare operation // configure OC0A pin for output // OC0A pin toggle on compare match // normal mode, clock source set to clkI/O÷8 // enable OC0A compare match interrupt // clear OCF0A flag // start the first compare operation // enable interrupt globally // wait for interrupt to occur // -------------------------------------------------------------------------------------------------------------------------------------------// OC0A interrupt service routine. It starts the next compare operation and clears the OCF0A flag. // -------------------------------------------------------------------------------------------------------------------------------------------ISR(TIMER0_COMPA_vect) { OCR0A += NN; } // start the next OC0A compare with NN as delay count ▲ Example 11.3 ▼ Write a program that uses the OC1A pin to generate a 50 Hz square wave with 75% duty cycle, assuming that fclk_I/O = 16 MHz. Solution: By selecting clkI/O ÷ 8 as the timer clock source, the high and low intervals of one cycle of the 50 Hz waveform consist of 30,000 and 10,000 timer clock cycles, respectively. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 11.7 ■ Using the Timer Normal Mode 371 We force the OC1A pin to high initially and choose toggle as the compare match pin action. Interrupt is used to restart the subsequent output-compare operations required to sustain the waveform. The assembly program that generates the specified waveform is as follows: .include <m2560def.inc> .def tmp = r16 .def tmp1 = r17 .def tmp2 = r18 .def HioLo = r29 .equ hiCnt = 30000 ; delay count for output compare operations .equ loCnt = 10000 ; " .cseg .org 0x00 jmp start .org oc1AAddr ; interrupt vector of OC1A jmp oc1AISR .org 0xF6 start: ldi tmp,low(RAMEND) ; initialize the SP out SPL,tmp ; " ldi r16,high(RAMEND) ; " out SPH,tmp ; " ldi tmp,0x20 ; configure OC1A/PB5 pin for output out DDRB,tmp ; " ldi tmp,0xC0 ; OC1A compare match is pull high sts TCCR1A,tmp ; " ldi tmp,0x02 ; set Timer 1 clock prescaler to 8, sts TCCR1B,tmp ; and select normal mode ldi tmp,0x80 ; force OC1A pin high immediately sts TCCR1C,tmp ; " ldi tmp,0x40 ; select toggle for compare match on OC1A sts TCCR1A,tmp ; " ldi tmp2,high(hiCnt) ; perform an OC1A compare operation with hiCnt ldi tmp1,low(hiCnt) ; as the delay count lds tmp,TCNT1L ; " add tmp1,tmp ; " lds tmp,TCNT1H ; " adc tmp2,tmp ; " sts OCR1AH,tmp2 ; " sts OCR1AL,tmp1 ; " ldi HioLo,0 ; next compare operation uses loCnt as delay count ldi tmp,0x02 ; enable OC1A interrupt sts TIMSK1,tmp ; " out TIFR1,tmp ; clear OC1FA flag sei ; enable interrupt globally here: rjmp here ; ----------------------------------------------------------------------------------------------------------------------------------------------; The OC1AISR interrupt routine restart a new compare operation to OC1A using either ; loCnt or hiCnt as the delay count depending upon whether HioLo is 0 or 1. ; ----------------------------------------------------------------------------------------------------------------------------------------------oc1AISR: sbrc HioLo,0 ; select pin action for output compare operation rjmp addHi Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 372 Chapter 11 addHi: startOC: ■ Timer Functions of the Mega AVR ldi ldi ldi rjmp ldi ldi ldi lds add lds adc sts sts reti tmp1,low(loCnt) tmp2,high(loCnt) HioLo,1 startOC tmp1,low(hiCnt) tmp2,high(hiCnt) HioLo,0 tmp,OCR1AL tmp1,tmp tmp,OCR1AH tmp2,tmp OCR1AH,tmp2 OCR1AL,tmp1 ; use loCnt as the delay count of the current ; output compare operation ; next compare operation uses hiCnt as delay count ; use hiCnt as the delay count of the current ; output compare operation ; next compare operation uses loCnt as delay count ; start a new compare operation on OC1A channel ; " ; " ; " ; " ; " The C language version of the program is as follows: #include <avr\io.h> #include <avr\interrupt.h> #define hiCnt 30000 #define loCnt 10000 #define HI 1 #define LO 0 char HIoLO void main (void) { DDRB |= 0x20; TCCR1A = 0xC0; TCCR1B = 0x02; TCCR1C |= 0x80; TCCR1A = 0x40; OCR1A = TCNT1 + hiCnt; HIoLO = LO; TIMSK1 |= 0x02; TIFR1 = 0x02; sei(); while(1); } // delay count for high interval in a period // delay count for low interval in a period // flag to select hiCnt or loCnt // configure OC1A pin for output // OC1A pin pull high on compare match // normal mode, clock source set to clk_I/O/8 // force OC1A pin to high // select toggle as the OC1A pin action on compare match // start the first output compare operation // enable OC1A interrupt // clear the OCF1A flag // enable interrupt globally // wait for interrupt to occur // -------------------------------------------------------------------------------------------------------------------------------------------// OC1A interrupt service routine. It starts the next compare operation and clears the OCF1A flag. // -------------------------------------------------------------------------------------------------------------------------------------------ISR(TIMER1_COMPA_vect) { if(HIoLO){ OCR1A = OCR1A + hiCnt; HIoLO = LO; } else { OCR1A = OCR1A + loCnt; HIoLO = HI; } } ▲ Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 11.7 ■ 373 Using the Timer Normal Mode 11.7.3 Using the Normal Mode to Make Sound Mega MCU 3.3 μF OC1A Figure 11.17 ■ Speaker Source: Atmel Corporation, The Atmel AVR Microcontroller Making sound is easy. Connecting a waveform with an appropriate frequency (between 20 Hz to 20 kHz) to a speaker or a buzzer can make a sound. A two-tone siren is generated by connecting the OC1A (or any other output-compare pin) to a speaker or a buzzer and switching between two different frequencies. The circuit connection between the OC1A pin and a speaker is shown in Figure 11.17. Circuit connection for a speaker Example 11.4 ▼ Describe how to use OC1A pin of the Timer/Counter1 to generate a two-tone siren that oscillates between 440 and 880 Hz, assuming that the frequency of clkI/O is 16 MHz. Solution: By choosing clkI/O ÷ 8 as the clock source of Timer/Counter1, the frequency of the clock input of Timer/Counter1 is set to 2 MHz. In each cycle of the siren tone, the OC1A pin must be toggled twice. The periods of the 440 and 880 Hz siren tone are 2.2727 and 1.1364 ms, respectively. The delay counts of output-compare operation for the 440 and 880 Hz tones are calculated to be 2273 and 1136, respectively. The procedure for generating a siren is as follows: Step 1 Connect an 8 V speaker to the OC1A pin. Step 2 Configure Timer 1 to operate in normal mode, and set the compare match output action to toggle. Step 3 Enable OC1A interrupt. Start the first OC1A operation with 2273 as the delay count. Step 4 Write the service routine for the OC1A interrupt, which simply restarts the OC1A operation with 2273 as the delay count. Step 5 Wait for half a second. Step 6 Change the delay count for the OC1A operation to 1136, and use it in the OC1A interrupt service routine. Step 7 Wait for half a second. Step 8 Change delay count to 2273 and go to Step 5. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 374 Chapter 11 ■ Timer Functions of the Mega AVR The assembly that generates the two–tone siren is as follows: .include <m2560def.inc> .equ hiCnt = 1136 ; delay count for creating 880 Hz tone .equ loCnt = 2273 ; delay count for creating 440 Hz tone .def dlyHi = R20 .def dlyLo = R21 .def tmpH = R22 .def tmpL = R23 .cseg .org 0x00 jmp start .org OC1Aaddr jmp oc1AISR .org 0xF6 start: ldi tmpH,low(RAMEND) ; initialize the SP out SPL,tmpH ; " ldi tmpH,high(RAMEND) ; " out SPH,tmpH ; " ldi tmpH,0x20 ; configure OC1A/PB5 pin for output sts DDRB,tmpH ; " ldi tmpH,0x40 ; configure TMR1 to operate in normal mode with compare sts TCCR1A,tmpH ; match action set to toggle ldi tmpH,0x02 ; select clk_I/O/8 as clock input to Timer 1 sts TCCR1B,tmpH ; " ldi dlyHi,high(hiCnt) ; initialize the delay count for the compare operation ldi dlyLo,low(hiCnt) ; (use the delay count for 880 Hz) lds tmpL,TCNT1L ; read the 16-bit timer 1 lds tmpH,TCNT1H ; " add tmpL,dlyLo adc tmpH,dlyHi sts OCR1AH,tmpH ; start the first OC1A operation to start the high tone sts OCR1AL,tmpL ; " ldi tmpH,0x02 ; enable OC1A interrupt locally sts TIMSK1,tmpH ; " sts TIFR1,tmpH ; clear OCF1A flag sei ; enable interrupt globally again: ldi R16,5 ; wait for 0.5 s call dlyby100msOC ; " ldi dlyHi,high(loCnt) ; change delay count to that for 440 Hz ldi dlyLo,low(loCnt) ; " ldi R16,5 ; wait for 0.5 s call dlyby100msOC ; " ldi dlyHi,high(hiCnt) ; change delay count to that for 880 Hz ldi dlyLo,low(hiCnt) ; " rjmp again ; jump to switch tone ; ----------------------------------------------------------------------------------------------------------------------------------------------; The OC1AISR interrupt routine restarts a new compare operation to OC1A using ; dlyHi:dlyLo as delay count. ; ----------------------------------------------------------------------------------------------------------------------------------------------oc1AISR: lds tmpL,OCR1AL lds tmpH,OCR1AH Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 11.7 ■ 375 Using the Timer Normal Mode add adc sts sts reti tmpL,dlyLo tmpH,dlyHi OCR1AH,tmpH OCR1AL,tmpL ; " ; start the next compare operation for ; channel OC1A ; ----------------------------------------------------------------------------------------------------------------------------------------------; Include the dlyby100msOC subroutine here ; ----------------------------------------------------------------------------------------------------------------------------------------------The C language version of the program is as follows: #include <avr\io.h> #include <avr\interrupt.h> #define hiCnt 1136 #define loCnt 2273 unsigned delay; void dlyby100msOC(int k); void main (void) { DDRB |= 0x20; // configure OC1A/PB5 for output delay = loCnt; // prepare to generate the low tone (440 Hz) TCCR1A = 0x40; // configure OC1A to normal mode, compare match action set to toggle TCCR1B = 0x02; // use clk_I/O/8 as Timer 1 clock source OCR1A = TCNT1 + delay; // start the first compare operation TIMSK1 = 0x02; // enable OC1A compare match interrupt TIFR1 = 0x02; // clear OCF1A flag sei(); // enable interrupt globally while (1) { dlyby100msOC(5); // wait for 0.5 s delay = hiCnt; // switch to delay count for 880 Hz tone dlyby100msOC(5); delay = loCnt; // switch to delay count for 440 Hz tone } } // -------------------------------------------------------------------------------------------------------------------------------------------// Include the dlyby100msOC() function here. // --------------------------------------------------------------------------------------------------------------------------------------------// -------------------------------------------------------------------------------------------------------------------------------------------// OC1A interrupt service routine. It starts the next compare operation and clears the OCF1A flag. // -------------------------------------------------------------------------------------------------------------------------------------------ISR(TIMER1_COMPA_vect) { OCR1A += delay; // start a new output compare operation TIFR1 = 0x02; // clear OCF1A flag } ▲ 11.7.4 Using the Normal Mode to Play a Song A siren can be considered as a song with two notes. A song is created by modifying the siren program. Each note has two components: one is the frequency and the other is the duration. To make the switching of frequency easier, the whole song score should be stored in a table. The Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 376 Chapter 11 ■ Timer Functions of the Mega AVR duration of a quarter note is about 0.4 s. The durations of other notes are derived proportionally. The complete list of the music notes and their frequencies is given in Appendix F. To play a song using the speaker, we place the frequencies and durations of all the notes in a music score in a table. For each note, the user program uses the output-compare function to generate the digital waveform with the specified frequency and duration. It is common for a song to have several contiguous identical notes in several different measures. When playing multiple contiguous identical notes, the buzzer/speaker generates one long note instead of multiple notes. This problem is solved by inserting a short note between two adjacent identical notes with an inaudible frequency (lower than 20 Hz or higher than 20 kHz). A music score may also have rest notes. A rest note can be played by generating an inaudible sound with the specified duration. The following example illustrates this idea. Example 11.5 ▼ Use the circuit shown in Figure 11.17, and write a C program to play “Home Sweet Home,” assuming that the frequency of clkI/O is 16 MHz. Solution: To generate the correct note, we need to calculate the appropriate delay count for each note in the music score. Assume that we select clkI/O ÷ 8 (= 2 MHz) as clock source to the Timer/Counter1; then the delay count used in compare operation for a note with frequency f is given by the following expression: delay Count = 2 × 106 ÷ (2 × f) (11.2) For example, the delay count for the A4 note (440 Hz) is 2273 (= 2 × 106 ÷ (2 × 440)). We use the delayby10msOC () function to generate durations for all the notes of the given song. This function generates a time delay that is a multiple of 10 ms. The assembly language version of the program is as follows: .include .equ .equ .equ .equ .equ .equ .equ .equ .equ .equ .equ .equ .equ .equ .equ .equ .equ .equ .equ .equ .equ .equ <m2560def.inc> C4H = high(3822) C4L = low(3822) C4SH = high(3608) C4SL = low(3608) D4FH = high(3608) D4FL = low(3608) D4H = high(3405) D4L = low(3405) D4SH = high(3214) D4SL = low(3214) E4FH = high(3214) E4FL = low(3214) E4H = high(3034) E4L = low(3034) F4H = high(2863) F4L = low(2863) F4SH = high(2703) F4SL = low(2703) G4FH = high(2703) G4FL = low(2703) G4H = high(2551) G4L = low(2551) ; delay count for creating 261.63 Hz tone ; delay count for creating 277.18 Hz tone ; 277.18 Hz ; 293.66 Hz ; 311.13 Hz ; 311.13 Hz ; 329.63 Hz ; 349.23 Hz ; 369.99 Hz ; 369.99 Hz ; 392.00 Hz Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 11.7 ■ 377 Using the Timer Normal Mode .equ .equ .equ .equ .equ .equ .equ .equ .equ .equ .equ .equ .equ .equ .equ .equ .equ .equ .equ .equ .equ .equ .equ .equ .equ .equ .equ .equ .equ .equ .equ .equ .equ .equ .equ .equ .equ .equ .equ .equ .equ .equ .equ .equ .equ .equ .equ .equ .def .def .def .def G4SH G4SL A4FH A4FL A4H A4L A4SH A4SL B4FH B4FL B4H B4L C5H C5L C5SH C5SL D5FH D5FL D5H D5L D5SH D5SL E5FH E5FL E5H E5L F5H F5L F5SH F5SL G5FH G5FL G5H G5L G5SH G5SL A5FH A5FL A5H A5L A5SH A5SL B5FH B5FL B5H B5L ZZH ZZL dlyHi dlyLo tmpH tmpL = high(2408) = low(2408) = high(2408) = low(2408) = high(2273) = low(2273) = high(2145) = low(2145) = high(2145) = low(2145) = high(2025) = low(2025) = high(1911) = low(1911) = high(1804) = low(1804) = high(1804) = low(1804) = high(1703) = low(1703) = high(1607) = low(1607) = high(1607) = low(1607) = high(1517) = low(1517) = high(1432) = low(1432) = high(1351) = low(1351) = high(1351) = low(1351) = high(1276) = low(1276) = high(1204) = low(1204) = high(1204) = low(1204) = high(1136) = low(1136) = high(1073) = low(1073) = high(1073) = low(1073) = high(1012) = low(1012) =0 = 20 = R20 = R21 = R22 = R23 ; 415.30 Hz ; 415.30 Hz ; 440.00 Hz ; 466.16 Hz ; 466.16 Hz ; 493.88 Hz ; 523.25 Hz ; 554.37 Hz ; 554.37 Hz ; 587.33 Hz ; 622.25 Hz ; 622.25 Hz ; 659.26 Hz ; 698.46 Hz ; 739.99 Hz ; 739.99 Hz ; 783.99 Hz ; 830.61 Hz ; 830.61 Hz ; 880.00 Hz ; 932.33 Hz ; 932.33 Hz ; 987.77 Hz ; an inaudible note ; " ; delay count high byte ; delay count low byte Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 378 Chapter 11 ■ Timer Functions of the Mega AVR .cseg .org 0x00 jmp start .org OC1Aaddr jmp oc1AISR .org 0xF6 start: ldi tmpH,low(RAMEND) ; initialize the SP out SPL,tmpH ; " ldi tmpH,high(RAMEND) ; " out SPH,tmpH ; " ldi tmpH,0x20 ; configure OC1A/PB5 pin for output out DDRB,tmpH ; " ldi tmpH,0x40 ; configure TMR1 to operate in normal mode and sts TCCR1A,tmpH ; set compare match action to toggle ldi tmpH,0x02 ; select clk_I/O/8 as clock input to Timer 1 sts TCCR1B,tmpH ; " ldi ZL,low(score<<1) ldi ZH,high(score<<1) lpm dlyLo,z+ lpm dlyHi,z+ lds tmpL,TCNT1L ; read the 16-bit timer 1 lds tmpH,TCNT1H ; " add tmpL,dlyLo adc tmpH,dlyHi sts OCR1AH,tmpH ; start the first OC1A operation to start the song sts OCR1AL,tmpL ; " ldi tmpH,0x02 ; enable OC1A interrupt locally sts TIMSK1,tmpH ; " out TIFR1,tmpH ; clear OCF1A flag sei ; enable interrupt globally ldi ZL,low(score<<1) ldi ZH,high(score<<1) songLp: lpm dlyLo,z+ ; read OC delay count high and low bytes lpm dlyHi,z+ cpi dlyHi,0 ; is the upper byte equal to 0? brne rdDur ; no, continue to the low byte cpi dlyLo,0 ; " breq done ; both bytes are zeros, stop rdDur: lpm r16,z+ ; read the duration of the current note call dlyby10msOC ; and place the current note for this duration rjmp songLp ; continue to the next note done: ldi r16,0 ; stop Timer 1 sts TCCR1B,r16 ; " rjmp done ; ----------------------------------------------------------------------------------------------------------------------------------------------; The OC1AISR interrupt routine restart a new compare operation to OC1A using ; dlyHi:dlyLo as the delay count. ; ----------------------------------------------------------------------------------------------------------------------------------------------oc1AISR: lds tmpL,OCR1AL ; start the next compare operation for lds tmpH,OCR1AH ; channel OC1A add tmpL,dlyLo ; " adc tmpH,dlyHi ; " Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 11.7 ■ Using the Timer Normal Mode 379 sts OCR1AH,tmpH ; " sts OCR1AL,tmpL ; " reti ; ----------------------------------------------------------------------------------------------------------------------------------------------; The following subroutine uses Timer 3 OC3A to create a time delay that is a multiple of ; 10 ms. The multiple is passed in R16. ; ----------------------------------------------------------------------------------------------------------------------------------------------dlyby10msOC: .def tmp1 = r8 .def tmp2 = r18 .def tmp3 = r19 ldi tmp2,0 ; configure Timer 3 to normal mode sts TCCR3A,tmp2 ; with clock source set to ldi tmp2,0x02 ; clk_I/O/8 sts TCCR3B,tmp2 ; " wp10: lds tmp1,TCNT3L ; make a copy of Timer 3 lds tmp2,TCNT3H ; " ldi tmp3,low(20000) ; add a delay count of 20000 to this copy add tmp1,tmp3 ; (equivalent to 10 ms) ldi tmp3,high(20000) ; " adc tmp2,tmp3 ; " sts OCR3AH,tmp2 ; start a compare operation on OC3A sts OCR3AL,tmp1 ; " ldi tmp2,0x02 ; clear OC3AF flag out TIFR3,tmp2 ; " wt10: in tmp1,TIFR3 ; wait until OC3AF flag is set to 1 sbrs tmp1,OCF3A ; " rjmp wt10 ; " dec r16 ; is the multiple decremented to 0 yet? brne wp10 ret score: .db F4L,F4H,30, G4L,G4H,10, A4L,A4H,60, B4FL,B4FH,20, ZZL,ZZH,3, B4FL,B4FH,60 .db C5L,C5H,20, ZZL,ZZH,3, C5L,C5H,60, A4L,A4H,20, ZZL,ZZH,3, A4L,A4H,40 .db C5L,C5H,40, B4FL,B4FH,60, A4L,A4H,20, B4FL,B4FH,40 .db G4L,G4H,40, A4L,A4H,120, F4L,F4H,30, G4L,G4H,10 .db A4L,A4H,60, B4FL,B4FH,20, ZZL,ZZH,3, B4FL,B4FH,60, C5L,C5H,20, ZZL,ZZH,3 .db C5L,C5H,80, A4L,A4H,40, C5L,C5H,40, B4FL,B4FH,60, A4L,A4H,20, B4FL,B4FH,40 .db G4L,G4H,40, F4L,F4H,80, ZZL,ZZH,40, C5L,C5H,20 .db ZZL,ZZH,3, C5L,C5H,20, F5L,F5H,60, E5L,E5H,20, D5L,D5H,60, C5L,C5H,20 .db C5L,C5H,80, A4L,A4H,40, C5L,C5H,40, B4FL,B4FH,60, A4L,A4H,20, B4FL,B4FH,40 .db G4L,G4H,40, A4L,A4H,120, C5L,C5H,20, ZZL,ZZH,3, C5L,C5H,20, F5L,F5H,60 .db E5L,E5H,20, D5L,D5H,60, C5L,C5H,20, ZZL,ZZH,3, C5L,C5H,80, A4L,A4H,40 .db C5L,C5H,40, C5L,C5H,40, B4FL,B4FH,80, G4L,G4H,40, F4L,F4H,120, ZZL,ZZH,40 .db C5L,C5H,160, B4FL,B4FH,80, G4L,G4H,80, F4L,F4H,40, ZZL,ZZH,40, G4L,G4H,40 .db ZZL,ZZH,40, A4L,A4H,80, ZZL,ZZH,40, C5L,C5H,40, F5L,F5H,60, E4L,E4H,20 .db D5L,D5H,60, C5L,C5H,20, ZZL,ZZH,3, C5L,C5H,80, A4L,A4H,40, C5L,C5H,40 .db B4FL,B4FH,60, A4L,A4H,20, B4FL,B4FH,40, G4L,G4H,40, F4L,F4H,120,0,0 The C program that plays the specified song is as follows: #include #include #define <avr\io.h> <avr\interrupt.h> C4 3822 // delay count for creating 261.63 Hz tone Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 380 Chapter 11 ■ Timer Functions of the Mega AVR #define C4S 3608 // delay count for creating 277.18 Hz tone #define D4F 3608 // 277.18 Hz #define D4 3405 // 293.66 Hz #define D4S 3214 // 311.13 Hz #define E4F 3214 // 311.13 Hz #define E4 3034 // 329.63 Hz #define F4 2863 // 349.23 Hz #define F4S 2703 // 369.99 Hz #define G4F 2703 // 369.99 Hz #define G4 2551 // 392.00 Hz #define G4S 2408 // 415.30 Hz #define A4F 2408 // 415.30 Hz #define A4 2273 // 440.00 Hz #define A4S 2145 // 466.16 Hz #define B4F 2145 // 466.16 Hz #define B4 2025 // 493.88 Hz #define C5 1911 // 523.25 Hz #define C5S 1804 // 554.37 Hz #define D5F 1804 // 554.37 Hz #define D5 1703 // 587.33 Hz #define D5S 1607 // 622.25 Hz #define E5F 1607 // 622.25 Hz #define E5 1517 // 659.26 Hz #define F5 1432 // 698.46 Hz #define F5S 1351 // 739.99 Hz #define G5F 1351 // 739.99 Hz #define G5 1276 // 783.99 Hz #define G5S 1204 // 830.61 Hz #define A5F 1204 // 830.61 Hz #define A5 1136 // 880.00 Hz #define A5S 1073 // 932.33 Hz #define B5F 1073 // 932.33 Hz #define B5 1012 // 987.77 Hz #define ZZ 20 // 50000 Hz (inaudible sound) unsigned int score[] = { F4,G4, A4,B4F,ZZ,B4F,C5,ZZ,C5,A4, ZZ,A4, C5,B4F,A4,B4F,G4,A4,F4,G4, A4,B4F,ZZ,B4F,C5,ZZ, C5,A4,C5,B4F,A4,B4F,G4,F4, ZZ,C5, ZZ,C5,F5,E5,D5,C5, C5,A4, C5,B4F,A4,B4F,G4,A4,C5,ZZ, C5,F5, E5,D5, C5,ZZ, C5,A4,C5, C5,B4F,G4,F4, ZZ,C5,B4F,G4,F4,ZZ, G4,ZZ, A4,ZZ, C5,F5, E5,D5, C5,ZZ,C5,A4, C5,B4F,A4,B4F,G4,F4,0}; unsigned char dur[] = { 30,10, 60,20, 3, 60, 20,3, 60,20, 3, 40, 40,60, 20,40, 40,120,30,10, 60,20, 3, 60, 20, 3, 80,40,40,60, 20,40, 40,80, 40,20, 3, 20,60,20,60,20, 80,40, 40,60, 20,40, 40,120,20,3, 20,60, 20,60, 20,3, 80,40,40, 40,80, 40,120,40,160,80,80,40,40, 40,40, 80,40, 40,60, 20,60, 20,3, 80,40, 40,60, 20,40, 40,120}; unsigned int delay; void delayby10msOC(unsigned char k); void main (void) { unsigned char j; DDRB |= 0x20; // configure OC1A/PB5 for output Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 11.7 ■ 381 Using the Timer Normal Mode delay = score[0]; TCCR1A = 0x40; TCCR1B = 0x02; OCR1A = TCNT1 + delay; TIMSK1 = 0x02; TIFR1 = 1<<OCF1A; sei(); j = 0; while(score[j]){ delay = score[j]; delayby10msOC(dur[j]); j++; } TCCR1B = 0; while(1); // configure OC1A to normal mode, set compare match action to toggle // use clk_I/O/8 as Timer 1 clock source // start the first compare operation // enable OC1A compare match interrupt // clear OCF1A flag // enable interrupt globally // stop Timer 1 } // -------------------------------------------------------------------------------------------------------------------------------------------// OC1A interrupt service routine. It starts the next compare operation and clears the OCF1A flag. // -------------------------------------------------------------------------------------------------------------------------------------------ISR(TIMER1_COMPA_vect) { OCR1A += delay; // start a new output compare operation } // -------------------------------------------------------------------------------------------------------------------------------------------// The following function creates a time delay that is a multiple of 10 ms using Timer 3 // OC3A function. // -------------------------------------------------------------------------------------------------------------------------------------------void delayby10msOC(unsigned char k) { TCCR3A = 0; // configure Timer 3 to normal mode TCCR3B = 0x02; // and select clk_I/O/8 as clock input OCR3A = TCNT3 + 20000; // start an output compare operation TIFR3 = 1<<OCF3A; // clear OCF3A flag while(k) { while(!(TIFR3 & (1<<OCF3A))); // wait for OCF3A flag to set OCR3A += 20000; // start a new OC3 compare operation TIFR3 = 1<<OCF3A; // clear OCF3A flag K– –; } } ▲ 11.7.5 Using the Normal Mode to Measure Signal Frequency To measure the frequency of a signal, we need to use the signal as the clock source of the timer/counter. After connecting the unknown signal to the external Tn pin input to the Timer/ Counter n and selecting Tn as the clock source, we enable Timer/Counter n to count up from 0 for 1 second. Depending upon the frequency of the unknown signal, the Timer/Counter n Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 382 Chapter 11 ■ Timer Functions of the Mega AVR may or may not overflow during the 1-second interval. The frequency of the unknown signal is expressed as follows: Frequency = tovCnt × 216 + final Timer count (11.3) where, tovCnt represents the number of times that Timer n overflows during the 1-second period. Example 11.6 ▼ Write a program to measure the frequency of an unknown signal connected to the T1 pin, assuming that fclk_I/O = 16 MHz. Solution: We select T1 as the clock source to Timer 1 and use Timer 5 to create a delay of 1 second. The assembly program that measures the frequency of the unknown signal is as follows: .include <m2560def.inc> start: again: .def tmp = r16 .def .def .def .cseg .org jmp .org jmp .org ldi out ldi out cbi ldi sts sts sts ldi ldi sts ldi sts ldi out sts sei ldi call ldi sts lds lds jmp t1OVCnt = r25 freqH = r2 freqL = r3 0x00 start OVF1Addr T1OVISR 0xF6 tmp,low(RAMEND) SPL,tmp tmp,high(RAMEND) SPH,tmp DDRD,6 tmp,0 TCCR1B,tmp TCNT1H,tmp TCNT1L,tmp t1OVCnt,0 tmp,0 TCCR1A,tmp tmp,7 TCCR1B,tmp tmp,0x01 TIFR1,tmp TIMSK1,tmp tmp,10 dlyby100msOC tmp,0 TCCR1B,tmp freqL,TCNT1L freqH,TCNT1H again ; r25:r2:r3 holds the frequency ; " ; " ; initialize the SP ; " ; " ; " ; configure PD6 for input (T1 pin) ; ; stop Timer 1 ; force Timer 1 to count from 0 ; " ; initialize TCNT1 overflow count to 0 ; configure Timer 1 to normal mode ; " ; configure Timer 1 to use T1 as its clock ; input and count using T1’s rising edge ; clear the TOV1 flag ; " ; enable Timer 1 overflow interrupt ; enable interrupt globally ; wait for 1 second ; " ; stop Timer 1 ; " ; copy the TCNT1L ; copy the TCNT1H Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 11.7 ■ Using the Timer Normal Mode 383 ; ----------------------------------------------------------------------------------------------------------------------------------------------; Insert dlyby100msOC here ; ----------------------------------------------------------------------------------------------------------------------------------------------; ----------------------------------------------------------------------------------------------------------------------------------------------; The following is the Timer 1 overflow service routine. ; ----------------------------------------------------------------------------------------------------------------------------------------------T1OVISR: inc t1OVCnt reti The C language version of the program is as follows: #include <avr\io.h> #include <avr\interrupt.h> unsigned char tovCnt; unsigned long freq; void delayby100ms(unsigned char cx); void main (void) { tovCnt = 0; DDRD &= ~0x40; // configure T1 for input TCCR1A = 0; // configure Timer 1 to normal mode TCCR1B = 0; // stop Timer 1 TCNT1H = 0; // let Timer 1 to count up from 0 TCNT1L = 0; // " TIFR1 = 1 << TOV1; // clear TOV1 flag TIMSK1 = 1 << TOIE1; // enable TOV1 interrupt TCCR1B = 0x07; // enable Timer 1 to count using T1 input as clock source sei(); // enable interrupt globally delayby100ms(10); // wait for 1 second TCCR1B = 0; // stop Timer 1 freq = (long)tovCnt * 65536 + (long)TCNT1; while(1); } void delayby100ms(unsigned char cx) { TCCR3A = 0; // configure Timer 3 to normal mode with clock source TCCR3B = 0x03; // set to clk_I/O/64 while(cx){ TCNT3 = 40536; // let Timer 3 to count up from 40536 TIFR3 = 1 << TOV3; // clear TOV3 flag while(!(TIFR3 & (1<<TOV3))); // wait until TOV3 is set to 1 cx– –; } } // -------------------------------------------------------------------------------------------------------------------------------------------// Timer 1 overflow interrupt service routine. // -------------------------------------------------------------------------------------------------------------------------------------------ISR (TIMER1_OVF_vect) { tovCnt++; } ▲ Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 384 Chapter 11 ■ Timer Functions of the Mega AVR 11.7.6 Measuring Signal Period Using the Normal Mode The period of a signal can be measured by capturing two consecutive rising or falling edges. The procedure is as follows: Step 1 Configure the timer/counter properly. Step 2 Wait for the first rising edge to arrive. Step 3 Enable timer overflow interrupt and cleared ICV and TOV flags. Initialize timer overflow count to 0. Force timer/counter to count up from 0. Step 4 Wait for the arrival of the second rising edge. The period of the signal is equal to the following expression: Period = timer overflow count × 65536 + captured second edge (11.4) Example 11.7 ▼ Assume that an unknown signal is connected to the ICP1 pin of the Mega2560 MCU and fclk_I/O = 16 MHz. Write an assembly and C program to measure the period of the signal and represent the period in the unit of Timer 1 clock cycles. Solution: The assembly program that measures the signal period is as follows: ; ----------------------------------------------------------------------------------------------------------------------------------------------; This program measures the signal period using ICP1 pin and represents the period ; in the unit of clock cycle. ; ----------------------------------------------------------------------------------------------------------------------------------------------.include <m2560def.inc> .def t1OVCnt = r25 .def perHi = r2 .def perLo = r3 .def tmp = r16 .cseg .org 0x00 jmp start .org OVF1Addr jmp T1OVISR .org 0xF6 start: ldi tmp,low(RAMEND) ; initialize the SP out SPL,tmp ; " ldi tmp,high(RAMEND) ; " out SPH,tmp ; " ldi tmp,0xEF out DDRD,tmp ; configure PD4 for input (ICP1 pin) ldi tmp,0 sts TCCR1A,tmp ; configure Timer 1 to normal mode mov t1Ovcnt,tmp ; initialize Timer 1 overflow count to 0 ldi tmp,1<<ICF1 ; clear ICF1 flag out TIFR1,tmp ; " Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 11.7 ■ Using the Timer Normal Mode 385 ldi tmp,0x42 ; capture rising edge, use clk_I/O/8 as clock source to Timer 1 sts TCCR1B,tmp ; " edge1: in tmp,TIFR1 ; wait until the first rising edge arrives sbrs tmp,ICF1 ; " rjmp edge1 ; " ldi tmp,0 sts TCNT1H,tmp ; force Timer 1 to count up from 0 sts TCNT1L,tmp ; " ldi tmp,0x01 ; enable Timer 1 overflow interrupt sts TIMSK1,tmp ; " ldi tmp,(1<<ICF1)|(1<<TOV1) ; clear ICF1 and TOV1 flags out TIFR1,tmp ; " sei ; enable interrupt globally edge2: in tmp,TIFR1 ; wait until the second rising edge arrives sbrs tmp,ICF1 ; (when ICF1 flag is set to 1) rjmp edge2 ; " lds perLo,ICR1L ; copy the latched timer 1 value lds perHi,ICR1H ; " ldi tmp,0 ; stop Timer 1 sts TCCR1B,tmp ; " here: jmp here ; ; ----------------------------------------------------------------------------------------------------------------------------------------------; The Timer 1 overflow interrupt service routine increment the overflow count by 1. ; ----------------------------------------------------------------------------------------------------------------------------------------------T1OVISR: inc t1OVCnt reti The C language version of the program is as follows: #include <avr\io.h> #include <avr\interrupt.h> unsigned char tovCnt; unsigned long period; void main (void) { tovCnt = 0; TCCR1A = 0; // configure Timer 1 to normal mode DDRD = 0xEF; // configure ICP1 pin for input (PD4) TIFR1 = 0x2F; // clear all flags related to Timer 1 TCCR1B = 0x42; // capture rising edge, use clk_I/O/8 as Timer 1 clock input while(˜(TIFR1 & (1<<ICF1))); // wait for the arrival of the first rising edge TCNT1 = 0; // let Timer 1 to count up from 0 TIFR1 = 0x21; // clear ICF1 and TOV1 flags TIMSK1 = 1; // enable TOV1 interrupt sei(); // enable interrupt globally while(˜(TIFR1 & (1<<ICF1))); // wait for the arrival of the second rising edge TCCR1B = 0; // stop Timer 1 period = (long)tovCnt * 65536 + (long)ICR1; while(1); } // -------------------------------------------------------------------------------------------------------------------------------------------// Timer 1 overflow interrupt service routine. // -------------------------------------------------------------------------------------------------------------------------------------------- Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 386 Chapter 11 ■ Timer Functions of the Mega AVR ISR (TIMER1_OVF_vect) { tovCnt++; } ▲ The pulse width and duty cycle of a signal are measured using a similar method, and hence these are left as exercise problems. 11.8 Using the CTC Mode In the clear timer on compare match (CTC) mode, the counter is cleared to 0 when the Timer/Counter n (TCNTn) counts up to the TOP value (TOP is either the OCRnA register [for all timers] or the ICRn register [for 16-bit timer only]). When the counter counts up to the TOP value, either the OCFnA or ICFn flag is set, depending on whether the OCRnA or ICRn register is selected as the TOP value. An associated interrupt is requested if it is enabled. If the TOP value is set to the MAX value, then the TOVn flag is also set when the timer/counter counts up to the TOP value. The CTC mode is used to create time delay and generate waveforms. 11.8.1 Using the CTC Mode to Create Time Delay To use CTC mode to create time delay, we use either the OCRnA or ICRn register to hold the TOP value of the timer. The procedure in using the CTC mode to create time delay is as follows: Step 1 Calculate the timer count corresponding to the desired time delay. Step 2 Place the calculated timer count in either the OCRnA or the ICRn register. Step 3 Clear the OCFnA (when OCRnA holds the TOP value) or the ICFn flag (when ICRn holds the TOP value). Step 4 Select the appropriate clock source, and enable the timer to count up from 0. Step 5 Wait until the OCFnA or the ICFn flag is set. Example 11.8 ▼ Write a function that uses the CTC mode of Timer/Counter3 to create a time delay that is a multiple of 1 ms, assuming that frequency of the clkI/O clock is 16 MHz. Solution: By setting the Timer 3 clock prescaler to 8, the timer count corresponding to 1 ms is 2000 clock cycles (10-3 × 16 × 106 ÷ 8 = 2000). Place 2000 in ICR3 register, let Timer 3 count up from 0, and wait for the ICF3 flag to be set to 1; a 1-ms delay is created. The following subroutine creates a time delay that is a multiple of 1 ms. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 11.8 ■ 387 Using the CTC Mode ; ----------------------------------------------------------------------------------------------------------------------------------------------; The following subroutine creates a time delay that is a multiple of 1 ms using ; Timer 3 CTC mode. The multiple is passed in register R16. ; ----------------------------------------------------------------------------------------------------------------------------------------------delayby1msCTC: .def tmp1 = r20 ldi tmp1,0x00 ; configure Timer 3 to CTC mode (WGM33:0 = 12) sts TCCR3A,tmp1 ; use the ICR3 register to hold TOP value ldi tmp1,0x1A ; with clock source set to clkI/O /8 sts TCCR3B,tmp1 ; " ldi tmp1,0 ; let Timer 3 count up from 0 sts TCNT3H,tmp1 ; " sts TCNT3L,tmp1 ; " wp1: ldi tmp1,high(2000) ; load 2000 into ICR3 so that Timer 3 sts ICR3H,tmp1 ; overflows in 2000 clock cycles ldi tmp1,low(2000) ; " sts ICR3L,tmp1 ; " nxtLp: ldi tmp1,1 << ICF3 ; clear ICF3 flag sts TIFR3,tmp1 ; " wt1: lds tmp1,TIFR3 ; wait until ICF3 flag is set to 1 sbrs tmp1,ICF3 ; " rjmp wt1 ; " dec r16 brne nxtLp ret The C language version of the function is as follows: void delayby1ms (unsigned char k) { TCCR3A = 0x00; TCCR3B = 0x1A; TCNT3 = 0; ICR3 = 2000; TIFR3 = 1 << ICF3; while(k) { while (!(TIFR3 & 1<< ICF3)); TIFR3 = 1<< ICF3; k– –; } } // configure Timer 3 to CTC mode with clock // set to clk_I/O/8 (WGM3:0 = 12) // TCNT3 counts up from 0 // ICR3 holds the TOP value // clear ICF3 flag // wait for 1 ms // clear ICF3 flag ▲ 11.8.2 Using the CTC Mode to Generate Waveform A periodic square wave with 50% duty cycle is easily generated using the timer CTC mode. To generate a periodic square wave with 50% duty cycle and frequency fW, the TOP value is computed using the following expression: TOP = (fCLK_I/O ÷ Timer prescaler) ÷ (2 × fW) – 1 (11.5) The next example illustrates this application. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 388 Chapter 11 ■ Timer Functions of the Mega AVR Example 11.9 ▼ Write a program to generate a 500 Hz square wave with 50% duty cycle from the OC0A pin, assuming that the fclk_I/O is 16 MHz. Solution: By setting the Timer0 prescaler to 64 and using Equation 11.5, the value to be loaded into the OCR0A register is calculated to be 249. The following assembly program generates the desired waveform: start: again: .include .def .equ .cseg .org jmp .org ldi out ldi out ldi out ldi out ldi out ldi out sts ldi out jmp <m2560def.inc> tmp = r16 NN = 249 0x00 start 0xF6 tmp,low(RAMEND) SPL,tmp r16,high(RAMEND) SPH,tmp tmp,0x80 DDRB,tmp tmp,0x42 TCCR0A,tmp tmp,0x03 TCCR0B,tmp tmp,0x0 TCNT0,tmp TIMSK0,tmp tmp,NN OCR0A,tmp again ; value to be placed in OCR0A register ; initialize the SP ; " ; " ; " ; configure PORTB pin 7 (OC0A pin) for output ; " ; configure the OC0A pin to toggle on compare match ; " ; select CTC mode and set clock source ; to clkI/O/64 ; disable OC0A compare match interrupt ; " ; load NN to OCR0A register ; " ; wait here or perform other operation The C language version of the program is as follows: #include <avr\io.h> #define NN 249 void main (void) { DDRB |= 0x80; TCCR0A = 0x42; TCCR0B = 0x03; TIMSK0 = 0; TCNT0 = 0; OCR0A = NN; while(1); } // value to be placed in OCR0A compare operation // configure the OC0A pin for output // OC0A pin to toggle on compare match // in CTC mode, clock source set to clk_I/O/64 // disable OC0A match interrupt // force TCNT0 to count up from 0 // start the first compare operation // wait for waveform to be generated A square wave with other duty cycle value (≠ 50%) is created in CTC mode by enabling interrupt and changing the TOP value using the interrupt service routine. The next example illustrates the procedure. ▲ Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 11.8 ■ 389 Using the CTC Mode Example 11.10 ▼ Write a program to generate a 1 kHz square wave with 30% duty cycle using Timer 0, assuming that fclk_I/O is 16 MHz. Solution: By setting the TCNT0 clock prescale factor to 64, the frequency of the TCNT0 clock is set to 250 kHz. The period of a 1 kHz square wave is 1 ms. The high interval of a period for the 1 kHz square wave corresponds to 75 clock cycles for the 250 kHz clock input and the low interval correspond to 175 clock cycles. The following assembly program generates the specified 1 kHz square wave: start: again: .include <m2560def.inc> .def tmp = r16 .def HIoLO = r17 .equ hiCnt = 75 .equ loCnt = 175 .equ LO =0 .equ HI =1 .cseg .org 0x00 jmp start .org OC0Aaddr jmp oc0AISR .org 0xF6 ldi tmp,low(RAMEND) out SPL,tmp ldi tmp,high(RAMEND) out SPH,tmp ldi tmp,0x80 out DDRB,tmp ldi tmp,0xC2 out TCCR0A,tmp ldi tmp,0x03 out TCCR0B,tmp ldi tmp,0x83 out TCCR0B,tmp ldi tmp,0x42 out TCCR0A,tmp ldi tmp,0x02 sts TIMSK0,tmp out TIFR0,tmp ldi tmp,0 out TCNT0,tmp ldi tmp,hiCnt out OCR0A,tmp ldi HIoLO,LO sei jmp again ; flag for selecting hiCnt or loCnt ; high interval clock count ; low interval clock count ; TCC0 capture/compare channel 0 interrupt vector ; initialize the SP ; " ; " ; " ; configure PORTB pin 7 (OC0A pin) for output ; " ; OC0A pin to be pulled high when TCNT0 matches OCR0A ; and select CTC mode ; set clock source to clkI/O/64 ; " ; force OC0A ; and pull the OC0A pin high ; OC0A pin toggle on compare match ; " ; enable OC0A compare match interrupt ; " ; clear OCF0A interrupt flag ; let TCNT0 to count up from 0 ; load OCR0A with hiCnt ; " ; next time load loCnt into OCR0A ; enable interrupt globally ; wait for OC0A interrupt Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 390 Chapter 11 ■ Timer Functions of the Mega AVR ; ----------------------------------------------------------------------------------------------------------------------------------------------; The following instruction sequence is the OC0A compare match interrupt service routine. ; ----------------------------------------------------------------------------------------------------------------------------------------------oc0AISR: sbrs HIoLO,0 ; skip if bit 0 is set rjmp setLO ldi tmp,hiCnt ; load OCR0A with hiCnt out OCR0A,tmp ; " ldi HIoLO,LO reti setLO: ldi tmp,loCnt ; load OCR0A with loCnt out OCR0A,tmp ; " ldi HIoLO,HI reti The C language version of the program is as follows: #include <avr\io.h> #include <avr\interrupt.h> #define hiCnt 75 // delay count for high interval in a period #define loCnt 175 // delay count for low interval in a period #define HI 1 #define LO 0 char HIoLO; // flag to select hiCnt or loCnt void main (void) { DDRB |= 0x80; // configure OC0A pin for output TCCR0A = 0xC2; // OC0A pin pull high on compare match TCCR0B = 0x03; // CTC mode, clock source set to clkI/O/64 TCCR0B = 0x83; // force OC0A pin to high TCCR0A = 0x42; // toggle OC0A pin on match in CTC mode TCNT0 = 0; // let TCNT0 count up from 0 OCR0A = hiCnt; // load high interval into OCR0A HIoLO = 0; // next time to load loCnt into OCR0A TIMSK0 = 0x02; // enable OC0A compare match interrupt TIFR0 = 0x02; // clear OCF0A flag sei(); // enable interrupt globally while(1); // wait for interrupt to occur } // -------------------------------------------------------------------------------------------------------------------------------------------// OC0A interrupt service routine. It starts the next compare operation and clears the OCF0A flag. // -------------------------------------------------------------------------------------------------------------------------------------------ISR(TIMER0_COMPA_vect) { if(HIoLO){ OCR0A = hiCnt; HIoLO = LO; } else { OCR0A = loCnt; HIoLO = HI; } } ▲ Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 11.9 ■ 391 Using the Fast PWM Mode 11.9 Using the Fast PWM Mode The fast PWM mode is mainly used to generate a single-slope PWM waveform shown in Figure 11.4a. In the fast PWM mode, the timer counts from BOTTOM to TOP and then restarts from BOTTOM. An 8-bit timer may use 0×FF or the value held in the OCRnA register as its TOP value. However, a 16-bit timer may use 0×00FF, 0×01FF, 0×03FF, the value held in the ICRn register, or the value held in the OCRnA register as its TOP value; where, n = 0, …, 5. The frequency of the fast PWM waveform is given by the following equation: ffastPWM = (fclk_I/O ÷ timer prescaler) ÷ TOP (11.6) 11.9.1 Compare Match Pin Action in Fast PWM Mode TCNTn = 0 TCNTn = OCRnx TCNTn = TOP (a) Non-inverting mode (COMnx1: 0 = 10) TCNTn = OCRnx TCNTn = 0 (b) Inverting mode (COMnx1: 0 = 11) Figure 11.18 ■ n = 0, …, 5 x = A, B, or C Source: Atmel Corporation, The Atmel AVR Microcontroller In the fast PWM mode, we mainly use the compare match pin actions 2 and 3. When the COMnx1:COMnx0 bit field in the TCCRnA register is 10, the fast PWM mode operates in the non-inverting mode. When the COMnx1:COMnx0 bit field in the TCCRnA register is 11, the fast PWM mode operates in the inverting mode. These two modes are shown in Figure 11.18. Fast PWM mode waveforms 11.9.2 Using OCRnA to Hold the TOP Value When using the OCRnA register to hold the timer TOP value, the OCnA pin is not available for generating the PWM output. Only the OCnB and OCnC pins are used to generate PWM waveforms. However, using the OCRnA register to hold the TOP value has an advantage: the generated PWM waveform is always symmetric. The OCRnA register is double-buffered. When a new value is written into the OCRnA register, it is written into the buffer register of OCRnA. The OCRnA register is updated with the value in the buffer one timer clock cycle after the TCNTn matches the TOP value, that is, at the moment when TCNTn is cleared to 0 and the TOVn flag is set. 11.9.3 Using ICRn to Hold the TOP Value The ICRn register is not double-buffered. This means that if ICRn is changed to a value lower than the current TCNTn value, the counter misses the compare match at the TOP value. The counter increments to the MAX value (0×FF or 0×FFFF) and rolls over to 0×0000 before the compare match occurs. Please note that the ICRn register is not available in an 8-bit timer. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 392 Chapter 11 ■ Timer Functions of the Mega AVR Using the ICRn register to hold the TOP value works well when the TOP value is fixed. By using ICRn, the OCRnA register is free to be used for generating a PWM output on the OCnA pin. However, if the base PWM frequency is actively changed (by changing the TOP value), using the OCRnA as TOP is clearly a better choice due to its double-buffered feature. 11.9.4 Extreme Cases for the Fast PWM There are two extreme cases for the fast PWM mode. One case is when the OCRnx register is set equal to the BOTTOM (0×0000). In this case, the output is a narrow spike for every TOP+1 timer clock cycle. Another extreme case is setting the OCRnx equal to TOP, which results in a constant high or low depending on the polarity of the output set by the COMnx1:0 bits. A frequency (with 50% duty cycle) waveform output in fast PWM mode is achieved by setting OCnA (OCnB and OCnC are disconnected from pins in this case) to toggle its logical level on each compare match (COMnA1:0 = 01 in Table 11.3 and Table 11.8). This applies only if the OCRnA register is used to define the TOP value. The waveform generated has a maximum frequency of fOCnA = fclk_I/O/2 when OCRnA is set to 0. Example 11.11 ▼ Write an instruction sequence and a sequence of C statements to generate a PWM waveform with 60% duty cycle using the fast PWM non-inverting mode from OC0A pin, assuming that fclk_I/O is 16 MHz. Set timer clock input prescaler to 8. Solution: We use 255 as the TOP value. The value to be loaded into the OCR0A register is 256 × 60% = 154. The following instruction sequence generates the specified PWM waveform: .def ldi out ldi out ldi out ldi out ldi out tmp = R16 tmp,0x80 DDRB,tmp tmp,0x83 TCCR0A,tmp tmp,0x02 TCCR0B,tmp tmp,0 TCNT0,tmp tmp,154 OCR0A,tmp ; configure PORTB pin 7 (OC0A pin) for output ; " ; Fast PWM mode, clear the OC0A pin on compare match ; set OC0A at BOTTOM ; set clock source to clk_I/O/8 ; " ; force TCNT0 to count up from 0 ; " ; set duty cycle to 60% ; " The following C statements generates the same waveforms: DDRB TCCR0A TCCR0B TCNT0 OCR0A |= 0x80; = 0x83; = 0x02; = 0; = 154; // configure OC0A pin for output // select fast PWM, non-inverting mode // and set clock prescaler to 8 // force TCNT0 to count up from 0 // set duty cycle to 60% ▲ Example 11.12 ▼ Write a sequence of instructions to generate a 2 kHz square waveform with 40% duty cycle from the OC1C pin using the fast PWM mode, assuming that fclk_I/O = 16 MHz. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 11.10 ■ Using the Phase-Correct PWM Mode 393 Solution: There are many ways to generate the specified waveform using the fast PWM mode. One possibility is as follows: • • • • • Select clkI/O /8 as the Timer 1 clock. Select ICR1 to hold the TOP value. The TOP value is (16 MHz ÷ 8) ÷ 2 kHz = 1000. Set compare output mode to 10 (non-inverting mode). Place 600 in the OCR1C register to set duty cycle to 60%. The following instruction generates the specified waveform with the specified settings: .def sbi ldi sts ldi sts ldi sts ldi sts ldi sts sts ldi sts ldi sts tmp = r16 DDRB,7 tmp,high(1000) ICR1H,tmp tmp,low(1000) ICR1L,tmp tmp,high(600) OCR1CH,tmp tmp,low(600) OCR1CL,tmp tmp,0 TCNT1H,tmp TCNT1L,tmp tmp,0x0A TCCR1A,tmp tmp,0x1A TCCR1B,tmp ; configure PB7 pin for (OC1C pin) output ; use ICR1 to hold TOP (1000) ; " ; " ; " ; set duty cycle (OCR1C <- 600) ; " ; " ; " ; let Timer 1 count up from 0 ; select noninverting output compare mode (10) ; " ; select clk_I/O/8 as clock source, fast PWM mode ; using the ICR1 register to hold the TOP value The following C statements generate the same waveform: DDRB ICR1 OCR1C TCNT1 TCCR1A TCCR1B |= 0x80; = 1000; = 600; = 0; = 0x0A; = 0x1A; // configure OC1C pin for output // use ICR1 to hold the TOP value // OCR1C controls the duty cycle // force Timer 1 to count up from 0 // select non-inverting output compare mode // select clk_I/O/8 as clock input, choose fast PWM mode ▲ 11.10 Using the Phase-Correct PWM Mode The phase-correct PWM mode is also meant to generate periodic square wave with specified frequency and duty cycle but is based on a dual-slope operation. The counter counts repeatedly from BOTTOM (0x0000) to TOP and then from TOP to BOTTOM. In non-inverting compare output mode, the output-compare (OCnx) signal is cleared on the compare match between TCNTn and OCRnx while counting up, and set on the compare match while counting down. In inverting output-compare mode, the operation is inverted. The dual-slope operation is illustrated in Figure 11.19. The frequency of the frequency-correct PWM waveform is as follows: fPCPWM = (fclk_I/O ÷ timer prescaler) ÷ (2 × TOP) (11.7) Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. Chapter 11 ■ Timer Functions of the Mega AVR TCNTn == TOP Counting up Counting down Counting up Counting down OCnx OCnx Figure 11.19 ■ TCNTn == OCRnx TCNTn == 0 Inverting output-compare mode TCNTn == OCRnx TCNTn == 0 TCNTn == 0 Non-inverting output-compare mode TCNTn == TOP Source: Atmel Corporation, The Atmel AVR Microcontroller 394 Phase-correct PWM mode, timing diagram 11.10.1 The Choice of the TOP Value An 8-bit timer may use 0×FF or the OCRnA register (n= 0 or 2) as its TOP value whereas a 16-bit timer may set its TOP value to 0×00FF, 0×01FF, 0×03FF, the value in the OCRnA register, or the value in the ICRn register. The timer/counter overflow flag (TOVn) is set each time the timer counts down to the BOTTOM value. When either the OCRnA or ICRn register is used for defining the TOP value, the OCFnA or ICFn flag is set accordingly at the same timer clock cycle as the OCRnx Registers are updated with the double buffer value (when Timer counts up to the TOP value). The interrupt flags are used to generate an interrupt each time the counter reaches the TOP or BOTTOM value. The TOP value must be selected to be higher than any compare register associated with the same timer. If the TOP value is lower than any of the compare registers, a compare match never occurs between the TCNTn and the OCRnx registers. Changing the TOP value frequently while the timer/counter is running in the phase-correct mode could result in an unsymmetrical output. The reason for this can be found in the time of update of the OCRnx Register. Because the update of the OCRnx register occurs at TOP, the PWM period starts and ends at TOP. This implies that the length of the falling slope is determined by the previous TOP value, while the length of the rising slope is determined by the new TOP value. When these two values differ the two slopes of the period differ in length. The difference in length gives the unsymmetrical result on the output. It is recommended to use the phase-and-frequency-correct mode instead of the phasecorrect mode when changing the TOP value while the timer/counter is running. When using a static TOP value there are practically no differences between the two modes of operation. 11.10.2 Pin Action on Compare Match in the Phase-Correct PWM Mode Like any other timer mode, there are four possible compare-match pin actions as shown in Table 11.4 and Table 11.9. Since the frequency-correct PWM mode is provided to generate PWM waveform, only the pin action choice 2 (non-inverting mode) and 3 (inverting mode) should be selected. Example 11.13 ▼ Use the OC0A pin to generate a 40% duty cycle PWM waveform using the phase-correct PWM non-inverting mode, assuming that the frequency of clkI/O is 16 MHz. Set timer clock input prescaler to 8. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 11.10 ■ Using the Phase-Correct PWM Mode 395 Solution: We set the TOP value to 0×FF. The value to be loaded into the OCR0A is 102 (= 256 × 40%). The WGM2:0 bits should be set to 001. The following instruction sequence generates the desired PWM waveform: .def ldi out ldi out ldi out ldi out ldi out tmp = R16 tmp,0x80 DDRB,tmp tmp,0x81 TCCR0A,tmp tmp,0x02 TCCR0B,tmp tmp,102 OCR0A,tmp tmp,0 TCNT0,tmp ; configure the PB7/OC0A pin for output ; " ; configure OC0A to phase-correct PWM, non-inverting mode ; " ; select clk_I/O/8 as the clock source ; to TCNT0 ; set duty cycle to 40% ; " ; force TCNT0 to count up from 0 ; " The following C statements generate the same waveform: DDRB TCCR0A TCCR0B OCR0A TCNT0 |= 0x80; = 0x81; = 0x02; = 102; = 0; // configure OC0A pin for output // configure OC0A to phase-correct, non-inverting PWM mode // select clk_I/O/8 as the clock input to TCNT0 // set duty cycle to 40% // force TCNT0 to count up from 0 ▲ Example 11.14 ▼ Write a sequence of instructions and C statements to generate a 5kHz PWM waveform with 75% duty cycle using the OC1B pin, assuming that the frequency of the clkI/O clock is 16 MHz. Solution: In this problem, we use the following settings to generate the specified waveform: • • • • • • • Select the phase-correct PWM mode to generate the specified waveform. Set clk_I/O as the clock source of Timer 1. Use ICR1 register to hold the TOP value. The TOP value is 16 × 106 ÷ (2 × 5000) = 1600. Place 1200 in OCR1B to set duty cycle to 75%. Set compare output mode to 10 (non-inverting mode). Select phase-correct PWM mode The following instruction sequence generates the specified waveform accordingly: .def ldi out ldi sts ldi sts ldi sts tmp = r20 tmp,0x40 DDRB,tmp tmp,high(1600) ICR1H,tmp tmp,low(1600) ICR1L,tmp tmp,high(1200) OCR1BH,tmp ; configure OC1B/PB6 pin for output ; " ; use ICR1 to hold TOP (1600) ; " ; " ; " ; set duty cycle (OCR1B <- 1200) ; " Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 396 Chapter 11 ldi sts ldi sts sts ldi sts ldi sts ■ Timer Functions of the Mega AVR tmp,low(1200) OCR1BL,tmp tmp,0 TCNT1H,tmp TCNT1L,tmp tmp,0x22 TCCR1A,tmp tmp,0x11 TCCR1B,tmp ; " ; " ; let Timer 1 count up from 0 ; " ; " ; select non-inverting output compare mode (10) ; " ; select clkI/O as clock source, phase-correct PWM mode ; " The following C statements generate the specified waveform: DDRB ICR1 OCR1B TCNT1 TCCR1A TCCR1B |= 0x40; = 1600; = 1200; = 0; = 0x22; = 0x11; // configure OC1B pin for output // use ICR1 register to hold TOP // OCR1B controls the duty cycle // force Timer 1 to count up from 0 // select non-inverting output compare mode // select clk_I/O/ as clock input, choose phase-correct PWM mode ▲ 11.11 Using the Phase and Frequency Correct PWM Mode Like the phase-correct PWM (PCPWM) mode, the phase-and-frequency-correct PWM (PFCPWM) mode is based on a dual-slope operation and is available only in a 16-bit timer. The counter counts repeatedly from BOTTOM to TOP and then from TOP to BOTTOM. In noninverting compare output mode, the output-compare (OCnx) signal is cleared on the compare match between TCNTn and OCRnx while counting up, and set on the compare match while counting down. In inverting compare output mode, the operation is inverted. The frequency of the PWM output of the phase-and-frequency-correct PWM mode is given by the following equation: fPFCPWM = (fCLK_I/O ÷ timer prescaler) ÷ (2 × TOP) (11.8) The difference between the PCPWM and PFCPWM modes are found by examining Table 11.6: • The PCPWM mode has five possible TOP values whereas the PFCPWM mode may have only two possible TOP values. • When both modes use the same TOP value, the PCPWM mode updates its OCRx register when the timer counts up to the TOP value whereas the PFCPWM mode updates its OCRx register when the timer counts down to the BOTTOM value. The timer/counter overflow flag (TOVn) flag is set at the same timer clock cycle as the OCRnx registers are updated with the double buffer value (at BOTTOM). When either the OCRnA or ICRn register is used to define the TOP value, the OCnA or ICFn flag is set when TCNTn has reached the TOP value. The interrupt flag is then used to generate an interrupt each time the counter reaches the TOP or BOTTOM value. When changing the TOP value, the user must make sure that the new TOP value is higher or equal to the value of all of the compare registers. If the TOP value is lower than any of the compare registers, a compare match never occurs between the TCNTn and the OCRnx. The length of the rising and the falling slopes is always equal because the OCRnx registers are updated when the Timer counts down to BOTTOM. This gives symmetric output pulses and is therefore frequency correct. Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s). Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it. 11.12 ■ 397 Driving the DC Motor The procedure of generating the PWM waveform using the PFCPWM mode is identical to the PCPWM mode and hence is left as an exercise problem. 11.12 Driving the DC Motor Mega2560 PA0 OC1A Direction Speed Motor driver chip DC motor On/Off ICP5 Figure 11.20 ■ Source: Atmel Corporation, The Atmel AVR Microcontroller A DC motor is an analog motor and is available in just about any size and is therefore common to many applications, especially those that require a large torque. Because the speed and torque of DC motors are controlled precisely over a wide range, they are used extensively in control systems as positioning devices. The DC motor has a permanent magnetic field, and its armature is a coil. When a voltage is applied to the armature, the motor begins to spin. The applied voltage level determines the speed of rotation. Among the several variations of DC motors, the brushless DC motor is by far the most popular one. Brushless DC motors are commonly used where precise speed control is necessary, for example, computer disk drives, spindles within CD, DVD drives, and mechanisms within office products (such as fans, laser printers, and photocopiers). Modern brushless DC motors range in power from a fraction of a watt to many kilowatts. Larger brushless motors up to about 100-kW ratings are used in electric vehicles. They also find significant use in high-performance electric model aircraft. To provide control to the speed, Hall-effect sensors are often used to provide speed information to the microcontroller that controls the DC motor. The microcontroller digitally controls the angular velocity of a DC motor by monitoring the feedback lines and driving the output lines. Almost every application that uses a DC motor requires it to reverse its direction of rotation or vary its speed. Reversing the direction is done by changing the polarity of the voltage applied to the motor. Changing the speed requires varying the voltage level of the input to the motor, and that means changing the input level to the motor driver. In a digitally controlled system, the analog signal to the driver must come from some form of D/A converter. However, adding a D/A converter to the circuit increases the chip count, which means increasing the system cost and power consumption. The other alternative is to vary the pulse width of a digital signal input to the motor. By varying the pulse width, the average voltage delivered to the motor changes and so does the speed of the motor. The PWM mode of the AVR timer/counter modules can be used to control the DC motor. The AVR MCU interfaces with a DC motor through a driver, as shown in Figure 11.20. This circuit takes up only three I/O pins. The pin that controls the direction can be an ordinary I/O pin but the pin that controls the speed must be a PWM output. The pin that receives the feedback must be an input-capture pin. Simplified DC motor control circuit Although some DC motors operate at 5 V or less, the AVR MCU cannot supply the necessary current to drive a motor directly. The minimum current required by any pract