981 311 4MB
Pages 369 Page size 470.16 x 673.92 pts Year 2010
Programming the Propeller™ with Spin™: A Beginner’s Guide to Parallel Processing
Other Books by Harprit Singh Sandhu An Introduction to Robotics This book, published in 1996, introduces you to robotics and then shows you how to build a weight-shifting, biped, humanoid robot that you can run from a PC. Complete plans are included and all the work can be done with a few tools at the kitchen table. This is the book that laid the foundation for the now abundant humanoid walkingrobot industry. Making PIC Instruments and Controllers This is a hands-on tutorial and resource book that teaches you how to build your own instruments and controllers using PICBasic on PIC microcontrollers. This PIC-based book is aimed at connecting your PIC to real-world measurements and sensors. This 316-page book is laid out in a very clear manner that makes it an excellent reference or textbook. Running Small Motors with PIC Microcontrollers This book is a hands-on tutorial and that teaches you how to run all sorts of small motors with PICBasic and PIC microcontrollers. A hands-on approach is brought to this PIC-based book aimed at running small motors of all sorts with these microcontrollers. Over 2,000 lines of PICBasic code you can use are included. This 352-page book is laid out in a very clear manner that makes it an excellent reference or textbook. Spindles This book is a treatise on working with the small metal-cutting lathe. It concentrates on making spindles that allow you to do simple milling machine work in the lathe, such as cutting gears and making clockworks. Convenience Items Certain items that make experimentation with the Propeller easier are available from Encodergeek.com, which is the support site for this book. Go to this site for book support, more illustrations, prices, and descriptions.
Programming the Propeller™ with Spin™: A Beginner’s Guide to Parallel Processing Harprit Singh Sandhu
New York Chicago San Francisco Lisbon London Madrid Mexico City Milan New Delhi San Juan Seoul Singapore Sydney Toronto
Copyright © 2010 by The McGraw-Hill Companies. All rights reserved. Except as permitted under the United States Copyright Act of 1976, no part of this publication may be reproduced or distributed in any form or by any means, or stored in a database or retrieval system, without the prior written permission of the publisher. ISBN: 978-0-07-171667-3 MHID: 0-07-171667-X The material in this eBook also appears in the print version of this title: ISBN: 978-0-07-171666-6, MHID: 0-07-171666-1. All trademarks are trademarks of their respective owners. Rather than put a trademark symbol after every occurrence of a trademarked name, we use names in an editorial fashion only, and to the benefit of the trademark owner, with no intention of infringement of the trademark. Where such designations appear in this book, they have been printed with initial caps. McGraw-Hill eBooks are available at special quantity discounts to use as premiums and sales promotions, or for use in corporate training programs. To contact a representative please e-mail us at [email protected]. All trademarks or copyrights mentioned herein are the possession of their respective owners and McGraw-Hill makes no claim of ownership by the mention of products that contain these marks. The Propeller and Spin are trademarks of Parallax Inc. Where indicated, the author used images with the permission of Parallax. Information has been obtained by McGraw-Hill from sources believed to be reliable. However, because of the possibility of human or mechanical error by our sources, McGraw-Hill, or others, McGraw-Hill does not guarantee the accuracy, adequacy, or completeness of any information and is not responsible for any errors or omissions or the results obtained from the use of such information. TERMS OF USE This is a copyrighted work and The McGraw-Hill Companies, Inc. (“McGrawHill”) and its licensors reserve all rights in and to the work. Use of this work is subject to these terms. Except as permitted under the Copyright Act of 1976 and the right to store and retrieve one copy of the work, you may not decompile, disassemble, reverse engineer, reproduce, modify, create derivative works based upon, transmit, distribute, disseminate, sell, publish or sublicense the work or any part of it without McGraw-Hill’s prior consent. You may use the work for your own noncommercial and personal use; any other use of the work is strictly prohibited. Your right to use the work may be terminated if you fail to comply with these terms. THE WORK IS PROVIDED “AS IS.” McGRAW-HILL AND ITS LICENSORS MAKE NO GUARANTEES OR WARRANTIES AS TO THE ACCURACY, ADEQUACY OR COMPLETENESS OF OR RESULTS TO BE OBTAINED FROM USING THE WORK, INCLUDING ANY INFORMATION THAT CAN BE ACCESSED THROUGH THE WORK VIA HYPERLINK OR OTHERWISE, AND EXPRESSLY DISCLAIM ANY WARRANTY, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. McGraw-Hill and its licensors do not warrant or guarantee that the functions contained in the work will meet your requirements or that its operation will be uninterrupted or error free. Neither McGraw-Hill nor its licensors shall be liable to you or anyone else for any inaccuracy, error or omission, regardless of cause, in the work or for any damages resulting therefrom. McGraw-Hill has no responsibility for the content of any information accessed through the work. Under no circumstances shall McGraw-Hill and/or its licensors be liable for any indirect, incidental, special, punitive, consequential or similar damages that result from the use of or inability to use the work, even if any of them has been advised of the possibility of such damages. This limitation of liability shall apply to any claim or cause whatsoever whether such claim or cause arises in contract, tort or otherwise.
This effort is dedicated to Robert A. Hoffswell, BA, MA Mathematician, Engineer, Scientist, Gentleman “My first acquaintance from the Age of Information” “Harvey the Fox” is a mathematician who worked as a physicist at the University of Illinois Particle Accelerator Lab. In the very lab where the cyclotron was invented. Where a copy of the original model hung on the wall. He is my first acquaintance from the Information Age. A man who knows how to research and understand things he once knew nothing about and how to use the information to create exquisite, useful, and fully functional devices. He is an Engineer and Scientist of course, but he is also a ham radio operator, a journeyman carpenter, a master woodworker, a maker of musical instruments, like fine guitars, ukuleles, and harpsichords. And exquisite looms and other wonders along the way. I have learned much about learning from the Fox.
This page intentionally left blank
CONTENTS Preface
xiii
PART I The Propeller/Spin System
1
Chapter 1 A General Introduction to the Propeller Chip
3
Introduction for the Beginner 1
The Propeller Manual 3 Parallax, Inc. 5 Overall System Description 5 The Propeller Tool 7 Instruments Needed to Support Your Experiments 8
Chapter 2 The Propeller Chip: An Overall Description
9
Basic Propeller Specifications 10 Voltage and Amperage Requirements 10 The Operation of the Eight Cogs 10 The Cogs 11 The Hub 12 Forty Pins Total, 32 Pins I/O 12 Connecting to the Propeller 13 The System Counter 14 Program Storage and Execution 14 Objects, Methods, and Other Definitions 15
Chapter 3 The Hardware Setup
19
Setting Up the Hardware 21 A Fundamental Reality We Have to Consider 23
Chapter 4 Software Setup: The “Propeller Tool” Environment
25
Classroom Analogy 27 Getting Ready to Use the Propeller 28 Installing the Software 28 Our First Program 29 The Typical Spin Program 32 Program Structure 34 General Pin Assignments Used in the Book 36 Propeller FAQ* 38
Chapter 5 The Various Propeller Memories
43
Assigning Memory for a New Cog 45 A New Cog Can Be Started to Run a Private or Public Method 45 vii
viii Contents
Chapter 6 The How and Why of Shared Memory
47
Memory Usage 48 Variable Validity 49 Loops 50
Chapter 7 Understanding One Cog
51
Static Versus Dynamic 53 One Cog 55 Counters 58 Counter: General Description 59 Assignment of the 32 Bits in Each of the Counters 59 Using Counter A for PWM Generation 60
Chapter 8 The Eight Cogs
65
The Cogs 65 The Flags 66 Special Memory Locations 66 The System Clock 66 Programming 67 The ROM 67
Chapter 9 Special Terms and Ideas
69
The Hardware 69 The Software 70 New Hardware-Related Definitions 70 New Software-Related Definitions 71
Chapter 10 The Spin Language
75
CON 77 VAR 77 OBJ 78 PUB or PRI 78 Creating a Program with Two Cogs 83
Chapter 11 Tasks Suited to Parallel Processing
85
Parallel Programming Examples 85 Summary 87
PART II Input and Output: The Basic Techniques to Be Mastered—Learning by Doing
89
Chapter 12 General Discussion of Input/Output
91
Chapter 13 Binary Pulsing
95
Chapter 14 Setting Up a 16-Character-by-2-Line Liquid Crystal Display
101
Chapter 15 Binary Input and Output: Reading a Switch and Turning on an LED if the Switch Is Closed
109
Discussion 111 The Repeat Command 112
CONTENTS ix
Chapter 16 Reading a Potentiometer: Creating an Input We Can Vary in Real Time
113
Analog Inputs 114 Advanced Techniques 118
Chapter 17 Creating and Reading Frequencies
129
Creating Audible Frequencies 130 Reading Frequencies 135
Chapter 18 Reading and Creating Pulses
139
Reading Pulse Widths 139 Determining the Pulse Width 140 Pulse Width Creation 146
PART III The Projects: Using What Was Learned to Build The Projects
149
Chapter 19 Seven-Segment Displays: Displaying Numbers with Seven-Segment LED Displays
151
Chapter 20 The Metronomes
159
Chapter 21 Understanding a 16-Character-by-2-Line LCD Display
163
8-Bit Mode 164 Sophisticated Total LCD Control 171 4-Bit Mode 182
Chapter 22 Running Motors: A Preliminary Discussion
189
R/C Hobby Servomotors 190 Stepper Motors (Bipolar) 190 Small Brush-Type DC Motors 191 DC Motors with Attached Encoders 191 Relays and Solenoids 191 Small A/C Motors at 120 Volts, Single Phase 192 Understanding the Concept of the “Response Characteristics” of a Motor 192 So What Does “Compliance” Mean? 192 DC Motor Operation Notes 193
Chapter 23 Motor Amplifiers for Small Motors
195
Amplifier Construction Notes (for Homemade Amplifiers) 197 Detailed “Use Information” for the Xavien Two-Axis Amplifier 198 Detailed “Use Information” for the Solarbotics Two-Axis Amplifier 199
Chapter 24 Controlling R/C Hobby Servos
203
Servo Control 204
Chapter 25 Controlling a Small DC Motor The Software 214
211
x Contents
Chapter 26 Running a Stepper Motor: Bipolar, Four-Wire Motors
225
Stepper Motor Power and Speed 226 Details on Bipolar Motors 226 Running the Motor 227 Programming Considerations 229 The Software 231
Chapter 27 Gravity Sensor Based Auto-Leveling Table
247
Sensor Specifications 248 Discussion 248
Chapter 28 Running DC Motors with Attached Incremental Encoders
257
Not about Motors 258 Discussion 258 DC Servo Motors with Encoders 261 Processor Connections 262 The Goal 262 PID Control in Greater Detail 263 Holding the Motor Position 265 Ramping 294 R/C Signal Use 305 Some Advanced Considerations You Should Be Aware Of 312
Chapter 29 Running Small AC Motors: Controlling Inductive Loads
PART IV Appendixes
313
315
Appendix A LCDRoutines4 and Utilities Object Listings
317
Appendix B Materials
327
Appendix C Turning Cogs On and Off
329
Appendix D Experiments Board
331
Appendix E Debugging
335
Debugging and Troubleshooting 335 Dumb Terminal Program 337 Signal Injection Techniques 337 Notes on Solderless Breadboards 338 Debugging at the More Practical Level 339 Writing a Rudimentary Program for Testing the LCD 340 Another List of Simple Checks 341
Epilogue
343
Index
345
Preface After I finished my book Running Small Motors with PIC Microcontrollers, I asked my friend David H. at HVW Technologies in Canada if he had in any ideas as to what might be worth covering in my next book. David suggested that a book about the new Propeller chip from Parallax, written in the same vein as my other hands-on books, could be a welcome effort. With this in mind, I contacted Parallax, Inc., in California and they turned me over to Ms. Stephanie Lindsay, their contact person for authors. Ms. Lindsay was good enough to send me a comprehensive authoring package to get me started on this adventure. In this book I share what I have learned about the Propeller chip and parallel processing with you. It is my wish that by the time you have read through it and have done all the experiments, you will have the confidence, skills, and knowledge necessary to start using the Propeller chip in ways that will make your life both more interesting and, hopefully, more productive. My first reaction to opening the authors’ package and starting on the Propeller manual was, How am I ever going to learn to use this processor? The material was not beginner friendly. Although it was at a higher level, it was very interesting. The further I got into reading and understanding the manual, the more fascinated I became with what the very clever engineers at Parallax had created. It is certainly one of the wonders of the modern world that you can buy eight 32-bit processors and shared memory for less than $8. In this book we will discover what all this, including parallel processing, means to us as engineers, technicians, and hobbyists. As always, I will minimize the use of complicated formulas and jargon so that if you are interested in things mechanical and electronic and have a rudimentary knowledge of what a computer program is, you will be able to use these processors to undertake simple tasks and maybe even some fairly complicated projects in a parallel-processing environment. There are, of course, two aspects to learning how to use the Propeller chip. The first is learning how to use each of the identical 32-bit processors in the chip. Parallax calls each of these eight processors a “cog,” and each of these cogs is similar to a typical 32-bit processor, with some special features added and some left off. The second is learning how to make these eight cogs interact with one another in an effective way to explore the fascinating parallel-processing possibilities that are now suddenly within our reach. Because the eight 32-bit processors on the chip are identical, once you have learned to use one of them, you have learned to use all of them. The intellectual discipline that has to be mastered involves setting up the problem in such a way that the eight processors can be used in the most effective way possible, thus creating a viable solution for the task you have in mind. This has to do with xi
xii Preface
really understanding the problem and with learning how to break a problem down into separate tasks, each of which can be assigned to one of the cogs, in an orderly and logical way. We will learn how to do this. Because not every problem lends itself to a parallel-processing solution, we will spend some time on learning how to identify those problems that can be solved within a parallel-processing environment. This book is intended for the novice user. It is for the novice user for two reasons: One, the material that Parallax provides regarding this chip is more advanced than a first-time user can master with ease. Two, I am also a novice as far as this particular discipline (parallel processing) goes. In this book, I share what I have learned with you, in a straightforward and hopefully nonintimidating manner that you will find useful. We will learn by doing, which is the best way to learn to do anything. Before we can start, though, we have to understand what the system is capable of and how this book is organized to address the tasks at hand. This book is divided into four parts that compartmentalize what we are interested in: ■ The first part of the book introduces you to the Propeller chip, starting with one cog
(the term used by Parallax for each of the eight 32-bit processors in the Propeller chip). First, we learn about just one of the eight processors and how to interact with the I/O provided on the chip. This I/O is in a shared portion of the chip that all the cogs can address. All the features of the one cog are covered in detail. At the end of the first part, you should have a good idea of what the system is all about and be ready to begin using it. ■ In the second part of the book, I cover what you need to know to develop the skills necessary for creating a system that allows the cogs to work together. We will do this by learning how to make the Propeller interact with a number of input and output devices. I have selected the kind of devices an amateur enthusiast, a technician, or an engineer is likely to be interested in interacting with on a day-to-day basis—displays, switches, detectors, motors, and such. The limited memory in the system does not lend itself to the handling of large arrays and related numbercrunching applications, so simple control applications like the ones we will consider are the most suited for investigation by us beginners. The major objective of this part of the book is to learn how to read and create signals of various types. ■ In the third part of the book, we use the lessons we have learned in Part II to build and program a number of devices using the Propeller chip. The device in each experiment is a real-world application of the parallel-processing environment, and each one uses more than one cog. Not all the projects are completed 100 percent, so you have the challenge to complete them. Appropriate information and hints are provided. ■ The fourth part of the book is composed of appendixes that provide you with supplemental information you will find helpful in using the device. This includes the hardware and software resources needed for the experiments we undertake. Where special items are needed, I have made arrangements to provide them on my website at Encodergeek.com.
Preface xiii
A large part of the information you need to help you use this processor can be found on websites maintained by Parallax and others. I recommend that you get familiar with what is in these websites and get comfortable with using the material these websites provide. The discussion forums are extraordinarily useful and should be made a part of your regular reading and learning experience. The following three online resources provide a good starting point as you progress through this book: ■ The Parallax forums. These forums are your most useful resource. ■ Wikipedia provides useful general information. ■ The support web pages provide specific information.
The Propeller chip software is organized such that routines called methods and procedures, created by one person, can be used by others with relative ease. Most of these procedures are well documented, and because all the code is visible, you can modify it to serve your more specific needs should that become necessary. This being the case, becoming familiar with and studying the work done by others is one of the skills you need to develop. I will provide methods with full documentation to support the devices we use so that you can see how these methods are created and then called in subsequent programs. All the experiments in this book can be undertaken with the Propeller Education Kit (32305) provided by Parallax and a minimal amount of additional hardware. Other than the Propeller programming tools provided by Parallax at no charge, consisting of Spin (a high-level language) and PASM (the Propeller Assembly language), no other software is needed. The few extra hardware items needed are listed in Appendix B. The work that we will undertake will be designed around the creation of software for running the type of devices you might use in the design of day-to-day projects on the hobby bench, the engineering laboratory, or the industrial research facility. The devices selected are inexpensive and fit within the constraint of working well with beginners who are just learning how to use the Propeller chip. None are hard to use. As mentioned previously, Parallax provides two languages for programming the Propeller chip. The first language is a high-level language called Spin. The Spin language can be used for almost everything we need to do, except for tasks that need extreme speed and therefore have to be handled with some sort of Assembly language constructs. All the work in this book will be done in the Spin language, with minor calls to Assembly language routines if and when necessary. The goal is to become familiar with the Spin language and to be aware of the capabilities that Assembly language provides. Assembly language routines can be embedded in the Spin language programs with minimal effort. In that this book addresses the needs of beginners, we will not do any programming in the Assembly language PASM. A large part of this book is dedicated to getting an understanding of how the Spin language is used to manage an eight-processor system and its shared memory. A number of simple rules are formulated to allow you to do this from a beginner’s point of view. Starting and stopping cogs and assigning specific tasks to them is covered to
xiv Preface
give you a feel for how you might use these functions. Because there are only eight cogs on the chip, we have to have some discipline regarding how they are to be used. Because each cog is also capable of performing more than one task, as is any “run of the mill” processor, we also need some understanding of when and why more than one task should be assigned to one processor. This, too, is discussed so that you can assign tasks in a more logical manner when you design the hardware and software for your projects. The Spin language does not support an interrupt capability of any description. Having eight processors in a parallel configuration pretty much eliminates the need for interrupts. However, there are still times when you may need to assign some form of more immediate attention to a task, and techniques that can be used to achieve this are demonstrated. Attention is also given to the special features each cog supports. Of advanced interest is the use of the two counters provided in each cog and the interesting ways in which they can be used. The use of these counters is not obvious to the first-time user, especially so if he is a beginner. These counters provide an important and powerful function within each cog, and using them effectively is an important part of using the Propeller chip. Because there is a total of 16 of these counters in the Propeller, they provide a resource we cannot ignore if we are to consider ourselves as being familiar with the Propeller system. Parallax provides detailed information on using these counters, but most of it is beyond the understanding of beginners. We will use a counter to create a PWM signal when we need one; no other use is covered. Part III of the book is devoted to the projects. I have concentrated on controlling the types of things beginners will be interested in. I have covered some of these tasks in other books I have written, and other authors have written a lot about these topics as well. The difference in this resource is that we concentrate on how to undertake these tasks with the Propeller chip and its parallel-processing environment in a way that’s interesting to the beginning programmer. Controlling things also has a lot do with process control, so in a way this book is a simplified introduction to process control in the parallel environment. The one thing that the Propeller chip does not do well is handle large amounts of data simultaneously. Such data crunching requires three basic resources: ■ A fast processor to perform the work quickly. (This we have.) ■ The implementation of a standardized, verified math package in the software to
allow for sophisticated mathematical manipulations. ■ A large amount of memory to store all the data to be crunched. The Propeller chip does not support all three of these capabilities and implementations. This does not mean that we cannot do the day-to-day math we need for our control operations; however, it does means that we are not working with a machine designed for crunching large number arrays. Consequently, there is no discussion of problems that require sophisticated mathematical capabilities in this resource.
Preface xv
Then again, these are not problems that the average beginner is expected to need to address. I have permitted myself a certain amount of repetition from time to time in the various chapters to allow each chapter and each program to stand alone so that you do not have to read the entire book or look back for segments of programs to get the information you need from any one location. Almost all program listings provide complete programs that are ready to run. In this book I use the word “transparent” to mean invisible to us. Something we see right through without knowing it is there. Those aspects of a program’s operation that are invisible are described as being “transparent to the user.” To the beginner, this means that those things that are transparent do not need to be of concern at this stage of the learning process. They happen automatically in the background, and the beginner cannot see or manipulate any aspect of their operation. We can ignore them for now. An example of a transparent operation is the operation of the computer mouse. It does its work without ever making any aspect of its internal workings visible to the user. The information in this resource came from all sorts of sources I was exposed to in my research, and they are not important enough to be documented as footnotes. The most important of them are the Propeller Manual, the Parallax forums, the Propeller object exchange, and the Internet. The experiments and exercises are similar to those I have used in my books on the PIC 16F877A about making instruments and controllers and running motors. These are basic techniques I developed to explain how the various techniques are implemented within a microprocessor. The task we are undertaking does not change, but the techniques used to get the job done do so that we can accommodate the instruction set available for the logic engine being used. The basic hardware you need to get going is the Propeller Education Kit (32305) from Parallax. Arrangements have been made to allow experimenters to get all other hard-to-get items from my Encodergeek.com website, and a list of what you need is provided in Appendix B. The Encodergeek.com site also hosts the support information and updates for the contents of this book. All the programs in the book are provided on the Encodergeek .com website, and you can copy and run them from there if you like. The site also contains a lot of other information of interest to the amateur experimenter. All the software in this book is provided for your use under the terms of the MIT License. It is yours to use as you see fit. Here is a commonly used version of the statement of the license. Terms of Use: MIT License Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
xvi Preface
The software is provided “as is,” without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose, and non-infringement. In no event shall the authors or copyright holders be liable for any claim, damages, or other liability, whether in an action of contract, tort, or otherwise, arising from, out of or in connection with the Software or the use or other dealings in the Software. —Harprit Singh Sandhu Champaign, Illinois USA [email protected]
Part I The Propeller/Spin System
Introduction for the Beginner Before we can start doing things with the Propeller, we need to have an understanding of exactly what we have to work with. Once we understand the Propeller hardware and a bit about the Spin software, we can proceed with our experiments and develop the software needed to execute them.
This page intentionally left blank
1 A General Introduction to the Propeller Chip
Notes A data sheet is now available for the Propeller chip, under the Help section
of the Propeller Tool (Version 1.2.6). If you need specific information about the Propeller, you should refer to the data sheet. The very adequate Propeller Manual (Version 1.1) is suitable for beginners and can be downloaded from the Internet at no charge. Teaching materials are being developed and released by Parallax on a continuing basis. Discussion forums are in place and provide very helpful advice. An extensive Object Exchange is maintained by Parallax on their website. However, all current efforts are aimed at those already fairly comfortable with microprocessor programming. This book provides an information resource for the beginner. It attempts to fill the void with a simple “learn by doing” approach designed specifically for the beginner who knows very little about this chip but has some general familiarity with electronics and with microprocessor programming. Before we start I would like to share a secret with you: Once you learn to use the Propeller in its parallel processing environment, you will be hard pressed to ever again use a conventional processor for the kind of tasks small microcontrollers are designed for. The Propeller system is both incredibly powerful and incredibly easy to use. You will be glad to have learned how to use it.
The Propeller Manual If you need to know more about any of the topics discussed in this book, go to the Propeller Manual for details. The information provided in the manual is not repeated here. This being the case, I strongly recommend you obtain a copy of the Propeller Manual to use as your absolute reference as you study these chapters. A copy of the manual is also available in the Help section of the Propeller Tool. You should have the electronic copy open on your computer when programming the Propeller so that you 3
4 A General Introduction to the Propeller Chip
can perform an electronic search when you need to find something in the manual. You will find that having both a hard copy and an electronic version of the manual is convenient and useful. Before we can start using any device effectively, we need to have some familiarity with the general framework within which the device operates. In our case we need to gain an understanding of how the eight microprocessors (the cogs) on the chip are arranged to interact with the shared memory and the other system resources that tie the eight cogs together. In Part I of the book in general, and in this chapter in particular, we will gain an understanding of these arrangements as we discuss some other general aspects of parallel computing in an introductory format. In 2006, some very clever and gifted engineers at Parallax, Inc., in California, under the leadership of Chip Gracey, introduced “Parallel processing for the rest of us” to the world. This adventure comes to us in the form of a chip that contains eight 32-bit processors with a rather large amount of shared memory. (It is available in a number of formats, including the 40-pin DIP package we are using.) This chip is called the Propeller. Along with the hardware in the form of the chip, the team has provided us with software in the form of two languages suitable for programming the chip. The first language is an object-based language called Spin, with some interesting and useful formatting enhancements. The other language is called Propeller Assembly and consists of a set of assembly language routines that allow fast, more immediate and elemental programming of the Propeller chip. All higher-level programming is done in the Spin language, and all assembly language references can be executed within the Spin framework so that an assembly language program can be started and stopped with just a couple lines of Spin code bracketing the entire assembly language notation. Programs are written with the Propeller Tool (an editing and loading program provided by Parallax). All the software is free for the downloading, from the Internet! All this leaves all the other systems you might consider for the kind of work that microcontrollers do in the dust. So much so that during the Fall of 2009, even Parallax did not fully comprehend what a wonderful logic engine they had created, and for a couple months you could not buy a 40-pin DIP Propeller chip anywhere in the world. Everyone was out of inventory. (The LQFP and QFN versions of the chip remained available.) Together, the hardware and software environments provide us with everything we need to implement small parallel processing scenarios. Because parallel processing is pretty much accepted as the next big step that will have to be undertaken to speed up the computational processes currently being run by fairly fast single-processor linear systems, the ability to play with these eight processors in a well-managed environment is a dream come true for many of us. In this book, I will share this adventure with you and in the process of so doing will introduce you to the techniques and rules that allow you to use the Propeller system with confidence and maybe even some expertise. Parallax has published a detailed data sheet for this chip. It contains all the information required for the kind of processing that needs to be informed of the most intimate details of the insides of the engine. This is not an important resource for beginners, though. The Propeller Manual provided for the Propeller chip covers both languages in detail with more than adequate examples of instruction usage and notation.
Overall System Description 5
Application notes that cover more specialized aspects of the chip’s operation are posted on the Parallax website for downloading at no charge. The discussion forums maintained by Parallax provide additional support that gives you access to everything you need at your level of expertise and understanding. The discussion forums are active, and a number of informed individuals both from within the Parallax organization and outside it post regularly. The range of what people are doing with the Propeller is extensive and impressive, even amazing. I urge you to read these forums regularly and participate in them as often as the need arises. Parallax also provides “live person on the phone” technical support for the Propeller chip at no charge!
Parallax, Inc. Parallax, Inc., is located in Rocklin, California. It is a relatively small corporation that provides microcontrollers, development tools, sensors, and robotics for industrial and educational organizations as well as for hobbyists, with their BASIC Stamp®, PropellerTM, and other related product lines. Parallax can be reached through the mail at the following address: Parallax, Inc. 599 Menlo Drive Rocklin, California 95765 USA Phone numbers are Office: Toll-free sales: Toll-free tech support:
(916) 624-8333 (888) 512-1024 (888) 997-8267
Their website is: http://www.Parallax.com/ The discussion forum for the Propeller chip can be found at: http://forums.Parallax.com And some other resources of interest include: Wikipedia Various independent Internet forums dedicated to Propeller usage
Overall System Description In the most general of terms, the Propeller chip consists of a bank of eight 32-bit RISClike (but not true RISC) microprocessors (called “cogs”) with some shared memory
6 A General Introduction to the Propeller Chip
that also share 32 I/O pins between them. Each of the eight processors can access these 32 I/O pins at all times. The 32 pins are accessed by setting the direction of each pin as either an input or an output (and, of course, the condition of the pin as high or low if it is designated to be an output). In order to coordinate the operation of the eight microprocessors, a hardware device called a “hub” accesses each processor in a round-robin fashion as controlled by the system counter and the system clock. Each cog has access to the system for the same amount of time. The eight cogs are independent of one another and are identical in every detail. The chip provides a bank of memory that can be accessed by each of the cogs when it is the cog’s turn to do so, as determined by the hub. Other ancillary functions such as reset delays and oscillator inputs are also provided. In general, the resources available on the chip can be divided into two families, referred to as the common and the mutually exclusive resources. The common resources, which encompass all the I/O pins and the system counter, are available to all the cogs at all times. This means that any number of cogs can access these simultaneously. The mutually exclusive resources, on the other hand, can only be accessed when it is a cog’s turn to have control of the system. As mentioned previously, the controlling sequence is managed by the processor hub, which gives access to each cog in a round-robin fashion. Doing this in an orderly way allows the system to stay in sync at all times. The system clock is a “programmable speed” device that can be controlled by an internal circuit, a phase-locked loop, and a crystal oscillator, as may be decided on by the system programmer/designer. The system clock itself is a 32-bit counter that is incremented during each cycle of the system oscillator. The system does not keep track of how many times this counter overflows, and the major use of this counter is for timing delays and other time-related functions that do not need to know how often the clock has overflowed. If you need to know how many times the clock counter has overflowed, you have to design a routine that will do that for you as a part of your program. The operation of the system clock is under the control of the clock register. The clock rate is programmable from 20 KHz to 80 MHz. The hub and the bus operate at half the rate of the system clock. (The slower the clock rate and the fewer the cogs in operation, the lower the power the system uses—and the savings can be substantial.) Each of the eight identical cogs has the following resources within it: ■ A 32-bit reduced instruction set (RISC-like) processor ■ 2KB of cog RAM ■ Two input/output assistants with phase lock loops ■ Two powerful counter modules ■ A video generator
A number of special-purpose registers are designated in the RAM to read the system counter, to manage I/O pin direction and states, and to configure the counter modules and video generator hardware. The lock bits are special and are located in their own register in the hub; they are accessible from the lock commands only.
The Propeller Tool 7
The hub allows access to each of the cogs in a round-robin fashion at a clock rate that is half the rate of the system clock. Detailed descriptions of the best- and worst-case scenarios for the interaction of the hub with the cogs, along with timing diagrams, are provided in the Propeller Manual. All 32 I/O pins can be used for I/O when the system is not using pins 28 to 31 for serial interfacing and/or external memory access. Each of the 32 pins can be made into either an input or output. If made into an output, each of the pins can be set either high or low. When designated as an input, the pin assumes a high impedance state and awaits input from the outside. Because each of the cogs can access all the I/O pins at all times, there is a need for an I/O sharing protocol that keeps things under control. You should become familiar with this protocol before designing complicated schemes for accessing the I/O pins with more than one cog. For our immediate purposes, however, this can be ignored. A family of eight lock bits is provided by the system to prevent errors when more than one cog is accessing common resources. Conditions can exist such that one cog is writing to a memory location when another cog is reading from that same location. The system of locks enables you to lock down and release the system while you undertake certain critical read/write operations (on more than one 32-bit long). The chip has 64KB total of shared (main) memory that can be accessed by all the cogs on a mutually exclusive basis, as controlled by the hub. Of this, 32KB is in the form of RAM and 32KB is in the form of ROM. The main RAM is used by the Propeller to store the application we write, along with data, variables, and stack space to perform specified operations. The other half of the main memory, the ROM, contains the font character definitions and the sine and log tables used for writing to display devices and for creating the math functions needed by any application. Main ROM also contains the boot loader, which is used upon startup. The Spin interpreter is also stored here, and it gets copied to each cog RAM, from where it fetches, interprets, and executes Spin code tokens from main RAM.
The Propeller Tool The Propeller Tool is a software-writing environment suitable for creating programs in Spin and Propeller Assembly. It is designed for use on an IBM (or Windows/Intel) compatible personal computer. (The software is not available for the Apple Macintosh at this time.) The Propeller Tool is connected to the Propeller hardware environment most conveniently through a prop plug, an inexpensive USB–to–serial port converter available from Parallax. (If you like, you can make your own converter; a circuit is provided in Propeller Help.) Downloading the programs to the Propeller chip and then executing them is a one-keypress proposition. Parallax provides a special font (called the Parallax font) for writing programs for the Propeller chip. This font is resident in the chip’s main ROM and is to be used in
8 A General Introduction to the Propeller Chip
video displays. It is also included in the Propeller Tool as a TrueType font that is installed on the programmer’s PC and used by the Propeller Tool. The font is divided into two parts: one for writing programs and the other for creating the wiring diagrams needed to document the effort being undertaken. Special features of the software environment allow extensive documentation to be embedded in the program being written at two levels. Each level of the documentation can be suppressed and made visible as needed. Because this can be done at two levels, minimal documentation can be separated from extensive documentation, and either one or both can be suppressed or made visible as needed by a programmer or user. There is no particular point in going over the details of the operation of the Propeller Tool. You should refer to the Propeller Tool’s Help section for these details. At the time of this writing, the current version of the Propeller Tool is version 1.2.6. The Propeller Tool environment is a very powerful and easy-to-use environment that allows you to have any number of programs open at any one time, limited only by the memory you have available in your personal computer. Having multiple programs open at the same time allows cutting and pasting between programs and speeds up the writing and documentation of programs. Among other things, it allows you to jump back and forth between programs with one click and execute the program with another. This, in turn, allows you to make modifications to programs and run either version to see the changes painlessly. Very ingenious, very powerful.
Instruments Needed to Support Your Experiments A good volt-ohm meter (VOM) and an oscilloscope should be available on the workbench at all times. A display instrument we will be using in almost every experiment is the 16-characterby-2-line LCD, but I am not listing it here as a necessity because we are using it as an electronic component onboard the breadboard, as opposed to using it as separate instrument. Having an oscilloscope is really a must, and learning how to use it effectively is a never-ending life-long learning experience. If you don’t have one, get one on eBay as soon as possible. An inexpensive dual-trace 20 MHz scope will be more than adequate for all your needs. An oscilloscope gives you the ability to see things, which is both very powerful and very useful for all investigators. Note A 20 MHz oscilloscope is just fine for much higher frequencies. The problem
with looking at higher frequencies is that they will not be seen as crisp square waves because the scope cannot respond rapidly enough. You will still see the square waves; it’s just that the corners will be rounded a bit. This does not bother what we are interested in. Even a cheap 5 MHz scope is fine. The important thing is to have a scope, and one with dual traces is the scope of choice. This way, you can compare waveforms and see relative timings.
2 The Propeller Chip: An Overall Description
The official identification number of the Propeller chip is P8X32A-D40 for the 40-pin version. The Propeller chip is manufactured by Parallax and is available to the general public in single unit quantities, via the Internet, for $8 each as of this writing. For that small amount of money you get eight 32-bit processors that access a rather adequate 32KB shared RAM and 32 lines of I/O. This is unprecedented power and value for those of us who need to use microprocessors to do our day-to-day work in the engineering office, the university laboratory, the technician’s workbench, or the hobbyist’s workshop. Of course, manufacturers also have a serious interest in this powerful chip, but here we are talking about an introduction for the beginner, so we will not go into what we might do in an industrial environment. Once you understand the basics, moving up to more advanced techniques can be undertaken without difficulty. Figure 2-1 provides the pin designations for the 40-pin DIP version of the Propeller chip. The Spin language uses the inner P designations for accessing the I/O pins. The external pin numbers are not used. (We will not use them either.) In this book, all references to the Propeller Manual are made to the latest version of the manual as revealed by Parallax (Version 1.1). The latest version is the version Figure 2-1 The pin available under the Help menu in the Propeller Tool and designations for the on the Internet, where it can be downloaded at no 40-pin Propeller chip charge.
9
10 The Propeller Chip: An Overall Description
Basic Propeller Specifications Parallax uses bytes (8 bits), words (16 bits), and longs (32 bits) for its memory descriptions. The Propeller chip has the following basic specifications: ■ The Parallax model designation for the chip is P8X32A-D40. ■ It is a 40-pin DIP chip. ■ It runs at 3.3 volts DC (VDC). ■ The chip can be run at from DC to 80 MHz. ■ It contains eight 32-bit processors called “cogs.” ■ Each of the eight cogs has 512 32-bit longs as its own RAM. ■ There are 32KB of RAM and 32KB of ROM accessible to each cog in a round-
robin fashion. (This is hub memory.) ■ It has 32 I/O lines that can be addressed by all the cogs at all times. ■ Each individual I/O line can sink 32 milliamps. ■ Any eight I/O lines can together source a maximum of 100 milliamps at any one
time. ■ A management scheme allows the eight cogs to access all other resources in a
round-robin fashion. ■ Any number of the eight cogs can be on or off at any one time. One cog must remain on to allow the system to stay alive. ■ Cogs can be loaded with new software in real time. ■ Any cog can turn any other cog off and start the next available cog. (They are identical.)
Voltage and Amperage Requirements The current draw of the device varies with the temperature, the operating frequency, and with the number of cogs active at any one time. For general design purposes, a requirement of half an amp at 3.3 VDC can be used for the power supply. More power is used if more cogs are active, and more power is used if more of the I/O is in use. More power is necessary if the processor is being run at higher frequencies because the higher frequencies needed more power to maintain operations. Most of the work done in this book will be done with a 5 MHz external crystal and 2× multiplier for 10 MHz operation.
The Operation of the Eight Cogs The eight cogs in the processor run independently and simultaneously, and are controlled and coordinated by a system counter or clock. From one to eight cogs can be active
The Cogs 11
Figure 2-2 The basic layout of the Propeller system
at any one time. All the cogs have access to all the I/O pins, the system counter, the data bus, and address busses at all times. The various activities within each of the cogs in the system are accessed in an orderly, round-robin fashion as controlled by the hub. The hub does not care how many cogs are running at any one time. It accesses them one at a time in a round-robin fashion. Each hub is accessed for the same amount of time to keep the entire system synchronized with the system counter. When the hub gives a turn to a cog, that cog has exclusive access to the shared resources. The shared resources can be divided into two types of resources: the common resources and the mutually exclusive resources. Each cog has access to the common resources at all times, as mentioned previously, but only one cog, the active cog, has access to the mutually exclusive resources and that’s only when it is its turn to be in charge of the system. All this is transparent to beginners, and we do not need to worry about it right now. (When I use the word “transparent,” I mean that we are not aware of its operation. In other words, we see right through it and are not aware of its presence, like a pane of glass.) The part of the system of immediate interest to us is shown in Figure 2-2. Note that this is a very simplified diagrammatic representation. Refer to the Propeller Manual.
The Cogs As was mentioned previously, there are a total of eight cogs. They are identical in every way except for their identification (as Cog_0 to Cog_7). Cog_0 is the controlling cog, on startup, and as you might expect, at least one cog has to be active at all times. These notes provide you with an introduction to the cogs in a simplified format.
12 The Propeller Chip: An Overall Description
Each of the eight cogs is a fully fledged 32-bit RISC-like processor. The usual interrupt structure and its related functions are not implemented in any form in the Propeller system. They are not needed. Each cog has an independent 2KB of RAM, accessible as 512 32-bit longs. This RAM is used by the cog to store: ■ The Spin Interpreter, copied over from main ROM, if the cog is executing Spin
code ■ Program code copied from main RAM, variables, flags, and data, if the cog is
executing Propeller Assembly ■ Interface locations for other system and peripheral requirements
Certain specific RAM locations in each cog, the special-purpose registers, have been assigned to specific uses to allow interaction with the rest of the system in an orderly manner. These uses are listed in the Propeller Manual.
The Hub The hub is a hardware device that controls how and when each of the cogs will interact with the various parts of the system. It also controls all the resources needed to maintain the integrity of the system. Because certain timing sequences have to be maintained to allow the system to operate properly, these need to be understood by the programmer so that he or she will design programs that comply with these timing and access requirements. For beginners, there are no special requirements that need to be met. Most of the requirements have to do with critical timing, which will have to be addressed when programming in Assembly language and dealing with timing critical tasks. The timing diagrams for these interactions are illustrated and explained in the Propeller Manual.
Forty Pins Total, 32 Pins I/O In this book, we are considering the 40-pin DIP version of the chip. Other, much smaller form factors are also available. Of the 40 pins on the Propeller DIP, 32 are I/O pins. The remaining 8 pins are used for power connections, reset connections, grounding, crystal connection, enabling the system, and other usual and basic housekeeping tasks seen on all microprocessors. All 32 I/O pins can be used for I/O when pins 31 and 32, which are reserved for serial communications to a PC, are not being used for communication. This communication takes place exclusively through pins 31 and 30. Pins 29 and 28 are used for access of external memory when such memory is in use. At other times they can be used for regular I/O connections. Refer back to Figure 2-1 for a pinout diagram of the 40-pin version of the chip.
Connecting to the Propeller 13
Connecting to the Propeller When we are connecting to a low-voltage, low-power device such as the Propeller, our goal is to minimize the load on the pins and to thus protect the device from harmful voltages and currents that might be generated by our experimental circuitry (and our attendant unintentional mistakes). The Propeller chip is designed for extremely low-power applications and runs at 3.3 VDC. Though this voltage is adequate for interaction with transistor-transistor logic (TTL) devices for most applications, it is desirable to put the output signals through standard (7404 or 7414) gates to keep the current requirements at the Propeller to a minimum. Connections through gates will isolate the chip and limit the power backfed into the Propeller if we make a wiring mistake. When we use these gates in our designs, they will most probably be inverting gates, meaning that each gate will invert the signal coming into it. We will have to keep this in mind as we write our programs. The advantage of using these gates/buffers is the increased power they provide for driving any attached loads and the isolation/protection of the Propeller chip. Needless to say, a separate 5-VDC power supply has to be provided for these gates and the circuitry beyond them. The ground connection is common. Noninverting gates (7407s) are available if you prefer to use them, but you will find that for most purposes an inverting arrangement is more convenient. Putting a signal through two inverting gates leaves it unchanged in polarity and is a convenient way of getting a signal buffered but unchanged if you need to do so. Figure 2-3 illustrates the use of an inverting buffer to control an LED.
Figure 2-3 Using an inverting buffer to connect to an LED and a dry contact switch with a pull-up resistor
14 The Propeller Chip: An Overall Description
The System Counter The 32-bit system counter operates at the same rate as the oscillator for the Propeller and is used as the master clock for all timing functions. It provides identical information to all the cogs and can be read simultaneously by all the cogs. Its major purpose is to support the timing of delays and other time-related functions. It does not keep track of the time elapsed or the number of times it has overflowed. If you need that information, you have to create the program functions to do so. All other timing functions can be implemented by observing a time differential based on the counts in the system counter at the two times of interest and knowing the operating frequency of the system—meaning that if we have two readings of the system counter and we know how fast the counter is running, we can calculate a time interval.
Program Storage and Execution In this book, we are talking about Spin code execution. Any code examples discussed will be written in Spin. When we move a program we wrote on the PC, in the Propeller Tool environment, to the Propeller chip, the program is moved either to main RAM in the Propeller or to the external serial EEPROM chip connected to the Propeller. Moving it to main RAM is much faster (with the Fn 10 key), and the RAM location is used for most developmental purposes because of this. If the main RAM option is chosen (Fn 10), the program is lost when the Propeller is turned off. The program will have to be reloaded into the Propeller the next time you need to use the program. Whatever you might have stored or saved in your PC will, of course, still be available for reuse. If, on the other hand, the program is moved to EEPROM (with the Fn 11 key), it will be available even after the Propeller system has been turned off. Downloading to the EEPROM takes much longer than downloading to the main RAM. However, programs in EEPROM are not volatile. When the Propeller system is turned on, it looks for a connection to a PC. If there is no connection to a PC, the current program in the Propeller external EEPROM is read, moved to Propeller main RAM, and executed. Therefore, the rule is, Once the application you have in mind has been finalized, store the program to EEPROM. While you are developing the program, use RAM storage. Spin code is always executed from main RAM, by the Spin Interpreter running in the currently selected cog. The Spin Interpreter is copied from main ROM to Cog 0 at startup, and then to any other cog as it is started by the application to run Spin code later on. Cog_0 (an arbitrary name) can launch other cogs after startup; then after that, any cog that is running can start and stop any other cog, as needed, and even stop itself. The Spin Interpreter running in the cog fetches tokens as needed from main RAM
Objects, Methods, and Other Definitions 15
Figure 2-4 How methods are organized and called in a Spin application
each time that cog has access to the hub and then executes them. Each inactive cog is still assigned its time slot by the hub. This is necessary to keep everything in sync. At least one cog needs to remain active at all times to keep the system alive. All other cogs can be turned on and off by each of the cogs and methods killed and loaded as needed to do the work to be done. Turning a cog off saves power. (Appendix C contains a demonstration program that shows you how to turn a cog on and off). At this stage, we do not need to worry about how the hub operates, what the system clock does, or how other various housekeeping functions are handled. If you need more information on these functions, they are described in detail in the Propeller Manual. For now, we can consider them to be transparent and thus invisible to us. A preliminary look at how a program is organized is provided in Figure 2-4.
Objects, Methods, and Other Definitions Spin defines the components and elements that make up Spin programs as follows. ■ An application is the collection of object files that would be the equivalent to a
single-file “program” in a non-object-based language. An application usually includes a top object file and a number of other objects, but an application can be just a single object. ■ An object is any file with a .spin extension, and it is a chunk of executable Spin code. An object may be designed to accomplish a whole application by itself, or it may be designed to interact with just a specific device and be managed by another object as part of a larger application. An application’s top object is in control when execution begins. This top object may include an OBJ declaration listing the other objects that will be called from the top object as the application is running.
16 The Propeller Chip: An Overall Description
■ A method is the equivalent of a main routine or subroutine in other languages.
Methods are created as Private (PRI) or Public (PUB) entities. Private methods can only be called from within the object they are a part of. Public methods can be called by any other object in the application by declaring the object in the OBJ declarations in the calling application. Methods return a result value automatically, though the result may not be used by the programmer. An object can contain any number of Private and Public methods and can call the Public methods in other objects by referring to their encompassing objects. Called objects have to be in the same folder as the calling object or in the same folder as the Propeller Tool so that they can be found by the calling object. ■ Global variables are defined under the VAR block and have to be defined as bytes (8 bits), words (16 bits), or longs (32 bits) as they are created. ■ Global constants are defined under the CON block and are given names and values as they are created. ■ Local variables are defined on the first line of the method they are used in. They are local to the method and not available outside it. They will be defined as longs. ■ Stack space is memory (in the main RAM) that is needed by each cog to operate within. It is assigned in the VAR block as a number of longs for each cog that will be started. The startup of each cog refers to the stack space assigned to it so that each cog is allocated space without conflict with other cog space. ■ Memory quantities are also defined in terms of bytes, words, and longs. Bits are not used as a unit of memory designation, so a memory bank would be described as consisting of 512 32-bit longs as opposed to 16 kilobits. There are no instructions for manipulating just a bit, although one bit can be manipulated in a more comprehensive instruction. Although we are not yet ready to deal with the Spin language, I’ve listed Program 2-1 to get you thinking about it. This program can be run. Program 2-1 Complete Listing of the Partial Program Shown in Figure 2-4
{{12 Sep 09 Harprit Sandhu BlinkLED.spin Propeller Tool Ver. 1.2.6 Chapter 2 Program 1 This program turns an LED ON and OFF, with a programmable delay It demonstrates the use of methods in an absolutely minimal way. Since the clock is 10 MHz Define the constants we will use. }} CON _CLKMODE=XTAL1 + PLL2X _XINFREQ = 5_000_000
'The system clock spec 'the crystal frequency (continued)
Objects, Methods, and Other Definitions 17
Program 2-1 Complete Listing of the Partial Program Shown in Figure 2-4 (continued)
inv_high inv_low waitPeriod output_pin
=0 =1 =5_000_000 =27
'define the inverted High state 'define the inverted Low state 'about 1/2 sec switch cycle 'line the led is on
'High is defined as 0 and low is defined as a 1 because we are using an 'inverting buffer on the Propeller output PUB Go dira [output_pin]~~ outa [output_pin]~~ repeat turnOff_LED wait turnOn_LED wait
'sets pin to an output line with ~~ 'makes the pin high 'repeat forever, no number after repeat 'method call 'method call 'method call 'method call
PRI turnOn_LED 'method to set the LED line high outa[output_pin] :=inv_high 'line that actually sets the LED high PRI turnOff_LED outa[output_pin] :=inv_low
'method to set the LED line low 'line that actually sets the LED low
PRI wait waitCnt(waitPeriod + cnt)
'delay method 'delay is specified by the waitPeriod
Program 2-1 demonstrates, in the simplest of ways, the creation of three private methods that among them allow the application to turn an LED on and off and to provide a delay between the switching actions.
This page intentionally left blank
3 The Hardware Setup
Note Parallax provides a Propeller Education Kit (#32305) that is suitable for
almost all our experiments and for all the experiments Parallax has created for their more advanced and formal educational programs. Although it is not strictly necessary for us to have one, this kit is the easiest way for us to obtain almost all the components needed for the work we will undertake in one convenient package. Later on you can use this kit to undertake all the exercises provided in the Parallax courseware. Everything in the kit can be used for other purposes. (If you want to get proficient in the use of the Propeller, you will want to study and run all the educational programs provided by Parallax. The related texts are free to download!) We want to start working with the system as soon as possible, and in order to do that we need a hardware/software setup that we can try our hardware and software ideas on. In this chapter, we will set up the system and get it ready for our first experiment. Our setups will be based on the Propeller Education (PE) Kit provided by Parallax whenever feasible. Of course, you do not have to use this kit, but I strongly recommend that you get it. It will simplify the learning process if we are working with the same hardware. This kit does not include the Propeller Manual that you need, but you can download a copy of the manual from the Propeller Tool’s Help menu at no charge. It is included as a PDF file. If you can afford it, you should get a hardcopy version of the manual from Parallax. There is nothing like having the book in your hands, and there is nothing like an electronic copy if you need to search a text file. They complement one another. Because we need to have a standardized setup that we can both work with, we will work with the basic layout exactly as suggested for the PE Kit provided by Parallax. This will allow you to do all the experiments that Parallax provides along with almost all the beginner’s experiments I have designed. All illustrations will reflect this layout, and all wiring diagrams will follow the layout suggested in the kit data. When changes are made to these layouts, they are called out in the descriptions. All the illustrations in this resource are in black and white to keep printing costs to a minimum. Identical illustrations, for most setups, in full color are provided on the support website 19
20 The Hardware Setup
(Encodergeek.com) and should be referred to for greater detail. It is much easier to glean information from a full-color illustration. See Figure 3-1 for a look at what the suggested PE Kit layout looks like. We will be using the 5 MHz crystal that comes with the PE Kit to control the frequency at which the Propeller operates. We will specify the oscillator speed for all our experiments with the following two instructions: _CLKMODE=XTAL1+ PLL2X _XINFREQ = 5_000_000
'The system clock spec multiply factor is 2. 'External oscillator frequency.(Crystal)
With these instructions, the Propeller will operate at 10 MHz. The frequency is very stable with a crystal (most crystals exhibit some drift with temperature and as they age). If we had used the internal RC network to specify the oscillator frequency, the frequency would not have been predictable with such accuracy. (See the Propeller Manual for a further discussion of system speed specification.) Note All Parallax material photographs carry Parallax copyrights and are used by permission.
Courtesy of Parallax Inc. Figure 3-1 Propeller Educational Kit.
Setting Up the Hardware 21
Courtesy of Parallax Inc. Figure 3-2 The Propeller Professional Development Board.
The PE Kit, with a few additions, will be adequate for all the experiments we will be conducting for this book. If, however, you have plans to work with the Propeller system over an extended period of time, an investment in the Propeller Professional Development Board (PPDB) offered by Parallax is worth considering. This flexible board provides a lot of accessories around its perimeter and will save you a lot of time and money over the long haul. I have provided a photograph of the board for your review in Figure 3-2. If, on the other hand, you are a software person and all you want to do is some software experimentation and development and you will not be adding a lot of hardware, the Propeller Demo Board may be the best investment for you. It has the interfaces you need for a keyboard, a monitor, a mouse, and much more. It is ready to use (see Figure 3-3). The Propeller chip itself is available in three form factors. They are illustrated in Figure 3-4.
Setting Up the Hardware Set the PE Kit up exactly as suggested by Parallax. This will allow you to conduct all the more advanced experiments that Parallax offers as a part of their educational program and the more simplified beginner’s experiments we will be undertaking as a part of the beginner’s learning experience in this book. The experiments created by Parallax are more formal and in many ways more suited to a first course about the Propeller at a junior college or a university.
22 The Hardware Setup
Courtesy of Parallax Inc. Figure 3-3 The Propeller Demo Board.
The experiments I have designed are more for the amateur engineer, the technician, or the hobbyist. I will not go into the scientific basis for the experiments, except at the most rudimentary level, so that we can proceed more with the use of what we are creating as opposed to the formal understanding of the science behind what we are creating. (In this I do not mean to set aside the value of the fundamental scientific understanding of all natural phenomena but rather I am committing to keep things simple as suitable for the absolute beginner. I urge you to understand what we are doing in the most fundamental scientific way possible. Many books are devoted to just that.)
Courtesy of Parallax Inc. Figure 3-4 The three Propeller P8X32A form factors.
A Fundamental Reality We Have to Consider 23
A Fundamental Reality We Have to Consider The Propeller chip is designed to be a device that uses very little power. It runs at 3.3 VDC and is designed to operate at lower frequencies that require much less power. These features make the chip very desirable for thousands of portable applications that demand a very low power drain, but it causes some special problems for us experimenters. Among these, the one we need to address first is that a lot of the devices we will be interacting with will be operating not at 3.3 VDC but at 5 VDC and will be using TTL-level logic. The CMOS circuitry in the Propeller will switch the TTL signal without difficulty, but because we have a very limited amount of power available directly from the chip to power all the 32 I/O lines, we have to buffer the outputs from the Propeller to amplify the signals we need. (The high impedance inputs need very little power to switch them high and low, but the outputs will have to be amplified for many of the uses we have in mind.) Buffering the outputs also protects the Propeller in the case of wiring mistakes that may introduce high voltages and currents to the buffered pins. (If we do not buffer the outputs, we will be limited to loading only three or four lines that are not going to high-impedance devices.) Let’s make the reasonable assumption that for most of the experiments we undertake in this book, we will need no more than 24 lines of I/O. Of these, we will need seven lines for the 16-character-by-2-line LCD (liquid crystal display) we use as the display for all our experiments. This leaves 17 bits for other interactions. As a general rule, most applications need two inputs for every output they support, so we will need to set the balance of the 17 bits as 6 bits of output and 11 bits of input. This means we will need to provide one 7404 hex buffer for the 6 output bits. Using three 7404s would allow us to have up to 18 fully loadable outputs. The circuitry within each 7404 is shown symbolically in Figure 3-5. (A buffered line can usually drive about 10 TTL level loads.) The 7404 hex inverter is a 14-pin device, and each one can buffer six lines. The lines are inverted as a part of the buffering process, meaning that a low is turned into a high and a high is output as a low as it goes through the buffer. For our purposes, this can be handled in the software by defining a high as 0 and a low as 1 when the constants are defined at the top of the program. Some of the high load outputs from the Propeller will be routed through a 7404 buffer. We do not need to limit the power needed by each input because the high input impedance of the Propeller inputs requires very little power. We would need a total of three 7404s buffers for all the lines we might need to use as outputs, but in this book we will never need more than one. The lines to the 16×2 LCD we will be using have very high impedances and therefore do Figure 3-5 Pinouts not need to go through buffers. The use of a buffer to for the six inverters in a 7404 IC power and LED is shown in Figure 3-6.
24 The Hardware Setup
Figure 3-6 Using one of the buffers in a 7404 to power an LED.
In my experiments, I used the Propeller chip to turn an LED on and off (directly without a buffer) and through various resistors and then through a 7404 buffer. In doing this, I was experimenting with various conditions under which the Propeller is likely to operate. I found that even with a 1 meg resistor in line with the buffer, the LED switched without difficulty. On the other hand, no resistor is needed to manage the input line currents because the input impedances are so extremely high already. My experiments indicated that any value of 0 to 1 meg ohms would work with the 7404 I was testing. Running mini experiments like this makes you comfortable with the operation of the devices you use every day. You will find that the inputs to the 7404 (and other similar gates) have a very high impedance so that even a direct connection will work, but that we can add a 1 meg resistor in line to make sure the load on the Propeller will be minimal, if by mistake we manage to a create a dangerous voltage at the gate input while we are setting it up. Once we get everything working the way we want it, we can remove the resistors. The program for blinking an LED shown in Figure 3-6 is the first program covered in Chapter 4, which is devoted to the programming environment for the Propeller chip.
4 Software Setup: The “Propeller Tool” Environment
Note In this and all other discussions, it is assumed that you have access to the Propeller Manual.
All the programs in this book are written in the Spin language, and all programming is done in a programming environment called the Propeller Tool. This program is provided free of charge by Parallax and is available for downloading from www .Parallax.com/Propeller. The “Propeller Tool” environment is a full-screen editor that allows Propeller programming in two languages. The first, the Spin language, is a higher-level language that will be used for writing all the programs in this book. The other language is called Propeller Assembly and consists of a comprehensive set of Assembly language instructions. All Assembly language routines must be included as DAT blocks within a Spin language program; they cannot be called as standalone methods or objects. We will not use the Assembly language. Although the Spin language seems daunting at first sight, it is really a fairly easyto-use language that beginners should find easy to learn after a few examples. There is really nothing intimidating about the language. The only difficult part is getting used to the rigid indenting required by the language for the proper formation of programming blocks. (See examples in the Propeller Manual.) This chapter introduces you to this programming environment. Extensive programming examples in the second and third parts of the book provide further examples as you get more familiar with the system. All the programs we develop in this resource are written exclusively in the Spin language. The Spin language is an object-based language. It employs a formatting requirement that makes it a lot easier to use and makes it more powerful than it seems to be at first sight. If you have problems with your first programs, the most probable
25
26 Software Setup: The “Propeller Tool” Environment
cause will be improper indenting. My first reaction to using the system was that it seemed more tedious than it needed to be, but then I realized it was a useful and well-thought-out way of doing what needed to be done. The Propeller Manual provides detailed instructions on how to use the language in the “Propeller Tool” environment and, of course, detailed descriptions for each of the commands. The examples given are often a little bit more sophisticated than what might be understood by an absolute beginner, and in this resource I endeavor to provide simpler examples and skip over the more advanced techniques that you find in the manual itself. My goal is to get you introduced to the system fundamentals. Once you understand the fundamentals, it will be your job to gain the proficiency you need to get your day-to-day work done. The Propeller Manual provides no information on programming. It assumes that you are familiar with standard programming techniques, and as a matter of fact you need to understand standard computer programming techniques fairly well in order to use the Propeller Manual effectively. As we develop the programs in this book, we use simple programming techniques that are easy to understand, even for the absolute beginning user. Keeping in mind that this is a resource for the beginner, we will concentrate on the simpler, more basic techniques that need to be mastered to be able to use the parallel-processing capabilities of the Propeller system effectively. Understanding the parallel-processing environment as implemented within the Spin language is fundamental to understanding how to use this Propeller chip. This is a new hardware environment. The basic concept that you must understand is that no matter how much hardware there is, if the software does not address the hardware features, you cannot use them. And no matter how powerful the software is, if there is no hardware to be addressed by it, the power is useless. Hardware and software must work together, and understanding how the interaction is implemented is the key to understanding how best to use any system. Because parallel processing is new to you and everything we do will be done in the Spin language, understanding the tools offered by the Spin language is critical. We need to understand how the hardware and software support one another to provide a viable environment within this system. Parallel processing needs a number of features that we are not yet familiar with. These features make the parallel-processing process possible. One example we will consider almost immediately is the need to provide a way to send up to eight separate subprograms to the Propeller’s eight cogs within one program. The Spin language provides the tools needed to do this, but we don’t yet understand how to use these tools. (Each cog can undertake more than one task within the subprogram assigned to it.) In order to understand how the Propeller and its parallel-processing environment are to be used, we first need to understand a few basic concepts associated with parallel processing. The concepts themselves are not particularly alien to understanding single-thread linear programming in that each of the eight cogs is pretty much a standard linear program processor with some features added and some other features left out. The new concept that needs to be understood is that the program we write has to have some way of deciding which cog is going to do what and when so that a coherent
Classroom Analogy 27
program that can provide a viable result is created. This need is accommodated within the Spin system by providing the ability to stop and start the cogs, as needed, and passing variables and program segments back and forth between the cogs as they are created. The launching and running of the cogs is under the complete control of the programmer. He or she can start and stop any of the eight cogs as seen fit and assign whatever tasks he or she wants undertaken to each of them. The skill required to make these seemingly simple assignments is what separates the good programmers from the not-so-good programmers. I will endeavor to show you how to do this in a relatively straightforward way in this book. Once you understand the basics, you will build on what you have learned here to develop the sophistication needed to do the work required of you on a day-to-day basis. Not only does the programmer have to assign various tasks to the cogs, he or she has to decide when to turn the cogs on and when to turn them off, which of the results being obtained need to be put into the shared memory so that other cogs can read this information when needed, and what variables are needed only locally. All the special techniques needed to make all this work have to be designed and implemented by the programmer. The system we are considering is very powerful and therefore, as can reasonably be expected, requires more skill to be used effectively.
Classroom Analogy A classroom analogy is one way to envision a parallel-processing system. Imagine a classroom, a blackboard, eight students, and a teacher. The teacher’s job is to assign each student his or her work, to call on one student at a time, and to maintain order. Each student does his or her work in another room, each with its own blackboard, in complete isolation and in silence. Students are invited to come into the classroom one at a time to read whatever is on the blackboard and to write whatever they need to on the blackboard. They read whatever they need to from the blackboard and put other variables, marks, and codes on the blackboard to provide information about the validity of the data they have put on there for the other students. The students use these marks and codes to interact with one another and to pass information back and forth via the blackboard. The following is the case for this scenario: ■ The ■ The ■ The ■ The
teacher is the hub. students are the cogs. main blackboard is the shared memory (the hub memory, main memory). students can write selected variables on the blackboard (the hub memory) and other variables on their own blackboards (cog memory, local variables). ■ The students can secure areas of the blackboard with locks. ■ The students can banish and reinstate other students! (Turning cogs on and off.) There are other aspects to this analogy, of course, but basically that is how it works.
28 Software Setup: The “Propeller Tool” Environment
Getting Ready to Use the Propeller We will use the Propeller Education Kit provided by Parallax, wired up as they suggest for the initial startup, connected to our IBM-PC through a USB port, working in the Propeller Tool environment. The first thing we have to address in order to use the Propeller chip is the fact that this device runs on 3.3 VDC. The devices used in our day-to-day electronics use both 3.3 and 5 VDC. To keep things simple, we will use 5 volt TTL devices in all our experiments. This means that we need a separate power supply for the Propeller and we have to provide an appropriate interface for all connecting devices, whether they feed information to the Propeller or are being fed information by the Propeller. The 3.3 volt requirement for the power to the Propeller chip is a blessing in that it allows us to isolate the power that the chip is using from all the other devices in our project. The easiest way to get the necessary 3.3 volts is to use a suitable regulator fed directly from the 5V power supply we are using for the rest of the project. (This is the way it is done on the Propeller Educational Kit by Parallax.)
Installing the Software The Propeller Tool The programming environment provided by Parallax for writing programs in the Spin and Propeller Assembly languages is called the Propeller Tool (PT). The Propeller Tool is a standalone program that provides an editing environment optimized for programming in the Spin and Propeller Assembly languages. It allows the downloading and running of the programs created (for the Propeller chip) with one keystroke. This software is designed to run on an IBM-PC or equivalent computer and is provided at no charge by Parallax. You can download it from the Internet. Almost all software is updated from time to time, so it behooves us to always use the latest version available. The current version of the Propeller Tool is version 1.2.6. All the programs in this book were written with this version of the software. Even as I type these notes, the tool is being revised to be easier to use and more sophisticated. Download the tool and put it in the folder where you are going to store all your Spin programs. Doing this will make it easier for the software to find your programs when you need to access them for editing and running. The tool provides a text editor and within it a very useful graphics font (it is a subset of the Parallax font) for documenting the circuitry being created. The two share the editing environment and can be used interchangeably within it. An ingenious colorcoding scheme separates the various parts of the program you are writing in a logical way, making it much easier to see what you are doing. The system allows two levels of commentary and documentation to be hidden or made visible as needed. Doing it this way allows both minimal and verbose documentation to be included in the code
Our First Program 29
during development and then suppressed at two levels, as necessary, to see more or less of the documentation on the screen as you develop your programs. You can cut and paste back and forth between Word and the Propeller Tool and the formatting will be preserved. If you prefer you can write your programs in Microsoft Word, but they must be executed from the Propeller Tool screen. (It is easier to use the PT.) The font size needs to be set to 10 (or 12) to allow adequate space for remarks on each line. Set the height to match the font size. Set the tabs accordingly for each section of the Propeller Tool (under the Edit | Preferences menu). All the programs we create will be written with the Propeller Tool, and some of the illustrations and diagrams having to do with the circuitry will be created with the Propeller font graphic facilities provided within the tool environment. Where more complicated circuitry needs to be illustrated, I provide drawings done with AutoCAD. The Propeller font does not adequately support the creation of electronic gates at this time. (Hopefully this is to be remedied in the next version of the chip. The font information is in the ROM on the Propeller chip, so it is an integral part of the chip. A new version of the chip has to be created to modify the font properties.) The Propeller Help Menu item explains the use of the Propeller Tool in profuse detail. No separate compiler is needed. The compiler is available automatically as a part of the Propeller Tool environment and is transparent to the user—you do not see it. When you ask the application to be downloaded to the Propeller chip, the system does so automatically and no interaction is required on the part of the user. Programs can be written in Spin, in the Propeller Assembly resource, or in a mixture of the two, and the compiler sorts everything out automatically. (All Propeller Assembly code must be listed in a DAT block within a Spin object.)
Our First Program Install a 7404 on the education kit board and wire in one LED, as was shown in Figure 3-3 (refer to Chapter 3). Before we get into the intricacies of the Spin language, let’s write a short program that is as simple as we can make it. In this program we are going to blink an LED fed from one line of a 7404 buffer. At the same time, we will vary the resistance in the line feeding the 7404 buffer to determine the value of a suitable “in line” resistance that the circuit will tolerate and still operate reliably. We could calculate this value, but we will instead do it using the trial-and-error method. We know that the 7404 buffer has a high impedance input. This means that it looks like a high resistance device to the Propeller. Even so, we will add more resistance to this line to further Figure 4-1 Circuitry between limit the current drawn from the Propeller (see the output line of the Propeller Figure 4-1). and LED
30 Software Setup: The “Propeller Tool” Environment
Figure 4-2 Photo of Propeller: 7404 and LED
Note Adding this resistance will slow down the operation of the gate ever so slightly, but we may not be able to detect the change with the instruments at our disposal.
The program we are about to consider blinks an LED approximately once a second—a half second on and a half second off—for each complete cycle with the hardware extensions shown in Figure 4-2. We do not have to go through a buffer, but doing it this way limits the current load on the Propeller. Program 4-1 appears in the Parallax font here. This font will be used for all programs developed and listed in this book to differentiate the program listings from the general book verbiage. Program 4-1 Blinking an LED about Once a Second
Re-listed {{12 Sep 09 Harprit Sandhu BlinkLED.spin Propeller Tool Ver. 1.2.6 Chapter 4 Program 1 This program turns an LED ON and OFF, with a programmable delay It demonstrates the use of methods in an absolutely minimal way. The clock is 10 MHz (continued)
Our First Program 31
Program 4-1 Blinking an LED about Once a Second (continued)
Define the constants we will use. }} CON _CLKMODE=XTAL1 + PLL2X _XINFREQ = 5_000_000 inv_high inv_low waitPeriod output_pin
=0 =1 =5_000_000 =27
'The system clock spec 'the crystal frequency 'define the inverted High state 'define the inverted Low state 'about 1/2 sec switch cycle 'line the led is on
'High is defined as 0 and low is defined as a 1 because we are using an 'inverting buffer on the Propeller output PUB Go dira [output_pin]~~ outa [output_pin]~~ repeat turnOff_LED wait turnOn_LED wait
'sets pin to an output line with ~~ 'makes the pin high 'repeat forever, no number after repeat 'method call 'method call 'method call 'method call
PRI turnOn_LED 'method to set the LED line high outa[output_pin] :=inv_high 'line that actually sets the LED high PRI turnOff_LED outa[output_pin] :=inv_low
'method to set the LED line low 'line that actually sets the LED low
PRI wait waitCnt(waitPeriod + cnt)
'delay method 'delay is specified by the waitPeriod
Notes on the First Program Make note of the following items in Program 4-1, starting from the top and moving down: ■ If we do not specify a frequency as such for the system, the crystal frequency is
multiplied by two as specified in the first two lines of the program. ■ We are using a 5 MHz external crystal and a 2× multiplier for a 10 MHz operation. ■ All the constants are defined up front on top of the program. This makes it easy to
make changes to the constants. ■ The direction of the pin being used has to be specified. This is done with the ~~
notation for output and ~ for input in the dira command. ■ We are using a wait period of freq/1000 500 (or 5,000,000) cycles (half a second).
32 Software Setup: The “Propeller Tool” Environment
Methods are used to do the following: ■ Turn the LED on. ■ Turn the LED off. ■ Create the wait period.
(If an LCD is attached, which should not be the case at this time, its contents will not be cleared or affected by this program.)
Running the First Program Once the program has been entered on the computer, and everything is hooked up, we can run the program by pressing the f10 key on the PC keyboard. The program will be transferred to the main RAM of the Propeller and executed. If things are right, the LED on line 27 blinks on a one-second cycle. If the crystal and its specification at the top of the program do not match, the program will not run properly. If things are close, touching the crystal might add enough capacitance to the system to make things work. If the blinking does not start spontaneously, and reliably, things are not right. Before we go any further, we must get this right. Look over the hardware and the software to see what is not right—and then fix it. Keep this program handy for checking the operation of the system whenever you create a new setup and want to make sure it has the potential to work.
The Typical Spin Program A typical Spin program is divided into six main sections or blocks that define the following components in the program: ■ CON Constants are those values that never change in the program. ■ VAR Variables change their values in the program over time. ■ OBJ Calls to other objects (programs) that have methods we are interested in
incorporating into our application. ■ PUB Public routines or methods that can be called from external objects. ■ PRI Private routines or methods that can only be called from within the parent object. ■ DAT Data used in the program. (This is also used in Propeller Assembly programming, but we will not cover that aspect of DAT use in this book.) Each section can have any number of lines of code in it, and each line can be commented as extensively as you like. Two types of multiline comments are supported. Those enclosed in single brackets and those enclosed in double brackets as shown here: {{Comment type 1}} {Comment type 2}
You can also comment each line with a single quote marker.
The Typical Spin Program 33
The Propeller Tool environment lets you list the program under consideration in four formats. The four choices appear on the top menu line of the program listing: ■ Full Source mode lists everything that was typed in as a part of the program. All the
code is listed along with all the comments. ■ Condensed mode lists everything except the comments that are in double brackets: {{ … }}. For us, this means that we should put all the verbose documentation in double brackets. This would include all the general comments as well as detailed descriptions of how the code works. Credits and general licensing comments should be included within double brackets. ■ Summary mode lists the method headings under each of the main sections. ■ Documentation mode lists general information in the double brackets and variable space used by the program. Information like how many variables are used by the program and how long the program is. As your familiarity with the program structures increases, you will settle on your own rules for documenting your programs. In the interim, the following rules will suffice. ■ At the top of the program, use the double brackets to extensively document what the program does in some detail along with author information and relevant dates and revisions. ■ Document each line of code with the (‘) marker comments so that each line is easier to understand. Explain what each line of code is doing. Where necessary, provide verbose documentation for difficult-to-understand lines. ■ Look at all four formats occasionally as your program evolves to see what is being listed under each format and adjust your commenting to make the best use of the formatting features. All the programs I provide will follow these guidelines with double bracketed comments being added to explain the use of particularly difficult-to-understand code segments. I like to do my programming in Full Source mode most of the time and Condensed mode some of the time. The effect of using the preceding rules is reflected in how Program 4-1 is laid out. Subsequent programs will follow these rules. The Propeller Tool allows you to have any number of programs opened at the same time. You can cut and paste freely between the programs as you develop the code for your current program. This can save you a lot of time and allows you to reuse lines of code that you know work in the way they are intended to. The names of all the open programs are listed on the top menu line of the Propeller Tool screen. A detailed description of the Propeller Tool (PT) environment and its effective use is provided under the Help section. The PT software provides a whole host of powerful tools you need to study and become comfortable with. An extensive section consisting of a detailed tutorial on using PT is also provided in the Help section. It covers the special features of the software that aid in more rapid development of software. The Propeller Manual contains detailed descriptions of all the commands in the Spin language and of the Assembly language commands. We will not go over the command descriptions in this book but will cover the use of the more commonly used commands so that you will be comfortable with their use.
34 Software Setup: The “Propeller Tool” Environment
A more extensive use of the commands is developed in the programs in the second and third parts of this book. The programs are devoted exclusively to the development of techniques that do real work in the real world. Once you get comfortable with the general layout of a Spin program, you can start adding more sophisticated and complicated commands to your programs. The basic goal is to get comfortable with the Spin language and how it works. Adding little complications as you get better at programming in Spin is relatively easy once you start writing programs that work.
Program Structure What does a Spin program look like, and where do we put what to make it work right? First, let’s look at a couple diagrams to see what a linear program looks like as compared to a program set up for a parallel environment. Figure 4-3 shows a schematic for a typical linear program. Notice that there is only one main loop. Figure 4-4, on the other hand, shows what the layout for a parallel programming schematic might look like. Notice that a number of independent programs share a common memory bank. The only interaction between the programs is through the shared memory. This is the hallmark of the parallel programming environment provided by the Propeller system. Note Each processor has its own loop, but they all use the shared memory.
The difference is readily apparent, so next let’s look at what a simple Spin program looks like as actual program code. (No parallel processing yet.)
Figure 4-3 Linear program schematic
Figure 4-4 Parallel program schematic
Program Structure 35
Figure 4-5 Code descriptions for the program to blink an LED
Figure 4-5 shows the code for blinking an LED, as was done in Program 4-1 earlier, with comments to explain what goes where within the object. You should also be looking at the entire code for this object (shown earlier) to see what the commenting for each line looks like and states. All objects that use only one cog are expansions of this object. The methods called are part of the object in the same cog. No methods are called from an external object in this example. When stack space has to be assigned for another cog that will execute Spin code, the spaces are declared on top of the program in the VAR section, as shown in Figure 4-6.
Figure 4-6 Assigning space for a new cog
36 Software Setup: The “Propeller Tool” Environment
This figure contains a number of new concepts that need to be explained before you look at the code: ■ Global variables PulsWidth is a global variable defined in the VAR block. It is
available to all the cogs. ■ Local variables Cycle_time and period are local variables that are used within
the MoveMotor method only and are not available to other methods or to other cogs. ■ Parameter passing Pin is a parameter that is passed to the MoveMotor cog when it is started. Figure 4-6 shows where all the variables go for a program that uses two cogs. The main cog in the program does not show any actual code. It just shows how the main program assigns space and then starts a cog to run the MoveMotor method. The space is assigned under VAR as 25 longs at the location Stack.
General Pin Assignments Used in the Book In general, the 40 pins on the Propeller will be given the assignments outlined in Table 4-1. If this scheme is followed, some items can be left attached at all times and others that must be relocated have to be moved only occasionally. The information in this table forewarns you about what pins might be needed for our experiments so that you can assign the pins you want to use accordingly. In this table, I = input and O = output for the data flow directions. Table 4-1 Pin Allocations for the Propeller Chip as Used in This Book
Pin
Usage
Dir
Description
Comment
P0
As needed.
I or O
Encoder when used.
P1
As needed.
I or O
Encoder when used.
P2
As needed.
I or O
Free. Encoder 2.
P3
As needed.
I or O
Free. Encoder 2.
P4
As needed.
I or O
Free. Servo/stepper motor.
)
P5
As needed.
I or O
Free. Servo/stepper motor.
)
P6
As needed.
I or O
Free. Servo/stepper motor.
) Xavien
P7
As needed.
I or O
Free. Servo/stepper motor.
) Amplifier
P8
As needed.
I or O
Free. Servo/stepper motor.
)
P9
As needed.
I or O
Free. Servo/stepper motor.
)
General Pin Assignments Used in the Book 37
Table 4-1 Pin Allocations for the Propeller Chip as Used in This Book (continued)
Pin
Usage
Dir
Description
P10
Free.
I or O
Free.
P11
Free.
I or O
Free.
P12
LCD connection.
O
Dedicated permanently.
P13
LCD connection.
O
Dedicated permanently.
P14
LCD connection.
O
Dedicated permanently.
P15
LCD connection.
O
Dedicated permanently.
P16
LCD connection.
O
Dedicated permanently.
P17
LCD connection.
O
Dedicated permanently.
P18
LCD connection.
O
Dedicated permanently. LED indicator 10.
P19
Potentiometer Sel.
I or O
Dedicated semi-permanently. LED indicator 9.
P20
Potentiometer Clk.
I or O
Dedicated semi-permanently. LED indicator 8.
P21
Potentiometer Dout.
I or O
Dedicated semi-permanently. LED indicator 7.
P22
Potentiometer Din.
I or O
Dedicated semi-permanently. LED indicator 6.
P23
Free.
I or O
Free. Goes through buffer, LED indicator 5.
P24
Free.
I or O
Free. Goes through buffer, LED indicator 4.
P25
Free.
I or O
Free. Goes through buffer, LED indicator 3
P26
Free.
I or O
Free. Goes through buffer, LED indicator 2.
P27
Free.
I or O
Free. Goes through buffer, LED indicator 1.
P28
System usage not to be disturbed by us, but can be used as I/O.
P29
System usage not to be disturbed by us, but can be used as I/O.
P30
System usage not to be disturbed by us, but can be used as I/O.
P31
System usage not to be disturbed by us, but can be used as I/O.
Comment
38 Software Setup: The “Propeller Tool” Environment
The pin allocations were decided upon based on the following considerations. If we agree on these assignments for our experiments, the disruptions between experiments will be minimal and the methods that we develop will be able to be called from third-party programs without worrying about what is connected to what pin for each experimental setup. The need to read an encoder is accommodated by assigning the first two pins as “quadrature encoder information” capture pins. We will use only one encoder later in the book to control a DC motor. It is often the case that two motors are needed to accomplish even simple tasks. We will provide for two encoder inputs up front. Pins P2 and P3 can be assigned to this. If encoders are not connected, the pins can be used for input or output. Input is more appropriate for these pins because no buffering is provided for output loading. The two-axis amplifier we will be using to run the servo and stepper motors later on in Part III of the book needs to be connected to the Propeller with six pins. Pins P4–P9 have been assigned to this usage. If an amplifier is not in use, these pins can also be used for any input or output application. No buffers are provided on any of these lines. The LCD will be connected to the Propeller initially with an 8-bit path for the data and later with a 4-bit path for the data. It needs three lines for data transfer, chip select, and so on, so a total of 11 lines have been assigned to this use. Only lines P12–P18 are needed if four-line LCD control is implemented. When not being used by the LCD, these lines can be employed for any other use. As with the other lines mentioned earlier, no buffering is provided (or needed) on these lines. Lines P19–P22 have been assigned to reading the two potentiometers used often in the experiments to read in data. They can use either the MCP3202 A2D converter to read two lines or the MCP3208 to read eight lines. These lines can be used for other applications when needed. (These chips read a voltage from 0 to 5 volts to a resolution of 12 bits very rapidly.) A 7404 hex buffer will be used to provide buffering for signals that need more power than what’s provided by the bare Propeller lines. Lines P22–P27 can be used as needed, with or without the six buffers provided by the 7404. A more detailed description of the possibilities with a complete wiring diagram is included in Appendix D, along with a comprehensive board design suitable for extensive experimentation. It follows the preceding guidelines and implements the use of connectors and jumpers to make the use of the board as convenient as possible. All the experiments in this book can also be performed on this board, and later on you can use the board for the many experiments you design.
Propeller FAQ* What is special about Cog 0? Not much. It is exactly like all other cogs except that it happens to be the first cog started when the Propeller chip boots up. See the boot-up procedure. So, all applications begin with Cog 0, executing the first method in the top object. After that, the *
Reprinted with permission by Parallax Inc.
Propeller FAQ 39
programmer can determine which cog will execute which portions of the application. All cogs are physically identical. Can Cog 0 be turned off? Yes. Upon startup, Cog 0 is loaded with the Spin Interpreter and starts fetching and executing application code tokens from main RAM. This application code can include a command to start a Spin or Assembly process in another cog with COGNEW or COGINIT and then shut itself down with COGSTOP(0). Cog 0 can be restarted by code running in another cog. Can any cog start or stop any other cog? Yes, by using COGSTOP and specifying the target cog ID. A common strategy when starting another cog is to store its ID for use in a future COGSTOP command when it’s time to stop it. Can a cog shut itself down? Yes. In Spin, any cog can simply use the COGSTOP(COGID) command in a method. In Assembly, it may look something like this (assuming MyID is an available register): Cogid MyID Cogstop MyID
'get our cog id 'terminate this cog
Do I have to indent the lines under PUB or PRI for those lines to be part of the method? No. Indenting the lines that are part of the method just makes it easier to read. Indenting is necessary to define other types of code blocks, such as REPEAT and IF. What do I have to write in my code to indicate the end of a method? Nothing! You do not have to end a method with any specific command or with a blank line. The compiler knows that a method is complete when it finds the beginning of the next block declaration (CON, DAT, OBJ, PRI, PUB, or VAR) or when it reaches the end of the program listing. In sample code listings, you will probably see one or two blank lines between methods just because they are easier to read that way. Can a cog launch an assembly routine into itself? Yes, it can, using COGID to identify itself (if the cog is not known) and COGINIT. If the cog was initially running Spin code, the Spin Interpreter in cog RAM will be overwritten with 496 longs from main memory, starting with the address where the desired assembly routine begins. What do I have to write in my code to indicate the end of an Assembly routine? Most Assembly routines are infinite loops and don’t need any end-of-routine indicator. In the rare case where you need to make an Assembly routine terminate at the end of its operation, you need to instruct it to shut down the cog that is running it. You can do this with the Assembly versions of COGID and COGSTOP. It may look something like this (assuming MyID is an available register): Cogid MyID Cogstop MyID
'get our cog id 'terminate this cog
40 Software Setup: The “Propeller Tool” Environment
If you do not do this, you may run into strange behavior, and here’s why: When an Assembly routine is launched, the cog fills its RAM with 496 longs from the main RAM, beginning at the AsmAddress specified in the COGNEW or COGINIT command. If your routine is less than 496 longs, the cog will also be “slurping up” whatever is in adjacent memory, which could be data, variables, or even another Assembly routine from the same DAT block. If your Assembly routine is not an endless loop, and it does not terminate by identifying its cog and shutting itself down, at the end of the routine the cog will keep going and try to execute this “slurped-up” data. This usually results in undesirable, and sometimes unpredictable, behavior. Since the Propeller has eight cogs, does this mean I can have up to eight object files in my Propeller application? No! There is no direct relationship between objects and cogs. Applications are limited by the size of the Propeller chip’s main RAM, which is 32KB (kilobytes), and not by the number of object files that make up the application. An application may consist of a single object, or many objects, as long as the total size of the application is less than 32KB. An application, whether made from one object or many objects, may execute with one, two, or up to eight cogs, depending only on the collective objects’ “requests” to launch cogs. So how many processes can the Propeller chip handle at once? You can have up to eight processes executing at any one time. This does not limit your application to eight objects, eight Spin methods, or eight assembly routines, just eight processes executing code at the same time. Some processes may need to perform continuously, such as the main program loop or code that is parsing a constant stream of data. Other processes, such as those checking a slow-changing sensor or updating a message displayed on a monitor, may only need to happen once in a while, and when these are done, the cog’s resources can be freed up for another process. Each cog also has two counter modules that can each handle a separate high-speed repetitive process in 32 different operation modes, monitoring or controlling up to two I/O pins each. Where does my application code live on the Propeller chip? The application you write in the Propeller Tool will reside, in its binary form, in the Propeller’s main RAM, not in cog RAM. Spin code is executed by the Spin Interpreter, running in a cog’s RAM, which fetches and executes chunks of code, called tokens, from the PUB and PRI blocks of the application in main RAM. Assembly code is actually loaded from the application in main RAM into cog RAM and executed directly, which is why it is so much faster. How do the cogs run Spin code? What does the Spin Interpreter do? Once the Propeller chip has run its boot-up procedure, the Spin Interpreter stored in the main ROM is copied to Cog 0’s RAM. This Spin Interpreter fetches chunks of the application code, called tokens, from the main RAM. Execution begins with the first method in the application’s top object. Cog 0 fetches one or more tokens, executes the related code, then gets more tokens and continues. Whenever the application launches a new cog with COGNEW SpinMethod or COGINIT SpinMethod, that new cog also
Propeller FAQ 41
gets a copy of the Spin Interpreter in its own cog RAM. The new cog then starts fetching and executing tokens from the application in main RAM too, starting at the point indicated in the SpinMethod argument of the COGNEW or COGINIT command. So, at any given time, there can be up to eight cogs using their own copies of the Spin Interpreter to fetch and execute tokens from the application. How do the cogs run Propeller Assembly code? Once the Propeller chip has run its boot-up procedure, the Spin Interpreter stored in the main ROM is copied to Cog 0’s RAM. This Spin Interpreter fetches chunks of the application code from the main RAM and executes it. When that code is a COGNEW AsmAddress or COGINIT AsmAddress command, the Propeller starts the designated cog, and that cog loads its cog RAM with 496 consecutive longs of data from main RAM, starting at the AsmAddress location. (This overwrites any code or data that may have been in the target cog’s RAM.) The cog then executes the Assembly code directly. Can I launch a new cog from an Assembly routine? Yes, you can, using the Assembly version of COGINIT. You can specify a target cog by ID, or request the next available cog. How long does it take to launch an Assembly routine into a cog? Approximately 512 × 16 × (1/clock speed) seconds. How are Spin methods similar to subroutines in other languages? How are they different? Spin methods are like subroutines in that they contain the instructions to perform a specific process, and can be used over and over again as needed. Unlike subroutines in languages such as BASIC, methods can be passed parameters—that is, a set of temporary values used in the execution of that instance of the subroutine—without having to define variables or constants globally in the program. What’s the difference between global and local variables? Global variables are declared with a VAR declaration and are available for use by all the methods within that object. Local variables are declared in the method declaration and can only be used in the method where they are defined. All variables, whether global or local, exist in main RAM; “local” does not mean the variable exists only in a certain cog’s RAM.
This page intentionally left blank
5 The Various Propeller Memories
Note The programs that the Propeller runs may be stored permanently in an I2C external EEPROM, but not inside the Propeller. If you do not include an EEPROM chip in your design, you will not have a standalone system. The Propeller will have to be loaded with your program every time you want to use it if there is no EEPROM or if there is no program in the EEPROM.
As you can well imagine, it takes more than one memory bank to run a parallel processing system. How does the Propeller system organize its memory banks, and how are they used? What do we have access to and what is the best way to set up our programming strategies? This and other related ideas are introduced in this chapter. We can better understand what we are talking about in this chapter by taking a look at Figure 5-1. Study this figure for a few seconds to get a firm idea of how the overall system is set up before we start talking about it. We need to be aware of a number of memory banks and special memory locations in the Propeller chip so that we can program it in the most efficient way possible and with as few memory-related problems as possible. Most of the memory functions are handled automatically by the nature of the architecture, and we as beginners don’t
Figure 5-1 An overview of the Propeller memory banks 43
44 The Various Propeller Memories
have to worry about what is happening where, or why. However, knowing a little bit about what is going on in the system will help you to be a better programmer. As you read this chapter, keep in mind that all eight cogs are absolutely identical in every way. Upon startup, Cog 0 is started and begins executing the first method in the top object, but after that all cogs are equal. The important thing you need to keep in mind, as you read, is the assigning of memory space for new cogs as they are launched to execute Spin code. This is not overly difficult at your current stage of the learning process—for now we can just over-assign the amount of space needed and things will be okay. Once we get the program running, we can lower the amount of memory assigned to each cog a little bit at a time until the program starts to malfunction. Then we can back off a couple longs and everything will be fine. Once the code is set, you can use an object in the Propeller Tool (PT) for determining stack space needs more accurately. Things get more complicated when you start writing rather long programs (and start turning cogs on and off and keeping track of what is going on in which cog). As far as opening a new cog goes, asking for a new cog is all you need to do because they are all identical, so it does not matter which one starts next. Two KB of dedicated RAM is organized as 512 32-bit longs in each cog, called cog RAM. This is the cog’s own “personal” RAM. This is where the Spin Interpreter is copied to from main RAM (or where Propeller Assembly code is copied to and executed) and for immediate use within the cog for internal calculations and dedicated special-purpose registers and general programming requirements. Only the cog this RAM is in can access this RAM, meaning that the cogs are insulated from each other. The only exception is the ability of one cog to pause or shut down another cog and to specify the program that the new cog is to run. All the cogs share an external 32KB of hub RAM, which is addressable as bytes, words, or longs. For our purposes, the basic use of the shared RAM is to allow the cogs to communicate among one another by sharing access to variables each of them create in this space and to hold the downloaded application. All shared variables are declared in the VAR section of this memory. If you want to share a constant, declare it in VAR and then set it to the value you want to share (from time to time, if it changes). Thirty-two input/output (I/O) pins can be accessed by all eight cogs at all times. The first cog started controls the initial clock frequency. The clock speed–related registers are set in this cog at the top of the main program, along with the constants. These values are used by the main program and all objects and methods that may be called from the main program. Even if a called object sets its own oscillator speed, that speed will be overwritten by the initial frequency specified at startup in the first cog. After startup, any active cog can change the operating frequency. Setting a low clock frequency is an easy way to save energy in portable devices while they are in an inactive or dormant mode. Eight bits are used as locks to prevent memory access conflicts between the various cogs. These global bits are accessed with hub commands and are available to each cog when it has control of the system (during its turn on the hub). The lock bits are defined by the system and are used for multiple cog access control of shared memory. If more than one cog is writing to more than one 4-byte long in the shared memory at one time,
A New Cog Can Be Started to Run a Private or Public Method 45
the possibility exists that an access conflict will occur if the hub transfers control to the next cog in the middle of a transfer—meaning that there is a possibility of reading and writing to the shared memory in a conflicting way. The lock bits allow us to control the read/write interactions and ensure orderly program flow. (See the related discussion in the PT Help section for more information on this. We will not use the lock bits in any of the programs in this book.) The main memory (not the cog memory) consists of a total of 64KB of memory divided between 32KB of RAM and 32KB of ROM. All the cogs share the block of 32KB of main ROM. This ROM contains the Spin Interpreter, the mathematics support tables, the bitmaps for the characters for the Parallax font, and so on. For all practical purposes, we as beginners do not have to worry about this part of the memory at this time—its operation is transparent to us. The interpreter is downloaded into each cog. When it is the cog’s turn, its interpreter fetches tokens from the main RAM and executes them. The 32KB section of shared RAM on the Propeller chip is accessible (shared) by all eight cogs. If a cog needs to bring something to the attention of another cog, the relevant information has to be placed in this area of the memory. If certain flags are needed to alert a cog about a change in memory, it has to be placed in this part of the memory. Any information that has to be shared or accessed by more than one cog has to be placed in the shared RAM under VAR.
Assigning Memory for a New Cog When you want to launch a new cog, you have to make an estimate of how much stack space (in main memory) it will need and then assign an estimated number of longs that represent the operational space for the new cog. At our current level of programming, we can say that five to ten longs are enough for short methods and that 30 to 35 will handle a good-sized method. None of the methods in this book take up more than 50 longs. All the stack space we assign for the various cogs is in main RAM. The memory for a new cog is assigned as shown in Figure 5-2.
A New Cog Can Be Started to Run a Private or Public Method Once you understand the basic information in Figure 5-2, take a look at Figure 5-3, which shows an expanded version of how a new cog is launched and how the various variables play out. For more examples of the opening of cogs, see the program listing in Parts II and III of this book. The programs tend to get progressively more difficult, so it is important to start with the shorter, simpler programs if you are having difficulty understanding the code. It is important to understand exactly what each line of code does before you move on to the more complicated code.
46 The Various Propeller Memories
Figure 5-2 Simple cog launch explanation, with no variables
Figure 5-3 Advanced cog creation explanation, with variables.
6 The How and Why of Shared Memory
The parallel processing environment has some special requirements as regards the memory provided for the system. We can reasonably expect that there will be a need for some shared memory that each of the processors in the parallel environment can access as needed. We can also reasonably expect that there is some memory assigned to each cog that does not need to have any input from any sources outside the cog. That is exactly how the memory is organized within the Propeller system. The main hub memory is shown diagrammatically in Figure 6-1. This is the application memory— the memory that will contain the variables, stacks, data, and code for the program you write. The first half of the memory is RAM, and the last half is ROM.
Figure 6-1 Propeller hub main memory map (from page 31 of Propeller Manual [Ver. 1.1]) 47
48 The How and Why of Shared Memory
Memory Usage The program we write resides in main RAM in the hub. On startup, each cog downloads the interpreter from the main ROM to its RAM. When it is the cog’s turn to access the system, it fetches tokens from its part of main RAM, as was assigned in the stack space for it, and executes these tokens in its memory space. In this way, all the cogs can be executing their part of the code at the same time. All the cogs have access to all the I/O lines at all times. All the variables we declare in the VAR block of the program listing are available to each of the cogs whenever they have access to the shared memory. The variables can be divided into two families as static and dynamic variables.
Static Variables If the selected variable can be considered to be valid at all times or if our interest is in the variable “at the time when we read it” (whenever that may be), the variable can be considered static. This would be true for a variable such as the temperature we were maintaining within a reactor vessel in a chemical plant. It does not particularly matter when exactly we read the variable because we are interested in the current temperature only. No handshake or other confirmations are required for reading variables that meet this requirement.
Dynamic Variables A dynamic variable is a variable that changes from time to time and our interest is in the time history of this variable. We may want to know what the elevation of a rocket was for every millisecond of its assent. For such variables, it is necessary to set some sort of protocol that will make sure each data point was read at the appropriate time. Which cog does what at what time is decided by the programmer, so the storage of the data points is assigned as a critical task to one cog. The data is read by the other cogs as time allows. For data that changes slowly (say, once a minute), we can set up a simple handshake arrangement to transfer the information. The simplest scheme involves using a flag. Cog_one places the data and sets the “data valid” flag. Cog_two reads the data and then clears the “data valid” flag. The first cog waits for the “data valid” flag to be cleared, replaces the data, and resets the “data valid” flag. As soon as the flag is set again, the second cog reads the data again, and so on. Other variables have mixed characteristics and the techniques for reading them are mixtures of what we have discussed previously. If a variable of interest is changing extremely rapidly, the cog creating the data has to store the data in one or two arrays, and the data is read an array at a time (alternating arrays if necessary) as system resources allow time to get the job done. Appropriate flags are created and used as was done with single data points.
Variable Validity 49
Variable Validity The variables that we use have to be created and modified in such a way that they are always current. Let’s look at an example. Suppose we want to read the value of a variable (X) for use in two cogs, where one cog determines X and the other cog displays it. In order for X to be valid at all times, it cannot be used in any calculations of formulas other than the one that sets it, and it has to be set in such a way that it is always valid. Suppose the value of Y was determined as the square of a number plus 1. You cannot write this code as the following: X=2 Y=X^^2 Y=Y+1
Because Y can be either X^^2 or X^^2 + 1 at any one time, we have no way of knowing when a cog is going to read the value because we are not using a “data valid” flag handshake. We have to code this as follows: X=2 X=X^^2 Y=X+1
Then, no matter when another cog reads Y, it will be valid. Although this is a rather trivial programming example, variations of this error will cause you many problems if you are not following the validity rule. As a general practical rule, a shared variable may be set once and only once (in the relevant loop) by the cog that controls it. No other cog may manipulate the value of the variable, meaning that it is to be considered a “read-only” value by all other cogs. This example also explains why more than one cog cannot be allowed to manipulate a variable. Answers using a variable that can be used in intermediate calculations will inevitably be incorrect because there is no way of guaranteeing when the variable will be valid (unless you are using locks). Another common conflict has to do with trying to use lines that are being used to control the LCD for other purposes. Although this can be done, it is best that you not. Keep in mind that the LCD is often called from within other programs. In the other programs we forget that the LCD is actually connected to the Propeller, and if we are constantly updating the LCD it is connected with some very busy lines. These lines cannot be used for any other purposes. This rule also applies to all pins that are dedicated for use by common utilities. Make a list of all the Propeller lines used by your program and by all the methods you are going to call from your program. The lines used in the called methods may not be used for other purposes. Table 4-1 (in Chapter 4) shows how the lines are used in the programs we are developing in this book. You may want to post a copy of that table where you can refer to it as you develop your programs.
50 The How and Why of Shared Memory
Loops Almost every cog sets the parameters (such as I/O line specifications and initial variable values) it needs for its operation and then launches a loop. Loops are used to perform the following tasks, for example, among a myriad of other uses: ■ Update the LCD. ■ Read the potentiometers. ■ Make calculations. ■ Read sensors.
Loops can be called once, any number of times, or forever, depending on the method’s needs. Loops can be nested, and they can perform more than one task. It is the responsibility of the programmer to make sure that the loops do not crash. Special attention has to be given to this because the Propeller does not provide safeguards against division by zero, counter underflows and overflows, register underflows and overflows, and other mathematical transgressions. This means that it may be necessary to provide checks on the ranges of variables and provide clamping within minimum and maximum values. Integer math can be negatively affected by the answer to a calculation when the order of the mathematical operations is picked without thought to register under- and overflows. Although 32-bit numbers are huge, this can still cause problems. Iterations that seem harmless when executed a few times can wreck havoc when executed infinitely. All cogs must also create and manipulate variables in such a way that they are guaranteed to be valid at all times and therefore can be used by other cogs without having to confirm their validity. If you start to get jittery LCD displays or motor operations in the programs we develop later in the book, chances are good some invalid data resides in a loop in one of the cogs. When a cog is started, all its variables are set to zero. This can cause problems in circumstances that depend on the values of variables to be nonzero. For example, the waitcnt instruction is sensitive to this and can be compromised. This situation can be avoided by setting variables to the appropriate values within the cog at the top of the code for the cog.
7 Understanding One Cog
In order to formalize the discussions about the object-oriented Spin language, Parallax has defined some concepts that we need to be familiar with before we proceed. The definitions of these terms, as used by Parallax, first appeared in Chapter 2 and are repeated here: ■ An application is a collection of object files that would be the equivalent of a
single-file “program” in a non-object-based language. An application usually includes a top object file and a number of other objects, but an application can be a single object. ■ An object is any file with a .spin extension, and it is a chunk of executable Spin code. An object may be designed to accomplish a whole application by itself, or it may be designed to interact with just a specific device. It can also be managed by another object as part of a larger application. An application’s top object is where execution begins. This top object may include an OBJ declaration listing the other objects that will be called from the top object as the application is running. ■ A method is the equivalent of a main routine or subroutine in other languages. Methods are created as private (PRI) or public (PUB) entities. Private methods can only be called from within the object they are a part of. Public methods can be called from any other object in the application by declaring the object in the OBJ declarations in the calling application. Methods return a result value automatically, although the result may not be used by the programmer. ■ An object can contain any number of private and public methods and can call the public methods in other objects by referring to their encompassing objects. Called objects have to be in the same folder as the calling object or in the same folder as the Propeller Tool so that they can be found by the calling object. ■ Global variables are defined under the VAR block and have to be defined as bytes (8 bits), words (16 bits), or longs (32 bits) as they are created.
51
52 Understanding One Cog
■ Global constants are defined under the CON block and are given names and values
as they are created. ■ Local variables are defined on the first line of the method they are used in. They
are local to the method and are not available outside it. They will be defined as longs. Before we start talking about cogs, we need to keep a thing or two about a Spin program in mind. A Spin program contains the source code for each of the to-be active cogs within it. On startup, the initial cog assigns the code to the various other cogs, as specified. Once the program starts, the individual cogs are autonomous and can turn each other on and off. There are no interrupts in the Spin system, so cogs are assigned various, what would normally be, interrupt-driven tasks. A cog can undertake either one or more than one task, depending on how rapidly the tasks need to be completed. Because there are no interrupts in Spin, all the programming in a cog is linear. Parallel processing is the holy grail of the computer industry, and the Propeller chip provides an exciting opportunity for us amateurs to investigate the possibilities. Although it is, of course, possible to do everything with a single processor, it is a lot easier if you have a number of processors available to do the work in a parallel environment. Each of the eight processors in the Propeller is capable of acting like the usual single-processor microcomputer and can undertake all the tasks you would expect a microcontroller to be able to execute. (Again, interrupts are not provided in the Propeller system, meaning that we cannot stop in the middle of a task and take care of something critical that comes up. Everything has to wait its turn.) The more pressing problem we face in small systems such as the Propeller is the constraint imposed by the limited amount of memory provided with each cog. It inhibits the handling of large amounts of data and the inclusion of standardized math/trig/log packages. A Propeller has an external EEPROM attached to it that provides memory for program storage. It does not provide random access to the external memory’s contents, however. This limitation is imposed by the fact that most serial one-wire memories have to be read in a way that inhibits their use as random-access devices. Usually you have to read everything from the beginning to a specific memory location, and that is not very handy except for program storage and databases that may be read in “all at one time.” There are two ways of organizing a parallel processing instruction set that executes a program: ■ Write one master program that is intelligent enough to sort out the needs of the
overall process and then assign as many cogs as are necessary to the various tasks that have to be undertaken automatically. At this time, the software (meaning the sophistication) to do this does not exist within the Propeller/Spin system. ■ Let a human programmer take a close look at the program requirements and decide what each of the cogs will be assigned to do. This is the way we will undertake our tasks because this is what the Spin language is designed to do. This means that we have to have a good understanding of exactly what needs to be done to solve the
Static Versus Dynamic 53
problem under consideration. Although this may seem trivial at first, it is a relatively sophisticated undertaking complicated by the fact that the solution is not unique. When there are many ways to solve a problem and the best way is not always apparent, things can get complicated. It takes a long time and lots of experience to get good at solving problems in a parallel environment. You have to develop a certain amount of “expertise.” Even so, we will come up with some basic guidelines about how to proceed as we learn more about the cogs and how to use them in their parallel environment.
Static Versus Dynamic Basically, the types of tasks we are interested in can be divided into two major categories: those tasks that do not change as we process the data and those that do. According to the classifications I will define, tasks involving data that does not change are classified as static tasks and those handling data that changes in real time are classified as dynamic.
Static Systems A large number of tasks handle large amounts of data that either does not change or changes only marginally over short periods of time. An example of such a task would be a list of customers an insurance company maintains. We may need to sort this list from time to time, in any number of different ways, to get information about its contents for our current needs, but there is no need to respond to something critical in real time. For example, we might be looking for everyone over 90 years of age to send them a wellness greeting, and if we can send the information out by the end of the day it will in most probability be okay. Here are some other examples of static systems: ■ Mailing lists ■ Census data ■ Payrolls ■ Calendars
In general, these databases do not change over short periods of time and their basic use involves the data itself rather than something dynamic that is happening within the system. You may be interested in the demographics of the U.S. population in 1873 and there is not much that is going to change within the database that represents that population in the next few days (other than newly discovered historical data that may be added from time to time). Handling static tasks requires speed but not necessarily parallel processing, although we had agreed earlier that almost every task could be done faster in a parallel environment. Even speed is not paramount in that a large mailing list can be sorted overnight, and for most purposes that would be acceptable.
54 Understanding One Cog
Parallel processing is not particularly well suited to handling such static systems, although as time goes on, and massively parallel systems become available in both hardware and software, parallel engines will be used to handle the kind of databases we have been discussing.
Dynamic Systems On the other hand, a number of other systems contain information that is changing constantly, and in many cases we need to read and manage the various properties of such a system in real time so that we can control the system to get the results we have specified. Almost every industrial control situation is a dynamic system with more than one variable. By definition, in any dynamic system things change constantly. One aspect of interacting with a dynamic system is looking at (reading) the variables that are changing. We are interested in these variables because they define the operation of the system. In most cases, the data of interest is represented by the many displays on the control panels that manage what is going on in the system. These displays are designed for human observation and response. In most cases, the management of the system itself is undertaken by some type of automatic mechanism executing a complicated algorithm. Each control loop has its own feedback system and has to be managed by some sort of machine intelligence. Today, this intelligence is provided by computers, both small and large. Such systems are particularly well suited for management by parallel systems where any number of variables may affect one outcome. Complex formulas, fuzzy logic, and machine intelligence play their role in controlling these systems. (In the old days, complicated systems were handled by experienced operators who had long-term experience with the systems. The operators were accepted as being experts in their fields.) An example of a simple dynamic control system is a domestic hot water heater. The controller turns the heat on at a certain temperature and turns it off at a higher temperature. If the temperature gets too high, another control might override the heat input or a relief valve might be used to release the built-up energy in a safe way. We do not need a sophisticated control system here. The available systems are reliable, durable, and safe, and the system response is fairly slow. On the other hand, an automated baking line in a modern bakery needs a very sophisticated control system, which has to be manipulated constantly to get the perfect cookies we expect on our grocery shelves. Machine intelligence and fuzzy logic have application here. The inputs of such a system include the following: ■ The temperature in the oven ■ The speed of the conveyors in the oven ■ The temperature history for the last hour along the long linear oven ■ The ambient external temperature ■ The humidity at the oven door ■ The color and variety of the flour being used and the year the grain was harvested in ■ The color of the finished product, top and bottom ■ The results of the last batch ■ Conditions halfway down the baking oven
One Cog 55
In most of the situations we would consider, most of the parameters would affect one another. They would be described as being interactive. Some would provide positive feedback, and some negative. In such situations, the management of the controlling functions can get quite complicated. Parallel processing is exquisitely suited to such control situations. Of course, as beginners we are not about to start programming the system for a modern factory with 2,500 interactive feedback loops, but the simple systems we will be looking at do represent the kind of situations we can expect to see in our workplaces on a regular basis. Understating these simple systems will prepare us to understand more complicated systems down the road.
Another, Simpler Example The running of a stepper motor represents a simple-but-difficult-to-manage system that needs constant attention in real time if we are to attain and maintain the high speeds that are often needed. The problem is especially interesting because there is nothing about the system that we do not understand, meaning that we know exactly what has to be done. The question is, how do we get it done? The running of a bipolar stepper motor is covered in detail in Part III of this book. In most of the applications we have in mind for our simple parallel systems, we need to display, read, set, and manipulate any number of variables. We will assign the cogs to tasks such as the following: ■ Managing the LCD display ■ Reading one or two potentiometers for input ■ Making simple calculations and comparisons ■ Reading information from various system components ■ Setting high and low limits for the controllers ■ Reading a keyboard ■ Communicating with a computer ■ Managing and annunciating alarms
As a general rule, in our experiments we will always use the LCD both to show us what is going within the system and to display the results of our efforts. We always read one or two potentiometers to provide the input variables we need. We will use one cog just to manage the device we are experimenting with, and other cogs will be added as needed.
One Cog The preceding being the case, we need a solid understanding of what each cog is capable of doing. The eight cogs are identical in every way, and if we understand one cog, we will understand them all.
56 Understanding One Cog
Each cog has the following exclusive and common (shared) memory resources available to it: ■ Two kilobytes of RAM organized as 512 32-bit longs ■ Access to 32KB of common RAM, addressable as bytes, words, or longs ■ Access to 32KB of common ROM ■ Access to clocks, locks, and other devices that make the system work ■ Access to a system counter
Individually, each of the cogs in turn has the following capabilities: ■ Counter A ■ Counter B
The counters can each execute a task independent of all other processes. A total of 16 counters are available for this. (Two each in eight cogs.) ■ A video generator
Other features include the following: ■ Mutual access to certain memories ■ Exclusive access to certain memories ■ Access to the 32 I/O lines by all the cogs at all times ■ Settable oscillator/clock speeds ■ I/O output register ■ I/O direction register
I/O input register can be read to determine the current state of all I/O pins. The external I2C EEPROM mentioned in the first paragraph of the previous chapter is not available to individual cogs. It downloads into hub memory (the main memory), and only at startup. This happens only if no PC is attached to the Propeller. If a PC is present, the system looks to the PC to receive its program. When downloading a program from a PC to the Propeller system, you have the choice of downloading the program to the attached external EEPROM or to the onchip main hub RAM in the system. The program and subprograms you create are targeted to available cogs, one after another. Because all cogs are identical, it does not matter what code is assigned to which cog. The programs in the various cogs can interact with one another via the shared memory. The system is completely flexible— which unfortunately means there are a lot of ways to get it wrong. It takes a formal and disciplined approach to get everything right. In this book, we will develop some of the techniques needed to assign cogs their responsibilities in an orderly way.
One Cog 57
The system will operate as follows for the programs we will write: The first cog will control the system on initial startup. It runs the initial program and assigns the execution of the various subprograms (that are part of the main program) to the other cogs as specified in the main program. The Spin Interpreter is copied from main ROM to cog RAM for each cog that will execute Spin code. The hub assigns system control to each cog, in a round-robin fashion. At this stage, we do not need to understand the details of how all this happens, but we do need to understand that this overall process exists. ■ Once the system is up and running, all the cogs are equal and any one of them can stop or start any other cog and assign it a program to run. All cogs can modify the clock speed. They are equal in every way. The Propeller Tool allows you to write programs on a PC and move them to and execute them on a Propeller chip with one keystroke. Using the tool is easy and intuitive. The difficult part is learning to use the Spin language. The Propeller can also be programmed in the Assembly language (Propeller Assembly) provided by Parallax and described in the Propeller Manual, but we will not cover that language in this book. (In addition, third-party C compilers are available for the Propeller chip, but using them is outside the scope of this book.) Everything can be done in Spin except tasks that require extreme speed. The use of the Propeller screen is discussed in detail in the Propeller Manual (see Figure 7-1). It is well worth doing all the exercises provided therein.
Figure 7-1 The Propeller Tool screen layout
58 Understanding One Cog
Counters Note Counter modules (sometimes referred to in this text as “counters”) are an advanced subject not suitable for beginners. We are going to need to generate a pulse width modulated (PWM) signal for many of our experiments, so we need to talk about just this one application of a counter in a very cursory manner. Do not worry if you do not understand this in every detail just yet.
Each cog contains two identical, independent counter modules that can be configured to perform a variety of tasks—some independent and some cooperatively with the cog. These counter modules are typically referred to as Counter A and Counter B, and on startup they are both disabled (off). Because the counter modules are capable of operating independent of the cog, they have no effect on the cog’s execution speed. Although each counter module has 32 different modes of operation and a myriad of applications, in this beginner’s book we will only discuss one use of these counter modules: pulse generation. It is important to emphasize that the operation of the counters can be independent of the operation of the cog once they have been set up. The cog can continue to fetch and execute Spin tokens while the counters do whatever they get configured to without interference between the two. Another approach for some applications involves code that modifies and/or reads the counter module’s registers. Depending on the application, this can be done once or periodically. In this next experiment, we will use one counter module to generate a series of pulses called a PWM (pulse width modulated) signal. The PWM signal’s pulses will repeat at a regular interval, as shown in Figure 7-2. This interval is called the signal’s period or cycle time, and repetitions of the signals are sometimes referred to as cycles. The duration of the pulse during a given cycle can be varied. These variations can be used for information exchange with devices such as servo controllers and TV remotes or for motor control by limiting the amount of time during each cycle that current is allowed through a transistor that supplies the motor. We will use a counter module to
Figure 7-2 Illustration of a PWM signal
Assignment of the 32 Bits in Each of the Counters 59
vary the pulse durations because it is a very precise tool for this task. Because the counter module can be configured to deliver the pulse independently, this makes it possible for the cog to attend to other tasks while the pulse gets delivered.
Counter: General Description In this experiment, we discuss Counter A (CTRA); however, counter B is identical. For a counter module tutorial, consult the “Counter Modules and Circuit Applications” chapter in Propeller Education Kit Labs: Fundamentals. Also, read the descriptions of the counters in the Propeller Manual. (That material is not repeated here.) Read the sections on the CTRA, FRQA, and PHSA registers. The three registers work in concert, so their functions and interactions need to be considered collectively. Each counter is configured by a 32-bit control register. Counter A is configured by the CTRA register, and Counter B is configured by CTRB. Each control register contains bit fields with the following information: Specification of a counter mode
CTRMODE
Identification of pin A
APIN
Identification of pin B
BPIN
Specification of a dividing factor
PLLDIV (Div factor is for PLL mode.)
The information is entered into the control register by setting and clearing relevant bits in the register. We have control of all the bits in the register, but not all bits are relevant. The counter “mode” that we specify determines how the counter will behave. In the PLL mode, the dividing factor manages how rapidly the process progresses. All this will be much easier to understand as we look at the PWM example identified earlier.
Assignment of the 32 Bits in Each of the Counters Of special interest to us at this time is the specification of the pin number that is going to output information from the counter. This number, which can vary from 0 to 31, is specified in bits 0 to 5 and is called the APIN bit field. We will use I/O pin P7. If the counter gets configured to interact with a second I/O pin, that number would be specified in bits 9 to 14, which is the BPIN bit field. Our example will only use the APIN field. If we were to use the phase locked loop (PLL) modes for generating high frequency signals, we would also need to specify a number in the PLLDIV bit field (bits 25..23) as a step in determining the final frequency. We will not utilize PLL mode
60 Understanding One Cog
in this text, so the details are not covered here. However, you can find out more about it in the Propeller Manual as well as in the Propeller Education Kit Labs: Fundamentals textbook. Both are available for download from Parallax.com. The 32 modes in which the counter can operate and the use of these modes are beyond our interests at this time; however, the 32 modes are specified by five bits in the counter control register. These bits go from bit 30 to bit 26. We are interested in a PWM operation. This is specified by setting these bits to 00100. See Table 2-7 in the Propeller Manual. An application note that describes counter operations is available from the Parallax downloads site, but it is rather advanced for beginners. (The first mode, 00000, is “counter off.”)
Using Counter A for PWM Generation A close look at Figure 7-2 indicates that we have to coordinate the operation of two signals. We have to make a signal go high at a fixed rate to set the cycle time, and we have to maintain a variable cycle time within this signal to set the pulse width. (Counters are much more complicated and versatile than that, but this is enough information for us at this time.) First, we have to specify the mode we want the counter to operate in. The singleended PWM mode is specified by setting CTRA[30..26] to binary 00100 with the following code: ctra[30..26]:=%00100
Next we identify pin A as the pin the signal will be expressed on: ctra[5..0]:=Pin
We set the number that will be added (or subtracted if negative) to the counter during each cycle as follows: frqa:=1
The counter is now set up. Next, we have to start using the counter. To make sure nothing we did not plan for will happen, we make the system dormant by setting the starting pulse width to zero: PulseWidth:=0
The cycle time is set by dividing the clock frequency in CPS by the frequency. The clock frequency is 10_000_000 CPS. We want a cycle time of 10 milliseconds. This specifies a frequency of 100 cycles per second, so we use the following: Cycle_time:=clkfreq/100
Using Counter A for PWM Generation 61
We need a starting point for the counter because we will be using the system counter to measure various cycle times and pulse widths. We do this by setting the starting period count because we will set the final period count by adding the current counter value to the cycle time: period:=cnt
With all this in place, the code in Program 7-1 will give us a fixed pulse width of PulseWidth. The pulse width is set as a negative value because we will be adding 1 from the counter at each cycle of the clock to work it to zero. Program 7-1 Segment: PWM Routine
PRI repeat 'power PWM routine. phsa:=PulseWidth 'Send a high pulse for PulseWidth counts period:=period + Cycle_time 'Calculate cycle time waitcnt(period) 'Wait for the cycle time
Program 7-2 allows us to look at the result with an oscilloscope. We will use a fixed pulse width that is half the cycle time (50_000 cycles) so that our success will be readily verifiable on the oscilloscope. Program 7-2 Generating a Fixed PWM Signal
{{14 Sep 09 Harprit Sandhu PWM.spin Propeller Tool Ver 1.2.6 Chapter 7 Program 2 This program generates a fixed PWM. Meaning that as programmed the width does not vary. (Set at 50%) It is easy to recognize }} CON _CLKMODE=XTAL1+ PLL2X _XINFREQ = 5_000_000
'The system clock spec 'crystal frequency
VAR long pulsewidth long cycle_time long period PUB Go dira[7]~~ ctra[30..26]:=%00100 ctra[5..0]:=7
'set output line 'run PWM mode 'Set the "A pin" of this cog (continued)
62 Understanding One Cog
Program 7-2 Generating a Fixed PWM Signal (continued)
frqa:=1 'Set this counter's frqa value to 1 PulseWidth:=-5000 'Start with position=5_000 Cycle_time:=clkfreq/1000 'Set the time for the pulse width to 1 ms period:=cnt 'Store the current value of the counter repeat 'PWM routine. phsa:=PulseWidth 'Send a high pulse for PulseWidth counts period:=period + Cycle_time 'Calculate cycle time waitcnt(period) 'Wait for the cycle time
Run this program and look at pin 7 with your oscilloscope. You should see a signal with a 50% duty cycle. (Now if we can somehow vary the pulse width, we will have a PWM generator.) Accordingly, we address varying the duty cycle of the PWM signal from 0% to 100%. We will do this by reading a potentiometer and using its input to vary the pulse width as needed. We need to make some modifications to the program to do this. Because you are not yet proficient enough to do this, I will just give you the code we need in Program 7-3. In order to run this program, you need to load the program Utilities and the program LCDRoutines4 to the same file as this program to make it all work. (They actually have to be saved to disk in the same file as your program for your program to be able to find them.) We require these objects because we need to call certain methods that are resident in these objects. Program 7-3 Variable PWM Signal Based on a Potentiometer Reading
{{14 Sep 09 Harprit Sandhu PWM1.spin Propeller Tool Ver 1.2.6 Chapter 7 Program 3 This program generates a variable PWM signal. Based on a potentiometer reading }} CON _CLKMODE=XTAL1+ PLL2X _XINFREQ = 5_000_000 VAR long long long word OBJ LCD UTIL
stack1[25] stack2[25] pulsewidth pot : "LCDRoutines4" : "Utilities"
'The system clock spec 'crystal frequency
'space for motor 'space for LCD ' ' 'for the LCD methods 'for general methods (continued)
Using Counter A for PWM Generation 63
Program 7-3 Variable PWM Signal Based on a Potentiometer Reading (continued)
PUB Go cognew(RunMotor(7),@Stack1) cognew(LCD_manager,@stack2) repeat Pot:=UTIL.read3202_0
'read the pot at MCP3202
line 0
PUB RunMotor(Pin)|Cycle_time,period 'method to toggle the output dira[7]~~ 'gain access to these three amplifier lines dira[19..20]~ 'potentiometer location ctra[30..26]:=%00100 'Set this cog's "A Counter" to run PWM ctra[5..0]:=Pin 'Set the "A pin" of this cog to Pin frqa:=1 'Set this counter's frqa value to 1 PulseWidth:=50 'Start with position=50 Cycle_time:=clkfreq/1000 'Set the time for the pulse width to 10 ms period:=cnt 'Store the current value of the counter repeat 'power PWM routine. phsa:=-(pot*244/100) 'Send a high pulse for PulseWidth counts period:=period+Cycle_time 'Calculate cycle time waitcnt(period) 'Wait for the cycle time to complete PRI LCD_manager LCD.INITIALIZE_LCD 'initialize the LCD repeat 'LCD loop LCD.POSITION (1,1) 'Go to 1st line 1st space LCD.PRINT(STRING("Pot=" )) 'Potentiometer position ID LCD.PRINT_DEC(pot) 'print the pot reading LCD.SPACE(5) 'erase over old data
Run the program and turn the potentiometer end to end. You should see a fixed cycle time in which the high portion of the wave goes from 0% to 100%.
This page intentionally left blank
8 The Eight Cogs
The eight cogs are identical in every detail. Therefore, now that we have a feel for what one cog can do, we need a general overview of the eight-cog environment. This chapter considers the eight cogs as a whole, along with their ancillary control hardware. You should be completely comfortable with the previous chapter before you start this chapter. You need to understand what the capabilities of one cog are to understand them altogether.
The Cogs Each of the 32-bit processors in the Propeller chip is called a cog. The Propeller chip has eight of these cogs on it. The eight cogs can be run simultaneously, and each of them can perform one or more tasks, depending on how the tasks are designed and programmed. A cog can be programmed to perform more than one task if the tasks can be performed in the time available and do not interfere with one another. Because the Propeller system does not support the use of interrupts, anything that would have needed an interrupt in the usual single-processor environment needs to be assigned to its own cog in the parallel Propeller environment. There is no easy way to avoid this requirement, and because you have eight cogs at your disposal, there is usually no need to. Each of the cogs is a 32-bit logic engine with a sophisticated instruction set. Between them, the eight processors have access to 32KB of hub RAM. Each of these cogs can access this memory, one at a time, in a round-robin fashion. The access to the memory is synchronized by the system clock and is controlled by a hardware device called the system hub. Each cog gets access to the shared memory for the same amount of time. All the cogs can access the 32 input/output lines simultaneously. The timing constraints of how these interactions take place and what the latency is (meaning the worst-case delay) are described in the owner’s manual and should not be a concern at 65
66 The Eight Cogs
this stage of the learning process. Timing critical tasks is beyond what we need to know as beginners. There is no user-accessible stack (for subroutine return addresses, and such) either common or specific to a cog, and there is no interrupt function anywhere within the entire system. Neither of these functions is needed because having eight cogs running in parallel essentially eliminates the need for them. By far the greatest shortcoming of the system is the lack of large amounts of memory. Not having a large amount of memory eliminates the possibility of undertaking large number-crunching operations. The chip is not designed for large number-crunching operations, but as a general-purpose controller it has more than adequate memory. Serial memory can be added to the system, but serial memory is not as fast as RAM and has read/write issues related to accessing it regarding the speed and rules of the operation. If a serial one-wire memory has to be accessed repeatedly, a lot of time is used up. Graphics applications that use large displays or run simulations also need large amounts of memory and therefore have the same problems. At our level of interest, the memory is not a concern. We have more than enough. None of the programs in this book come close to needing but a small part of the memory at our disposal.
The Flags The system provides eight flags (which are referred to as “semaphores” or “locks” in the literature) to allow various processors to access resources that are shared in an orderly manner. This is done by setting and clearing the semaphores. The semaphore system is not a concern for beginners, but we should have an awareness of the existence of these flags so that when we come up against these difficulties, we will know that the solutions have already been implemented by the machine designers.
Special Memory Locations The shared memory consists of 32KB of hub memory organized as 512 longs. Part of this memory is reserved for special-purpose registers that determine internal cog relationships. These are listed in the owner’s manual.
The System Clock The system clock coordinates the operation of all the hardware items in an orderly fashion. The system clock rate can be controlled by the Propeller chip (although none of the programs in this book use that capability). The resister/capacitor combinations internal to the system allow the system clock rate to be used without an external crystal. It is also possible to use an external crystal to set the clock rate and use a multiplier to
The ROM 67
increase it. The decisions as to which system will be used and the frequency at which the system will run are made by the programmer and the hardware designer, depending on how the system is to be used. For most of our experiments, we will use the 5 MHz crystal that comes with the education kit. We will use a multiplier of 2 for an effective rate of 10 MHz for the clock. We specify the operational frequency at the top of the program under the Constants assignment. As beginners, we do not need to be concerned about the finer details of how the system clock operates. Leave it at 10 MHz for all the experiments for now.
Programming The program is written with the Propeller Tool, which provides a complete programming environment. If you prefer, the program can be written in Word or any other word processing program and then cut and paste it into the Propeller Tool. If you want to have circuitry as a part of the program documentation, the circuitry must be created in the Propeller Tool environment with the Parallax font. Once written, the program can be transferred either to RAM or EEPROM and executed from either one. In either case, the program has to be loaded into the main memory of the Propeller under consideration before it can be executed. If the program is in Assembly code, that code will be executed as such. If the program is written in Spin, it will be interpreted by the Spin Interpreter during run time and executed.
The ROM The read-only memory contains the Spin Interpreter, math tables for generating all the related mathematical functions, sin and log tables for making mathematical calculations, and font descriptions for the font used by the system. For now, we do not need to worry about how all this takes place because it happens automatically, in the background, when we are using the Spin language.
This page intentionally left blank
9 Special Terms and Ideas
This chapter introduces you to several new terms and ideas used by the parallelprocessing discipline that cover the new concepts, software, and hardware created for working in a parallel-processing environment. The ideas we are interested in are expressed in the Spin language environment, as implemented by Parallax, to allow us to program the Propeller chip. The Parallax software engineers have decided to design the Spin language in a way that you will find both easy to use and powerful once you get used to its structure. They also decided to coin a few terms that allow us to differentiate discussions in and about this language to provide a certain amount of semantic isolation. For most of us, parallel processing is a new concept. Even fairly competent programmers need to rethink how they approach a problem before they start to program in a parallel environment. The major concept that has to be addressed is assigning the various parallel tasks to the eight processors in an intelligent fashion. This can be done in two ways. In the first, we write a program just as we would for a one-processor linear system, and the computer is so smart that it figures what has to be done and how it is to be done in a multiprocessor system. The second method involves the programmer breaking the task down into well-thought-out subtasks and then assigning the subtasks to the eight processors, as appropriate. Because each cog is capable of doing more than one thing, the problem lends itself to elegant and innovative solutions. As things stand as of this writing, the artificial intelligence needed to allow the computer to assign the tasks autonomously does not exist for the Propeller. We have to resign ourselves to assigning the tasks to the various subprocessors individually as we design the application.
The Hardware The hardware is already set to be used as a parallel environment, with eight cogs, 32 input/output lines, and shared memory. This is set in concrete. Nothing that we can change is available to us on the hardware side. What we do have available to us is the 69
70 Special Terms and Ideas
freedom to use the hardware as we see fit. Although this may seem trivial at first, as we will see, it is not. There are intelligent ways to use the hardware—and there is much room for foolishness.
The Software The software introduces us to some new concepts and constructions to allow us to play in a parallel environment; therefore, understanding the software is the key. It’s not just understanding what each instruction does; it is understanding what the motivation is behind designing the software the way it was designed so that our efforts are not contrary to the way the system is intended to be used. In other words, we do not want to row upstream. Even so, each programmer will have his or her own way of doing things. Each project undertaken has to provide a satisfactory solution, and there are many ways to get the job accomplished. The fact that we have eight processors at our disposal makes for many, many interesting possibilities. As we look closely at the system, we will see that some of the realities are forced upon us by the features selected by the hardware designers and some by the choices made for us by the designers of the software. Because this was all decided some time ago, we have no say in the matter. We have to work within what has been provided to us. Here are two basic concepts that need to be understood: ■ If a certain item of hardware does not exist, there is neither a need nor a way to
address it. It needs no software support. ■ If we have some great piece of hardware and the software to address it does not
exist, there is no way to give the hardware the instructions needed to manipulate its properties. We can only ignore the hardware. In other words, if there are only 32 I/O lines on the processor, no amount of software sophistication will allow us to turn I/O line 33 on or off, and if the hardware has 33 input/output lines and the software allows us to address only 32 of them, the 33rd line is useless for all practical purposes. In philosophical terms, we say that we cannot discuss those things for which there are no words. First, the words need to be invented and defined. The Spin language does this for us to allow us to proceed with programming. That is what the instruction set of every language does.
New Hardware-Related Definitions On the hardware side, the new definitions are as follows: ■ Cog A cog is an independent 32-bit RISC-like processor that resides within the
Propeller chip. The program that the cog executes is downloaded into Cog_0, along with all other program instructions. The interpreter is transferred from main ROM
New Software-Related Definitions 71
to the cog when each cog is opened. An area of memory has to be assigned to every cog except Cog_0 in the main memory for its program space. Cogs are given access to shared resources, one after another, in a round-robin fashion by the hub. ■ Hub The hub is the central monitoring device that controls which cog gets to do what and when. It allows access to the shared system resources by each cog, one at a time, in a round-robin fashion. It manages all ancillary functions for the cogs. Each cog is assigned the same amount of time during its turn to access the mutually exclusive resources. ■ Shared memory This is the internal memory (to the Propeller) that all the cogs can access when it is their turn to control the system. It is the hub RAM. All the variables declared in the VAR section of the program are stored in the shared memory, regardless of whether more than one cog addresses them. The shared memory is not to be confused with the external memory that the program is read from on startup if no PC is attached to the Propeller system. The external memory is not accessed by any cog directly, although it does download to the Cog_0 memory space on initial startup and is loaded through Cog_0. ■ System clock Like all system clocks, the Propeller system clock times all internal operations. There is only one system clock, and it is shared by and accessible to all the cogs. Its speed is programmable. ■ Round-robin This refers to the serial access the hub provides for all exclusive resources to each of the cogs in the system. Each cog gets the same amount of time as every other cog. Turning off a cog saves energy but does not save time. In other words, turning off a cog does not speed the system up. ■ External memory This is the “one-wire” memory that is external to the Propeller chip. This memory contains the program the Propeller will execute if it is not connected to a computer on startup. This means you cannot have a free-standing device if it does not have external memory as a part of the Propeller’s peripherals.
New Software-Related Definitions On the software side, the new terms and definitions are as follows: ■ Object An object is a piece of software that contains any number of methods that
can be called by other programs if they have been defined as PUB or public routines (methods). Any program that wants to use the programs in an object has to declare its intentions in the OBJ part of the program. An object itself does not have to be executable, although most are. ■ Methods and nesting An important part of the way the Spin language is defined is the lack of a RETURN statement and the way in which this fact is compensated for. In the Spin language, a subroutine is called a “method.” All methods are terminated with a blank line. All statements that are a part of a repeat structure in a program listing are made part of the repeat structure by insetting them by one or more spaces. This is illustrated in Program 9-1.
72 Special Terms and Ideas
Program 9-1 Segment Illustrating Indented Lines
repeat 'movement loop iters:=pot2 'set number of iterations to perform index:=0 'reset index repeat iters 'do iterations index:=index+1 'increment index targetPosition:=targetPosition+index 'set new position waitcnt(clkfreq/Pot1+cnt) 'wait time for iteration repeat iters 'now do the slow down index:=index-1 targetPosition:=targetPosition+index waitcnt(clkfreq/Pot1+cnt) repeat while startFlag==0 'wait till done waitcnt(clkfreq+cnt) 'delay to see stop targetPosition:=startPosition 'set to go back waitcnt(24_000+cnt) 'wait to get done repeat while startFlag==0 'wait till done waitcnt(clkfreq+cnt) 'delay to see stop ■ Process A program is called a “process” in the Spin language. ■ Method Subroutines are called “methods” in the Spin language. ■ Latency Latency is the time between when an action is required to take place and
when it actually takes place. The concept is particularly relevant in the Spin language because each cog gets access to the mutually exclusive resources only when it is that cog’s turn. So the possibility exists that when a cog is about to ask for some piece of information, it becomes some other cog’s turn and the first cog now has to wait until its next turn to get the information it requires. This is the worst-case latency for this particular scenario. See the Propeller Manual for a discussion of this topic. Other processors also have latency, but this is not as critical as it is in the Propeller system because of the multiple processors and the resource sharing requirements. ■ Variable assignments Variables are assigned in two ways: either as shared variables or as variables local to a method. Shared variables are declared under the VAR block, like this: VAR long long long long long long long long long long
Pos[3] stack2[25] stack3[25] stack4[25] stack5[25] stack6[25] stack7[25] pulswidth startPosition PresentPosition
'Create buffer for encoder 'space for Cog_LCD 'space for Cog_SetMotorPower 'space for Cog_RunMotor 'space for Cog_FigureGain 'space for Cog_Start 'space for readopts ' ' '
New Software-Related Definitions 73
long long word long long long word word
TargetPosition PositionError startFlag gain pot1 Pot2 iters index
' ' ' '
'number of iterations
Local variables are declared on the first line of the method, like so: PUB POSITION (LINE_NUMBER, HOR_POSITION)|CHAR_LOCATION 'Position the cursor 'Line Number : 1 to 2 'Horizontal Position : 1 to 20 'specified by the two numbers CHAR_LOCATION :=(LINE_NUMBER-1)*64 'figure location. See Hitachi HD44780 CHAR_LOCATION +=(HOR_POSITION-1)+128 'fig loc. See Hitachi HD44780 SEND_INSTRUCTION2 (CHAR_LOCATION) 'send the instr to set cursor
In the preceding code, LINE_NUMBER, HOR_POSITION, and CHAR_ LOCATION are local variables available only in the public POSITION method. Local variables are stored in the main memory, not in the cog memory. They do not take up cog memory space.
This page intentionally left blank
10 The Spin Language
Note I find that the best way to use the Propeller Manual is to have a hard copy in hand for reference and the latest version of the manual in electronic format open in a window on the computer screen. This way, you can search as well as cut and paste from the manual rapidly when you need to. However, nothing beats having the book in your hand—and nothing beats being able to read in bed! Note In the program listings, I have tried to use a straightforward programming style that’s easy for beginners to read and understand. If you look at the published listings, you will see that it is possible to write much more efficient code, but this would make the code harder to read. I have tried to avoid this whenever possible. Once you get comfortable with Spin, you can convert what I have provided to a more efficient format that suits your programming style.
You should have a hard copy of the Propeller Manual (PM) in your possession for reference as we proceed with this chapter. This is especially important because, as of this writing, the manual is the definitive authority on the Propeller chip, the Spin language, and the Assembly language. You cannot do much without it. Almost all experiments in this book are performed on and with the Propeller Education Kit as provided by Parallax. I used the version with the 40-pin chip. All illustrations show wiring on this kit. All wiring diagrams are for this kit, although they all will work on other hardware. Both the Development Board and the Demo Board are also suitable, but minor modifications to the software might be required to reflect the appropriate addressing changes you find necessary. Before we can start writing simple routines that will allow us to learn how to use the Propeller chip, we need to have a rudimentary understanding of how the language is used to write programs. The new higher-level language Parallax has designed specifically for this chip is called Spin. Spin is an object-oriented language that shares some properties with simpler languages such as BASIC. However, it is a very powerful language, and you will find that it is not hard to learn, especially considering that there is no alternative other than the even-harder-to-learn Assembly language (PASM) if you want to use the Propeller chip. 75
76 The Spin Language
We will not cover the sophisticated intricacies of the language in this book but rather concentrate on using the simplest of the commands in the language to perform the simplest tasks so that we can start to become comfortable with the language. We will move toward using the language in a more sophisticated context as your skills improve and your comfort level with the language increases. In the first few examples, I provide code written in Spin that looks as much like BASIC as I can make it so that you can more easily follow what is going on. For those who are not comfortable with BASIC, I suggest you either get a beginning BASIC text or just ignore the BASIC examples and concentrate on learning what we are trying to do with Spin. The first program is the ubiquitous “blink one LED” program that seems to be a requirement in most texts. Before we can write this program, we need to say something about how the code is specified in Spin. Spin is structured, meaning that it requires you to be more organized in the way you do things. It requires that constants and variables be specified before you start writing the body of your program. It means that routines have to be specified as being private or public, and it means that a program has to follow a certain general structure. It also means a host of other things, which we will discover as we go along. Spin uses a documentation scheme that allows you to do the following: ■ You can embed documentation within the program in a way that allows you to sup-
press two levels of the documentation. ■ You can separate the documentation from the code when needed.
These are extremely useful features, and every attempt should be made to follow the suggestions given in the Propeller Manual in regard to the use of these features. The Spin screen is color-coded so that each section of code is easy to recognize as a separate block. Although you can specify the color codes, we will not bother with that in this book. We will use the color scheme that comes with the Propeller Tool. Six separate block designations are used in the Spin language: ■ CON Used for the specification of constants ■ VAR Used for the specification of variables ■ OBJ Used for the designation of objects to be called ■ PUB Used for declaring methods as public ■ PRI Used for declaring methods as private ■ DATA Used for declaring data and data structures
All programming segments must fit within these six blocks. However, comments and documentation can appear outside the blocks. We will cover the use of the blocks in more detail as we need them. Let’s begin with a few instructions that will be used in almost every program we will ever write. The first ones have to do with declaring constants of all kinds.
VAR 77
CON The CON statement is used to declare the constants that will be used in the program. In any program, the first thing we need to do is to declare and define the constants we are going to use within our program. Defining the constants also names the constants and thus makes it much easier to follow the program. It is best to define each constant on a new line, and every constant within the program should be defined and its use then described adequately. Doing it this way allows you to change a constant at this one location and it will be changed all over the program. This makes it easier to understand and maintain programs. In our case, we will be using the following two constants: ■ Pin To identify the pin being used ■ Delay To specify the delay between the state change of the LED
In the listing, these constants will be typed in as follows (shown in the Parallax font): Pin = Delay =
1 500
; number of the pin connected to the LED ; delay in milliseconds (half a sec)
All the constants declared in the CON section are in the shared memory and are available to all the cogs. Only those constants actually declared in the CON section are available to all the cogs. Constants used by methods that you call from your program are local and are not shared. The value of a constant never changes within the program, across all methods.
VAR Variables, of course, are those values that change from time to time within the methods. We define the variables up front so that they are all in one place and are easy to rename and redefine if that becomes necessary. Because Spin uses a number of different types of variables, we have to specify the name of the variable along with the byte, word, or long designation that will be used to contain that variable. In our first program, the variables will all have a value under 255, so we can use the byte variable specification for them. (One byte can hold a value of from 0 to 255 in its 8 bits.) Putting the variables right under the constants allows us to see all the variables together in one place so that we can add and remove them from the list as necessary. Keeping the variable list next to the constants is an advantage in that if a constant needs to become a variable or a variable needs to become a constant, it can be done from this one place with ease.
78 The Spin Language
All the variables declared in the VAR section are in the shared memory and are available to all the cogs. Only those variables actually declared in the VAR section are available to all the cogs at all times. Variables used in objects that you call from within your program are not shared, and in most cases you may not even know what they are or how they were used in the called method.
OBJ The OBJ statement defines an object to be called from your program. An object is equivalent to a program and may contain one or more methods. The OBJ section of the program lists the objects that will be called from the program. The objects themselves are defined somewhere else (within limits). The program can call objects or parts of them as needed. It is a good idea to define what each object does in some detail in the documentation so that we know why we are calling it and what it does. Once these items have been defined, we are ready to start writing the main body of the program. Most programs start with the PUB (public) statement followed by an arbitrary name (it is best to use either GO to indicate the start of a program or MAIN to follow the C convention). In our case, we are going to call all our beginning methods GO. Our first line of executable code will follow the GO assignment.
PUB or PRI A method can be specified as being public or private. Private methods are available only to the immediate object they are in. Public methods are available to other objects in the immediate vicinity (stored in the same file). In the Spin language, the specification of every object starts in the first column of text. The body of the object is indented one or more spaces, and everything that is indented under the first line of the object becomes a part of the object or method. There is no “return” at the end of the object, and the object is terminated by the first new block designation encountered. The next unindented line of code after the end of the current object defines the beginning of the next object. So in a way, our main subroutine extends from the declaration of GO as being a public subroutine to the beginning of the next unindented block of code. Let’s get ready to write the pseudo-code instructions that will demonstrate what a Spin program looks like. Here is what we want our first program to do: ■ Select and set the LED line to be an output. ■ Declare the number of the line to which our LED is connected. ■ Turn the LED line to High or On. ■ Pause for a short time.
PUB or PRI 79
■ Turn the LED to Low or Off. ■ Pause for a short time. ■ Repeat the last four lines. ■ End the program.
In order to do all this, a certain amount of housekeeping is necessary before we start. The following minimal setup is necessary for our particular program: ■ We need to decide which of the 32 lines available in the Propeller system will be
used to control the LED. We will use line 27 so we can save all the pins on one side of the Propeller, from 0 to 15, for future experiments. ■ We need to set the selected line to be an output line. ■ We need to decide how long the delays will be. We will use 0.5 seconds. ■ We need to decide and specify the number of cycles to be completed. We will do it forever. Note The cnt variable in Program 10-1 is the system counter in the Propeller. See the Propeller Manual (PM).
Instead of writing an absolutely minimal four- or five-line program, we will write something a little more complicated and useful. We will still blink the LED, but we will use predefined constants and methods to get a little further along into the Spin language right away. Program 10-1 contains detailed comments on every line and additional general comments to explain what is going on in the program. We have established a standard that requires the beginning of each program to be a GO method, not unlike using MAIN in the C language. We will follow this standard for all our programs. The simple program structure is illustrated in Figure 10-1.
Figure 10-1 Simple program with three method calls
80 The Spin Language
All programs are available for copying from the support website. Program 10-1 Blink an LED Using Methods
{{04 June 09 Harprit Sandhu BlinkMethods.spin Propeller Tool Ver. 1.2.6 Chapter 10 Program 1 Blinking an LED This program turns an LED ON and OFF and demonstrates the use of subroutines in an absolutely minimal way. Define the constants we will use. Propeller font schematic: │ 100 Ω 21├──────────┐ │ LED │ GND }} CON _CLKMODE=XTAL1+ PLL2X _XINFREQ = 5_000_000 pin waitPeriod high low
=21 =500 =1 =0
'CON defines the constants 'The system clock spec 'external crystal 'select the pin to be used for the LED 'set the wait period 'define the High state 'define the Low state
{{ The following PUB Go is the main part of the program. Everything else is in the 3 called methods. }} PUB Go dira [pin]~~ repeat turnOn_LED wait turnOff_LED wait PRI turnOn_LED outa[pin] :=high
'sets pin to an output line 'specifies times to repeat. 'these 4 Methods are called 'these 4 Methods are called 'these 4 Methods are called 'these 4 Methods are called
with the ~~ Blank=forever by name alone by name alone by name alone by name alone
'Method to set the LED line high 'line that actually sets the LED high (continued)
PUB or PRI 81
Program 10-1 Blink an LED Using Methods (continued)
PRI turnOff_LED outa[pin] :=low
'Method to set the LED line low 'line that actually sets the LED low
PRI wait 'Method defines the delay waitCnt((Clkfreq/1000)*waitperiod +cnt) 'wait till counter 'reaches this value
If there is disagreement between a program in this book and the same program on the website, use the program on the website. It will have the latest changes and error corrections in it. Figure 10-2 illustrates the circuit layout for Program 10-1 on the Propeller Education kit. You must completely understand each and every line in Program 10-1 before you read another word. This simple program defines the essential structure of almost every program we will investigate in this book, and if you understand it in every detail, you are on your way to becoming a Spin programmer. In later discussions, we will not use words such as “subroutine” but rather will follow the nomenclature used in the Propeller Manual and use “method” so that we can become familiar and comfortable with it. New Spin words will be added to our vocabulary as they are needed for the programs we develop. Program 10-1 demonstrates the following concepts: ■ The CON block is for the constants. In the constants block, we specify what wire/
pins on the Propeller are to be used for what function. If we ever decide to attach the LCD to another pin, all we have to do is change the designation in this block.
Figure 10-2 Schematic of program with two cogs in it
82 The Spin Language
■ The VAR block is for the variables. We will not use any variables in this first pro-
gram, but in order to demonstrate the use of a VAR block, we must have at least one variable defined in the block. I have defined a dummy variable called “numbr” as a byte. This would mean that “numbr” could have contained any number from 0 to 255 if we were using it in our program. ■ The PUB Go statement starts the program proper. The program first defines the pin we are using as being an output and then repeats the turning on and off of the LED an infinite number of times, which is defined by not providing a number after the repeat command. ■ The three PRI blocks are methods that are private to this program and are used to define the actions of the three calls in PUB Go. They turn the LED on, create the wait pause, and turn the LED off in the sequence in which they are called. The purpose of this program is not so much to turn the LED on and off but rather to go through all the procedures we need to go through to write and execute a Spin program. Once you are comfortable with this program, you will be able to write an awful lot of programs in Spin. As we add to the techniques used with the Propeller in subsequent programs, you will acquire more and more of the skills that you need to Spin effectively. The wiring for Program 10-1 is illustrated in Figure 10-3. Turning an LED on and off is okay as a start, but we need to input and output all sorts of things into and out of the Propeller if we are to create useful interactions. A most useful addition to any microcontroller project is a small liquid crystal display (LCD). We will implement the rudimentary control of a 16×2 LCD controlled by a Hitachi 44780 controller. Later on, if you like you can extend this implementation to a full and comprehensive control of any display that uses the Hitachi controller. We, on the other hand, will convert the rudimentary LCD display program into code that can be used within all our future programs to display the results of whatever it is that we are doing with the Propeller. This is covered in detail in Chapter 14.
Figure 10-3 Wiring schematic for blinking an LED in Program 10-1
Creating a Program with Two Cogs 83
Creating a Program with Two Cogs Figure 10-4 shows the placement of the various components you need to start a second cog in your system. All other cogs are to be started in this way. Note Cog_two will allow us to implement the use of a 16×2 LCD display.
Figure 10-4 Wiring for one LED as programmed in Program 10-1
This page intentionally left blank
11 Tasks Suited to Parallel Processing
Everything (except the most rudimentary tasks) can be handled in a parallel-processing environment. Of course, many tasks are best not handled in this environment. An illustrative example is the display of all the numbers from 1 to 1,000. We could assign this to three processors: one to create all the odd numbers, one to create all the even numbers, and a third to display them all on the computer screen. Obviously, this is not the most intelligent way of getting this job done. Like many other tasks, this task is easily handled by one processor, and that is how we would normally handle it even in a Propeller environment. Essentially, this task is too simple to need a parallel environment. A parallel environment works best when a number of tasks need to be undertaken simultaneously to complete the job at hand. Complicated-but-not-too-complicated tasks are best picked as our first examples. These and similar examples will be followed up in Part III of the book with full-fledged programming implementations.
Parallel Programming Examples Stepper Motor Running a bipolar stepper motor is a good target for parallel programming. The running of bipolar stepper motors is covered in detail in Part III of this book in Chapter 26, and you may want to refer there before you continue reading here. At the least, you should know how a stepper motor works so that what we consider here makes sense to you. Here, we will confine ourselves to the general discussion of the parallel tasks we need to undertake to run the motor.
85
86 Tasks Suited to Parallel Processing
To run a stepper motor, we need to undertake the following tasks: ■ Determine the sequencing requirements for the motor coils. ■ Read a potentiometer that we will use to set the speed of the motor. ■ Manage the power to the amplifiers for the two motor coils. ■ Manage the LCD to display information of interest to us as we run the motor.
Because we are working in a parallel environment, each of these tasks can be assigned to a cog.
DC Motor Speed Control Controlling the speed of a DC motor with a potentiometer often requires the reading of the potentiometer or some other input device and modulating the power to the motor so that the encoder counts read reflect the desired motor response. In such a situation, a parallel-processing arrangement can be used to our advantage. With the setup we will be using for our experiments, the cogs can be assigned as follows: ■ Read the potentiometer that will control the speed. ■ Create the PWM signal needed to power the motor. ■ Read the encoder repeatedly to get speed feedback. ■ Display the results of the experiment on the LCD.
Hobby Servo (R/C) In a hobby servo, the control requirement is to send the servo a pulsed signal every 1/60th of a second. The timing of the pulses is not critical, but the length of the pulses is. They have to be 1,520 microseconds ±750 microseconds long. As usual, we will use the input from a potentiometer to control the length of the pulses. Each critical task will be assigned to a separate cog. With the setup we will be using for our experiments, the cogs can be assigned as follows: ■ Read the potentiometer that will control the pulse width. ■ Create the pulse width needed to position the motor. ■ Send the pulses to the motor at the required times. ■ Display the results of the experiment on the LCD.
There are many variations of this control scheme. One obvious possibility is to write the code so that the servo output is a 90-degree quadrant instead of a 180-degree move. In most applications of these servos, the middle 90 degrees of the move is the most useful. It would also be possible to read a second potentiometer and use its value as a trim factor.
Summary 87
Self-Leveling Table In a self-leveling table, we need to be able to make a correction both in the X and Y directions. In order to make the correction, we need to detect what the error in the position of each axis is. We get this information from a gravity sensor called the Memsic 2125. We will need a servo for each axis. The two axes will be controlled independent of one another. These functions are implemented by assigning the tasks to the cogs, as follows: ■ Read the X and Y errors from the sensor. ■ Make an incremental correction to each axis if there is an error. ■ Display the status of the table on the LCD. ■ Add the reading of two potentiometers to trim the exact level position of the table.
The software developed here could be used to stabilize a camera platform or to provide automatic leveling for a model aircraft.
Summary In general, every application breaks the tasks to be accomplished into a number of fairly straightforward blocks that are simple to create, and it assigns them to individual cogs. Of course, calculations will also have to be made, and pins will have to be set up to perform the necessary I/O. However, we will not discuss these tasks here. They are all covered in Part III of the book, where these ideas are turned into actual working applications. The coverage may not be exactly as listed in this chapter, but the general ideas are preserved.
This page intentionally left blank
Part II Input and Output: The Basic Techniques to Be Mastered— Learning by Doing
Although the idea is losing currency in today’s academic world, we learn best by doing. Learning works best when the hands, the eyes, and the brain work together to reinforce one another. With this in mind, we will proceed with undertaking a number of progressively difficult experiments that lend themselves to implementation on the Propeller system. In this part of the book, we will develop the basic techniques necessary to use the Propeller to address any number of real-world situations. In Part III of the book, we will use what we have learned here to create some real-world devices. In this part of the book, we are mastering the building blocks.
This page intentionally left blank
12 General Discussion of Input/Output
This is a general discussion of how we will proceed with learning the basics of using the Propeller so you will understand the how and why of the experiments and thus get the most out of them. The experiments we will undertake are designed to give you the hands-on experience you need to get familiar with the Propeller chip. As such, I have tried to make them as short and as easy to understand as possible. Within the various experiments, I tried to incorporate as many of the basic Spin language techniques as I could, to make you more comfortable with the software environment. As was stated previously, the Assembly language programming facility provided for the Propeller has not been used in any of the programs except for the prewritten code for reading an optical encoder used in Chapter 28 as a part of the DC motor experiment. This is a book specifically for beginners, and PASM is really too difficult to get into at this stage. Besides, you really need to have a pretty good feel for binary mathematics and Boolean algebra before you can use PASM because a lot of it has to do with manipulating bits and bytes, and a foundation is required before it can be used. (I considered the possibility of writing a beginner’s book on PASM, but decided it was not really a subject for beginners!) The experiments start off with the most rudimentary of all experiments: reading an input line. Because we have to have a way to verify that we actually read the input, we will turn an LED on if and only if the input line has been grounded. This experiment contains the code segments needed for an absolutely minimal program. In some ways, this is about as short an input/output program as one can write for the Propeller. This is the prototypical Spin program, and all programs are basically variations of this program. We will build on it from here on out.
91
92 General Discussion of Input/Output
The purpose of the first experiment is not so much to turn the LED on and off as it is to get familiar with everything you need to do to create a fully functional program that is downloaded to the Propeller chip and causes some sort of a response in the hardware that you can see. The easiest way to do this is with an LED. You will also notice that this object (program) incorporates simple methods (subroutines) to introduce you to how methods are used within the Spin language. It is not a parallelprogramming example. From there, we make a fairly big leap to using a liquid crystal display (LCD) with the Propeller and developing all the methods that we will need to use it in the experiments that follow. We have to make this jump because we need an LCD (or something else) to show us what is going on within our experiments in a visual format. All the methods we need to give us comprehensive access to the LCD are developed, and the techniques for storing them at a suitable location on disk and then calling them from within another object are covered. A comprehensive discussion of what one needs to do to control an LCD is provided in Chapter 14. The discussion there gives you the information you need to control all aspects of the operation of a typical 16×2 LCD from the absolute beginning. Although writing to a computer display is mentioned in this tutorial, I do not cover the creation of the software needed to communicate with a display because the subject is more advanced than is suitable in a book for beginners. You should not let this issue keep you from using larger displays because there are a number of objects (in the object exchange) that allow you to use a display with minimal effort. These programs are in the public domain, and I encourage you to learn how to use them based on the use demonstrated for the LCD. The way you access a larger display is similar to how you access the LCD, and using an LCD is covered in detail. Once we have an operational LCD, we can start to develop the techniques we need to bring information into the Propeller and to get output information from the Propeller. The LCD programs developed allow us to see what is going on within the system with minimal new programming. As we proceed, you will see that we really do need to be able to look into an operating program to see what is going on, and that an LCD can be quite adequate for doing that. Besides, the LCD is the most inexpensive way to get a self-contained operation going with the kit we are using. The inputs and outputs we have the greatest interest in are the types of signals that computers use to interact with the world. A summary of them follows: ■ Pulsing ■ Using the LCD to see what is going on ■ Binary I/O interaction ■ Reading and creating pulse widths ■ Reading and creating frequencies ■ Reading and creating pulse sequences ■ Read a varying DC voltage signal (generated by a potentiometer)
General Discussion of Input/Output 93
Generally, almost everything we read into a computer and send out of a computer comes in and goes out in one of these formats. Each of these is covered in a separate chapter to compartmentalize things and keep confusion to a minimum. We need a source that provides us with signals that we can respond to. Because we are operating in a parallel-programming environment, the generation of any signals we may need can be assigned to one of the Propeller’s cogs. We do not need a separate programmable signal generator to provide our signal needs. Because input/output is what it is all about, learning how to generate the signals we need is an important skill for us to master. Mastering the preceding input and output techniques gives us a basic understanding of the processes used to get information in and out of a microprocessor. In that we have eight cogs to work with, we can assign one cog to read the information and another to put it out in the same shape and form as the basis for our experiments. If both the input and output waveforms look to be (somewhat!) identical in some respect, we will have successfully read and generated the waveform under consideration. You can use one trace of your oscilloscope to look at the incoming waveforms and the other to look at what you are sending out. There will be a delay between the two waveforms, and the shapes and frequencies will not be identical. However, they need to be pretty much similar if you want to claim success. There will also be some timing discrepancies, but we won’t let that distract us. Let’s see how well we do. Once we get things working, you can work on getting them perfect. Once we are comfortable with the inputs and outputs covered in this part of the book, we will move to the third part of the book, where we will use what we have learned in Part II to create real-world devices. Part III of the book is dedicated to the construction of a number of devices that use the information we mastered in the first two parts of the book. All the projects are straightforward and are designed to be similar to the projects you might expect to undertake if you are interested in the realworld use of the Propeller chip.
This page intentionally left blank
13 Binary Pulsing
Before we can do any useful work with a microprocessor, we need a way to get information into and out of the processor. If nothing goes in and nothing comes out of the black box, its use is somewhat limited! The output has to be such that we can either read it or connect it to some other device that can respond to it. We or the device then reacts to this signal in a way that creates useful information or work. That, in its simplest form, is the application of computers to solve the problems we are interested in. The simplest output any programmable device can provide is a signal that goes on and off. The rate at which the line goes high and low and the relative timing of the high and low signals can provide useful information in any number of ways. Most of the serial communications that computers undertake between one another is based on the manipulation of such signals, as defined by the ASCII codes. All the communication within the computer itself is undertaken with on/off signals. We run motors with PWM (pulse width modulated) signals that vary the duty cycle of the signal between zero and one, and thus the speed of the motor. More properly, the power to the motor is said to be a function of the PWM signal. Therefore, learning how to manage these on/off signals is pretty much fundamental. For most purposes, it is not possible for human beings to use the information that the signal provides without some kind of secondary manipulation or amplification of the signal. The most common interface is the computer monitor. Learning the techniques for using the signals that computers provide is an important part of learning how to use computers. In this, the second part of the book, we learn the basics of how to read and generate the various signals that computers create and need to do useful work. Part III of this book is devoted to running experiments and making devices that use the techniques we developed in Part II. For our first exercise, we will write a simple program to blink an LED on and off on an even “on/off” cycle. The purpose of the program is not to blink an LED but rather to go through all the procedures that need to be undertaken to write a complete
95
96 Binary Pulsing
program and run it. By doing this, we become familiar with the operation of the entire system. Because we are all beginners as far as the Propeller chip goes, we also need to get familiar with what a program written in Spin looks like and we need to get familiar with what the procedures for running a Spin program are. We also need to start thinking about incorporating methods into the objects we write. In the Spin language, subroutines are called “methods.” Although there is really no need to call methods in the LED-blinking program we are about to examine, it uses three very simple two-line methods to perform the functions that manipulate the LED signals. A listing of the program is provided in Program 13-1. Program 13-1 Blinking an LED: Simple Method Calls
{{12 Sep 09 Harprit Sandhu BlinkLED.spin Propeller Tool Ver. 1.2.6 Chapter 13 Program 1 This program turns an LED ON and OFF, with a programmable set delay. It demonstrates the use of methods in an absolutely minimal way. The clock is running at 10 MHz. Define the constants we will use. There are no variables in this program. }} CON _CLKMODE=XTAL1 + PLL2X _XINFREQ = 5_000_000 inv_high inv_low waitPeriod output_pin
=0 =1 =5_000_000 =27
'The system clock spec 'the crystal frequency 'define the inverted High state 'define the inverted Low state 'about 1/2 sec switch cycle
'High is defined as 0 and low is defined as a 1 because we are using an 'inverting buffer on the Propeller output. PUB Go dira [output_pin]~~ outa [output_pin]~~ repeat turnOff_LED wait turnOn_LED wait
'sets pin to an output line with ~~ 'makes the pin high 'repeat forever, no number after repeat 'method call 'method call 'method call 'method call (continued)
Binary Pulsing 97
Program 13-1 Blinking an LED: Simple Method Calls (continued)
PRI turnOn_LED 'method to set the LED line high outa[output_pin] :=inv_high 'line that actually sets the LED high PRI turnOff_LED outa[output_pin] :=inv_low
'method to set the LED line low 'line that actually sets the LED low
PRI wait waitCnt(waitPeriod + cnt)
'delay method 'delay is specified by the waitPeriod
Here is what is going on in Program 13-1: ■ Program 13-1 declares four constants and then starts a public procedure that calls
the three private methods that control the LED and the timing delay. All are named to be easy to remember. ■ The CON block states the constants that will be used in the program. In this particular case, we have four constants that define the operating parameters for the program. ■ PUB Go, the main procedure, defines the pin we are going to use as an output and then repeats the main loop of the program. The three PRI (private) methods that are called provide the On/Off and delay functions used by the program. Other programs you write may be much more complicated, but they will follow this basic layout. We will creep up on more complex programs so that you will have no problem following what is going on. The wiring needed between the Propeller chip and the LED is shown in Figure 13-1. I have omitted all the power wiring so that we can concentrate on the wiring we have to create. The power wiring follows the recommendation of Parallax for their Education Kit, which will be used as the basic layout throughout this book. All the experiments will fit on the prescribed Education Kit assemblage of breadboards. The layout of the basic electronics that power the board is shown in Figure 13-2.
Figure 13-1 Wiring layout for blinking an LED
98 Binary Pulsing
Once you have the wiring connected up and the program running, you will have learned the basic procedure for running all programs. As a general rule, we will reserve pins P26 and P27 for general output from the Propeller chip. These lines need to go through a 7404 hex buffer to prevent overloading the very limited current capacity of the Propeller pins. Figure 13-3 shows the placement of the 7404 hex buffer on the breadboards to accomplish this. For the record, Figure 13-2 provides the schematic for wiring up the basic Propeller layout. This is as suggested for the Propeller Education Kit by Parallax. Note This layout will be used for all the experiments in this book.
The Memory module is not shown in this layout, and we will not need it for any of our experiments. However, you can install it if you like for your own experiments. All experiments use this basic layout. Parallax recommends that you connect power and ground to both sides of the Propeller, as is shown in Figure 13-2.
Figure 13-2 Basic power-up layout and USB connection for a Propeller chip
Binary Pulsing 99
Figure 13-3 Hex buffer placement and wiring layout
This page intentionally left blank
14 Setting Up a 16-Character-by2-Line Liquid Crystal Display
Although this is early in the game, we absolutely have to have some way to look at the results of what we are doing in the Propeller as we develop our programs. We will go over the operation of a 16-character-by-2-line LCD in absolute detail later in Chapter 21. For now, we just need to design the wiring layout and develop the code that will allow us to start using the LCD with our experiments (with minimal explanations). The minimal discussion provided in this chapter is designed to keep you from getting completely lost as you install your LCD onto the breadboard. Almost all the 16-character-by-2-line displays on the market are controlled by the Hitachi HD44780 or a compatible LCD controller. Do not purchase an LCD that does not meet this specification because all the work described in the book is based on LCDs as controlled by this Hitachi controller. The possibility that we could buy a bare LCD and write all the code to control it is beyond the scope of this book. Looking through the data sheet that comes with the display, you will find a pinout table very similar to the one shown in Table 14-1. We will use this table to wire the LCD to the Propeller chip. We will be using the Parallax Education Kit wired exactly as suggested by Parallax for their educational materials. See Figure 14-1 for a pictorial representation of the connections. Note Many of the units do not support lines 15 and 16, and we will not be using them in any of our experiments either.
Position the LCD on a bottom line of the board, as shown, with pin 14 in the rightmost holes at the bottom of the perforated board assembly. The wiring scheme we will be using is listed in Table 14-2. Note This scheme is suitable for 4-bit or 8-bit communications.
101
102 Setting Up a 16-Character-by-2-Line Liquid Crystal Display
Table 14-1 Pinout connections for a typical 16×2 LCD
Pin No.
Symbol
Description
1
VSS
Logic ground.
2
VDD
Logic power 5 volts.
3
VO
Contrast of the display. Can usually be grounded.
4
RS
Register select.
These are
5
R/W
Read/Write.
the three control
6
E
Enable.
lines.
7
DB0
8
DB1
9
DB2
This is
10
DB3
one port or
11
DB4
eight lines
Half the port
12
DB5
of data.
can also
13
DB6
be used.
14
DB7
See the data sheet.
15
BL
Backlight power.
These two lines
16
BL
Backlight ground.
can be ignored.
Figure 14-1 LCD placement on the perf board—installed at extreme right, as low as possible. (Eight-bit path shown.)
Setting Up a 16-Character-by-2-Line Liquid Crystal Display 103
Table 14-2 Wiring Connections Between the Propeller and the LCD
Pin No.
Symbol
Propeller pin
1
VSS
Ground
2
VDD
5 volts
3
VO
Ground
4
RS
P18
5
R/W
P17
6
E
P16
7
DB0
P15
8
DB1
P14
9
DB2
P13
10
DB3
P12
11
DB4
P11
12
DB5
P10
13
DB6
P9
14
DB7
P8
15
BL
16
BL
Data can be transferred to the LCD either 8 bits at a time or 4 bits at a time. Initially, we will wire up all eight lines of the data bus, but once we get the LCD working, we will change over to 4-bit mode so that we can free up four lines for other uses. The Spin code we will be using to access the LCD is listed in Program 14-1. This code will display four A’s and four a’s on line 1 and four B’s and four b’s on line 2 when everything is wired up correctly and the program is downloaded and run. Wire up the LCD and run the program to confirm this. The code for this program is listed here so you can see what we are doing, but the code will not be explained at this time so that we can move on to the experiments as soon as possible. The various routines will be placed in an “LCDRoutines4” program, and we will be able to call every method in LCDRoutines4 by its name from our programs. We will not have to type in any of this code again. All this is explained in Chapter 21, which is devoted to a very detailed explanation of how an LCD needs to be set up and the programs written to access the features we have in mind. The listing provided here also demonstrates the ability of the Spin language to create electronic diagrams within the Spin language with the Parallax font. Only the diagram for this exercise was drawn with the Parallax font in this book. All other diagrams were drawn in AutoCAD because at this time the Parallax font does not permit the creation of logic gates and some other elements that need to be documented for our experiments.
104 Setting Up a 16-Character-by-2-Line Liquid Crystal Display
I understand that this deficiency is to be remedied in a future version of the chip and may well be in place by the time you read these words. Program 14-1 Implementation of LCD Use for Our Experiments (Listing of Methods Available within “LCDRoutines”) {{11 Sep 09 Harprit Sandhu LCDminimal.spin Propeller Tool Ver 1.2.6 Chapter 14 Program 1 PROGRAM TO BEGIN USING THE LCD A minimal LCD implementation to allow us to use the LCD in our experiments immediately. This program is an absolutely minimal implementation to make the LCD usable. You can work on improving it. We will improve it later. ┌────────────┐ │ ┌────────┐ │ │ │ ┌────┐ │ │ │ │ │ │ │ │ POWER ETC: ┌─────────-───-───────────────┴─┴─┴─┴─┴─┴┐ │ │ │ BASIC CONNECTIONS │ 1 0 9 8 7 6 5 4│3 X X G│3 2 1 0 9 8 7 6│ │ │ │ FOR THE EDUCATION │ │ │ │ │ │ │ KIT ARE STANDARD │ Propeller │ │ CHIP │ │ │ │ CONNECTIONS AND ARE │ 0 1 2 3 4 5 6 7│G B R 3│8 9 0 1 2 3 4 5│ │ │ │ NOT SHOWN HERE └─────────────────────────┬─┬─┬─┬─┬─┬─┬─┬┘ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ┌─────┼─┼─┼─┼─┼─┼─┼─┼────┼─┼─┘ │ ┌───┼─┼─┼─┼─┼─┼─┼─┼────┼─┘ 5VDC │ │ ┌─┼─┼─┼─┼─┼─┼─┼─┼────┘ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ┌──────────┳─┼─┐ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ┌────┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─────---------────┐ │ │ G 5 G S W E 0 1 2 3 4 5 6 7 │ │ │ ┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐ │ │ │ └─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘ │ │ │ ┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐ │ │ │ └─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘ │ │ └───────────────────────────────────────---------─┘ │ 16 CHAR BY 2 LINE LCD DISPLAY GND 8 BIT MODE Schematic
Revisions
(continued)
Setting Up a 16-Character-by-2-Line Liquid Crystal Display 105
Program 14-1 Implementation of LCD Use for Our Experiments (Listing of Methods Available within “LCDRoutines”) (continued) Pin assignments are assigned as constants because the pins are fixed. These numbers reflect the actual wiring on the board between the Propeller and the 16x2 LCD display. If you want the LCD on other lines, that would have to be specified here. We are going to use 8-bit mode to transfer data for now. All these numbers refer to lines on the Propeller. }} CON _CLKMODE=XTAL1 + PLL2X _XINFREQ = 5_000_000 RegSelect ReadWrite Enable DataBit0 DataBit7 waitPeriod high low
'The system clock spec 'the crystal frequency
= 16 = 17 = 18 = 8 = 15 =500_000 =1 =0
'set the wait period 'define the High state 'define the Low state
{{ Defining high and low states will allow us to invert these when we use buffers to amplify the output from the prop chip. We will then make low=1 and high=0 thus inverting all the values throughout the program. }} PUB Go DIRA[DataBit7..DataBit0]:=%11111111 DIRA[RegSelect] := High 'the DIRA[ReadWrite] := High 'the DIRA[Enable] := High 'the INITIALIZE_LCD waitcnt(1_000_000+cnt) CLEAR repeat 4 SEND_CHAR ("A") repeat 4 SEND_CHAR ("b") POSITION (1,2) repeat 4 SEND_CHAR ("C") repeat 4 SEND_CHAR ("d") repeat
'the lines for the LCD are outputs lines for the LCD are outputs lines for the LCD are outputs lines for the LCD are outputs
'initialize the LCD 'wait for LCD to start up 'clear the LCD 'print 4 'A's 'print 4 'a's 'move to POSITION: line 2, space 1 'print 4 'B's 'print 4 'b's 'this is a parking loop to keep the system 'from shutting down. It just loops here 'see what cursor does if it is omitted
(continued)
106 Setting Up a 16-Character-by-2-Line Liquid Crystal Display
Program 14-1 Implementation of LCD Use for Our Experiments (Listing of Methods Available within “LCDRoutines”) (continued) PRI INITIALIZE_LCD waitcnt(500_000+cnt)
'The addresses and data used here are 'specified in the Hitachi data sheet for 'display. YOU MUST CHECK THIS FOR YOURSELF OUTA[RegSelect] := Low 'these three lines are specified to write OUTA[ReadWrite] := Low 'the initial set up bits for the LCD OUTA[Enable] := Low 'See Hitachi HD44780 data sheet 'display. YOU MUST CHECK THIS FOR YOURSELF. SEND_INSTRUCTION (%0011_0000) 'Send 1st waitcnt(49_200+cnt) 'wait SEND_INSTRUCTION (%0011_0000) 'Send 2nd waitcnt(1_200+cnt) 'wait SEND_INSTRUCTION (%0011_0000) 'Send 3rd waitcnt(12_000+cnt) 'wait SEND_INSTRUCTION (%0011_1000) 'Sets DL=8 bits, N=2 lines, F=5x7 font SEND_INSTRUCTION (%0000_1111) 'Display on, Cursor on, Blink on SEND_INSTRUCTION (%0000_0001) 'clear LCD SEND_INSTRUCTION (%0000_0110) 'Move Cursor, Do not shift display
PUB CLEAR SEND_INSTRUCTION (%0000_0001)
'Clear the LCD display and go home
PUB POSITION (LINE_NUMBER, HOR_POSITION) | CHAR_LOCATION 'Pos crsr 'HOR_POSITION : Horizontal Position : 1 to 16 'LINE_NUMBER : Line Number : 1 or 2 CHAR_LOCATION := (HOR_POSITION-1) * 64 'figure location CHAR_LOCATION += (LINE_NUMBER-1) + 128 'figure location SEND_INSTRUCTION (CHAR_LOCATION) 'send the instr to position cursor PUB SEND_CHAR (DISPLAY_DATA) 'set up for writing to the display CHECK_BUSY 'wait for busy bit to clear before sending OUTA[ReadWrite] := Low 'Set up to read busy bit OUTA[RegSelect] := High 'Set up to read busy bit OUTA[Enable] := High 'Set up to toggle bit H>L OUTA[DataBit7..DataBit0] := DISPLAY_DATA 'Ready to SEND data in OUTA[Enable] := Low 'Toggle the bit H>L PUB CHECK_BUSY | BUSY_BIT 'routine to check busy bit OUTA[ReadWrite] := High 'Set to read the busy bit OUTA[RegSelect] := Low 'Set to read the busy bit DIRA[DataBit7..DataBit0] := %0000_0000 'Set the entire port to input REPEAT 'Keep doing it till clear OUTA[Enable] := High 'set to 1 to get ready to toggle H>L bit BUSY_BIT := INA[DataBit7] 'the busy bit is bit 7 of the byte read OUTA[Enable] := Low 'make the enable bit go low for H>L toggle WHILE (BUSY_BIT == 1) 'do it as long as the busy bit is 1 DIRA[DataBit7..DataBit0] := %1111_1111 'set the port back to outputs
(continued)
Setting Up a 16-Character-by-2-Line Liquid Crystal Display 107
Program 14-1 Implementation of LCD Use for Our Experiments (Listing of Methods Available within “LCDRoutines”) (continued) PUB SEND_INSTRUCTION (DISPLAY_DATA) 'set up for writing instructions CHECK_BUSY 'wait for busy bit to clear before sending OUTA[ReadWrite] := Low 'Set up to read busy bit OUTA[RegSelect] := Low 'Set up to read busy bit OUTA[Enable] := High 'Set up to toggle bit H>L OUTA[DataBit7..DataBit0] := DISPLAY_DATA 'Ready to READ data in OUTA[Enable] := Low 'Toggle the bit H>L
Program 14-1 will be improved upon, added to, and then broken up into its various methods as our skills improve. Once we have worked up a comprehensive set of methods, the methods will be placed in an object called LCDRoutines4, from where we will be able to call whatever method we need in any of the programs we develop. You do not have to worry about the details of this at this time. It will all be explained later in Chapter 21. The final versions of the programs LCDRoutines4 and Utilities are also listed in Appendix A. LCDRoutines4 is the 4-bit version of LCDRoutines. The Spin language is designed to allow the easy sharing of previously developed programs by third-party users. You are welcome to use any of the software developed in this book for use in any way you see fit as per the terms of the MIT license described in the preface of this book. You should also develop some expertise in using other objects in the object exchange maintained by Parallax so that you do not have to reinvent the wheel from time to time. Get familiar with the object exchange. It is a very useful resource for beginners.
This page intentionally left blank
15 Binary Input and Output: Reading a Switch and Turning on an LED if the Switch Is Closed
In any real-world situation, you’ll be reading inputs either as discrete single-line inputs or as resistances, frequencies, pulse widths, or similar signals. In this chapter, we will consider reading one external input as being either high or low. Because we need to know whether we have actually read the input successfully, we will turn an LED on if and only if the input is read as being low. We will define one pin as an input for the input signal and one pin as an output to turn on the LED. All the work in this program is being done in one cog, although in a parallel-processing environment we could assign the input to one cog and the output to another, as we will do in many of the following programs. First, let’s take a look at the program and then we will discuss what each part of the program is doing. For our purposes, the signal will go between a logical 0 and logical 1 at the Propeller input pin. For the Propeller with its CMOS circuitry, anything over half the 3.3 DC volts power (or 1.65 volts) is a seen as a high. The input impedance of the lines in the input state is so high that they tend to float and will drift between 0 and 1 if they are not connected to anything (when defined as inputs). You can observe this if you run a finger close to a free input line with a wire sticking in the air like an antenna. The stray capacitance (usually a positive charge) of your body provides enough current to switch the line to a high condition as you approach it. For us, this means that all input lines have to be tied high or low, with a high resistance when we use them as inputs (or defined as outputs and then made high or low). If you are going to pull the line low in your circuit to read it, tie it high with a 1 meg resistor, and if you are going to pull the line high to read it, tie it to ground with a 1 meg resistor. Keeping all this in mind, Figure 15-1 shows the circuit for reading a line that is connected to a switch that grounds it. 109
110 Binary Input and Output
Figure 15-1 Switch controls LED on line P27 by pulling line P23 low.
Note The power to drive the LED comes from the power to the 7404, not the Propeller. The 7404 inverts each signal it processes.
In Figure 15-1, we are using a buffer in the 7404 to drive the LED. We are using a 1 meg resistor to pull line P23 up to 5 volts. The current to the LED is limited by the 470 ohm resistor. The switch grounds line P23. This is pin 28 on the chip. The Spin language uses the internal numbers, never the external chip pin numbers. The code that runs the circuitry in Figure 15-1 is listed in Program 15-1. After you have studied it, we can discuss it. Program 15-1 Reading a Switch and Turning an LED on while the Switch Is Down
{{12 Sep 09 Harprit Sandhu ButtonLED.spin Propeller Tool 1.2.6 Chapter 15 Program 1 This program turns an LED ON if an input that has been pulled up is grounded It demonstrates the use of subroutines in an absolutely minimal way. First define the constants we will use. }} CON _CLKMODE=XTAL1+ PLL2X _XINFREQ = 5_000_000
'The system clock spec (continued)
Discussion 111
Program 15-1 Reading a Switch and Turning an LED on while the Switch Is Down (continued)
input_pin output_pin inv_high inv_low
=23 =27 =0 =1
'select 'select 'define 'define
the the the the
pin to be used for input pin to be used for the LED inverted High state inverted Low state
'High is defined as 0 and low is defined as a 1 because we are using an 'inverting buffer on the output PUB Go dira [output_pin]~~ 'sets pin to an output line with ~~ notation outa [output_pin]~ 'makes the pin a low output dira [input_pin]~ 'sets pin to an input line with the ~ notation repeat 'repeat forever because there is no number after repeat if ina[input_pin]==0 'check pin for high or low turnOn_LED 'subroutine call else turnOff_LED 'subroutine call PRI turnOn_LED 'subroutine to set the LED line high outa[output_pin] :=inv_high 'line that actually sets the LED high PRI turnOff_LED outa[output_pin] :=inv_low
'subroutine to set the LED line low 'line that actually sets the LED low
Discussion This is essentially how we read a switch into the Propeller chip when we need to. If we were looking at extremely fast phenomena, we would have to take measures to de-bounce the switch in either hardware or software to make sure we did not misinterpret its operation. We will not worry about that at this time, but you should be aware of the fact that switch bounce is a problem with mechanical switches. Mechanical switches are hundreds, even thousands of times slower than even slow microcontrollers. We defined all the constants at the top of the program. Defining constants allows you to make changes to the I/O line identifications and such with ease. When we do it in this way, any changes we make will be reflected throughout the program automatically. We define a high as 0 and a low as 1 in this program because we are using one of the inverting hex buffers in the 7404. These buffers turn a 0 into a 1 and a 1 into a 0, so we take care of this inversion in the software definitions. Note that this does not affect the input at the input pin because we are reading that directly (there is no intermediate buffer). As a rule, we can connect to high impedance inputs directly, unless we are dealing with high voltage, in which case special safety precautions must be undertaken.
112 Binary Input and Output
If you remove the pull-up register on the input line, you will notice that even putting an oscilloscope on the line will pull it down. As discussed previously, all input lines must be tied high or low if you want to prevent unexpected behavior.
The Repeat Command When no number appears after the repeat command, the indented lines under the repeat command are repeated endlessly. If there is a number, it defines how many times the lines are to be repeated. Note that we are using methods to perform simple tasks such as turning the LED on and off. Although not strictly necessary in this case, we are using methods to do even simple tasks now because in the long run this is the best way of doing it. We say it is “good practice.” It allows things that we do often to be made easy, and the methods themselves are easy to edit. The changes you make to a method will be reflected throughout all the objects you develop, automatically, if you use these programming techniques.
16 Reading a Potentiometer: Creating an Input We Can Vary in Real Time
Along with binary on/off switches, which provide a two-state input, we need to be able to enter information that we can vary with a rotating knob, so that we can see the effect of varying the inputs on our experiments. This is usually done with a potentiometer placed across a voltage. This being the case, we need to learn how to interact with such a voltage next. In this chapter we will learn how to read a potentiometer first into one byte (and later on with a resolution of 12 bits). One byte gives us a value between 0 and 255 for the full range of the potentiometer rotation. We can use this to control a variable with a resolution of approximately 0.39% (one part in 256). It is also possible to read a potentiometer into more than one byte; 12-bit analog-to-digital (A-to-D) converters provide an easy way to get much higher resolutions, and we will consider their use at the end of the chapter. Twelve bits provide a resolution of one part in 4,096, or 0.0244%. Note We will set up most of our experiments with the ability to use two variable inputs,
meaning that we will need the ability to read two potentiometers into our experiments. This will allow us to vary two variables in real time when we need to without having to change the experimental setup. We will not discuss a two-potentiometer setup in this chapter, but our experimental setups will have the ability to use two variable inputs. Reading the second potentiometer is similar to reading the first one.
One way to measure the resistance of a potentiometer without an A-to-D converter is to charge a capacitor to a known voltage and then discharge it through a resistor until it gets down to a known, specific voltage. The time it takes for the capacitor to discharge will be a function of the resistance of the potentiometer. The relationship is not strictly linear, but it is good enough for our immediate purposes. 113
114 Reading a Potentiometer: Creating an Input We Can Vary in Real Time
When a Propeller line is high, it is at 3.3 volts. It switches from high to low at half this voltage, or 1.65 volts. These two facts are the basis for the resistance determination. Our task is to measure the time it takes for the capacitor to go from 3.3 volts to 1.65 volts. We do this by connecting the capacitor to a line of the Propeller. In our program we are using line P19. By making this line an output (high) and waiting a few milliseconds, we charge the capacitor attached to it to 3.3 volts. We then turn the line into an input and turn on a timer immediately. We monitor the state of the input pin. As soon as it goes low (at 1.65 volts), we read the timer again. Because we know the speed of the oscillator, as well as the time it took for the voltage to drop to 1.65 volts, we can get a reading that is related to the value of the resistance. We read the counter twice, immediately after turning the line into an input and immediately after the line switches from high to low. The difference is related to the resistance. The lower the resistance, the lower the time difference. However, even at the lowest resistance it takes time for the various program instructions to execute. This minimum value has to be subtracted from the difference and represents the adjusted shortest time. The highest count read with the potentiometer at one extreme is divided by a number that produces a value of 255. The timer reading at the other extreme potentiometer position represents the various delays the execution of the program instructions create. This value has to be subtracted from the delay count to get the 0 value for the potentiometer. The value you pick for the capacitor should not be too small or too large. If it’s too small, you will not get a high enough count to allow a good reading on the potentiometer. It will be too coarse. If too large a value is picked, the conversion will take too long. I used a 10K potentiometer and a 10 mfd (micro farad) capacitor with the circuitry shown in Figure 16-1 for Program 16-1.
Analog Inputs Reading a Potentiometer Assume that we will use a potentiometer with a maximum value of 10K ohms for this experiment. We will use the potentiometer as a voltage divider and read the voltage at the wiper. The voltage represents the analog value we are interested in. For our first exercise, let’s take a look at what we would need to be able to take the potentiometer reading with the Propeller chip (see Figure 16-1). In order to do this, we have to set up a simple circuit to charge and then discharge a capacitor. We determine the reading of the potentiometer from the information received from the circuit. Looking at the pin with an oscillo- Figure 16-1 Circuitry for scope as we take the readings is very instructive. The reading a potentiometer next section explains this further. with a Propeller chip
Analog Inputs 115
The Details If we charge a capacitor to an arbitrary voltage and then slowly discharge it through a resistor across the capacitor, the time that it takes for the voltage to come down to any specific voltage from the full-charge voltage will be a function of the resistance through which the charge on the capacitor is being drained and the voltage driving the reaction. The apparatus is attached to a port of the Propeller that has been configured to be an output and then set high. In a few moments, this will charge the capacitor to the voltage that the microprocessor provides as the high signal on an output line (3.3 volts DC for the Propeller). Once the capacitor is fully charged, the port is turned into an input, a timer is started, and the system is programmed to monitor the state of the port as the capacitor discharges. As expected, initially the input port will be read as being high. As the capacitor is discharged by the potentiometer, a point will be reached when the port will be read as being low. How soon this happens depends on the resistance that the potentiometer is set to. If we measure the high-to-low time interval with the timer we started, the interval will be a function of the resistance of the potentiometer. This phenomena is used to determine the value of the potentiometer setting. We can assume that if the potentiometer is set to 0 ohms, the capacitor will discharge immediately and the timer will indicate a 0 time interval. If, on the other hand, we set the potentiometer to its maximum resistance, which in our case is 10K ohms, the time of discharge will represent the maximum resistance of the potentiometer. All other values are represented by times between 0 and the maximum time. The relationship is not perfectly linear, but it’s linear enough for all practical purposes. For our immediate needs we can consider it to be linear. This is expressed graphically in Figure 16-2. For the sake of technical correctness, the rate at which a capacitor charges and discharges is more accurately represented in Figure 16-3. We can assume a linear relationship because we are seeing a very tiny portion of this curve in our experiment, and for all practical purposes this tiny portion can be looked at as a straight line. We can convert the relationship we have observed to provide a value of between 0 and 255 if we are interested in an 8-bit representation of the resistance of the potentiometer. The value of the capacitor we choose to charge is not critical, but too small a capacitor
Figure 16-2 Graphic of resistance vs. time to discharge
Figure 16-3 Theoretical charging and discharging of a capacitor
116 Reading a Potentiometer: Creating an Input We Can Vary in Real Time
will give us insufficient time for the signals to settle down and too large a capacitor will take too long to discharge. In our particular case, a capacitor of 10 micro farads will give us an answer well within 0.01 seconds. This is fast enough for most purposes. Program 16-1 shows how the potentiometer was read, converted to an 8-bit value, and displayed on the LCD. Program 16-1 Reading a Potentiometer
{{Aug 31 09 Harprit Sandhu ReadPot.spin Propeller Tool Version 1.2.6 Chapter 16 Program 1 READING A POTENTIOMETER This routine reads a 10K pot with a 10 mfd cap. This routine is what is used in the utilities to read the pot. Pot is always read from the same line. }} CON _CLKMODE=XTAL1+ PLL2X _XINFREQ = 5_000_000 PotLine = 19 OBJ LCD : "LCDRoutines4" VAR long long long long
startCnt endCount delay PotValue
'The system clock spec 'Crystal spec 'line the pot it on
'We will be using these METHODS in this program 'these are the variables we will use. 'count at start 'count at end 'time difference 'Value of the pot reading
PUB Go LCD.INITIALIZE_LCD 'set up the LCD repeat 'loop dira[PotLine]~~ 'set potline as output outa[PotLine]~~ 'make it high so we can charge the capacitor waitcnt(4000+cnt) 'wait for the capacitor to get charged dira[PotLine]~ 'make potline an input. line switches H>L startCnt:=cnt 'read the counter at start of cycle and store repeat 'go into an endless loop while ina[PotLine]~~ 'keep doing it as long as the potline is high EndCount := cnt 'read the counter at end of cycle and store delay := ((EndCount-StartCnt)-1184) 'calc time for line to go H>L if delay>630000 'max permitted delay delay:=630000 'clamp delay (continued)
Analog Inputs 117
Program 16-1 Reading a Potentiometer (continued)
PotValue:=(delay/2220) 'This reduces the value to 0-255 or 1 byte PotValue L if delay>610_000 'max permitted delay delay:=610_000 'clamp delay PotValue:=(delay/2300) 'Reduces value to 0-255 or 1 byte valutotal:=valutotal+potvalue 'figures total potvalue:=valutotal/repval 'figure average potvalue =0 result:=PotValue 'figure average
118 Reading a Potentiometer: Creating an Input We Can Vary in Real Time
Figure 16-4 Complete circuitry for reading a potentiometer
We will not use the technique developed in these programs to read a potentiometer once this technique has been demonstrated. Instead, we will use an A-to-D converter to read the potentiometer(s). This A-to-D converter reads the potentiometers with a resolution of 12 bits to give us a reading between 0 and 4,095. This higher resolution is much more flexible for our purposes and will be used in all the following developments, as detailed next.
Advanced Techniques Using the MCP3202/MCP3208 Family of A-to-D Converters There are times when we need to get really serious about reading in a variable to a high resolution. If the variable can be expressed as a voltage between 0 and 5 volts, it can be read into the Propeller to a resolution of 12 bits with a chip identified as the MCP3202. (The 3208 is an eight-line version of the 3202.) This chip allows us to read a channel very rapidly, at 100,000 cycles per second (cps), and is available in versions that read two, four, and eight channels. It is a single-wire device. All these chips need a four-wire interface that meets the Serial Peripheral Interface (SPI) standard (go to the Internet to read more on the SPI standard).
Advanced Techniques 119
The MCP3202 and MCP3208 are shown in Figure 16-5. Chips that read more than two channels need to have more pins to accommodate the additional channels. Before you consider using the MCP3202 or the MCP3208 in any of your projects, download the data sheet to see if you can figure out what needs to be done to use the chip on your own. This is a particularly good opportunity to get familiar with data sheets because this is a simple chip that is relatively easy to understand and interface to. This ideal first-time opportunity should not be wasted by us beginners. I will go Figure 16-5 The MCP3202 and MCP over the details, but I strongly recommend that you try figur3208 pinouts ing it all out on your own to gain learning experience and confidence. Because the chip follows the SPI standard for serial peripheral chips, we talk to it in a serial format, as specified in the data sheet. Here is what we have to do: 1. Get the wiring in place, as shown in Figure 16-7, later in this chapter. 2. Select the chip to make it active. This is done by pulling the Chip select line low
from a high condition. If it is starting up in a low state, you have to make it high and then low to activate the startup sequence. 3. Tell the chip what mode we want to use it in. Four bits have to be either set or cleared. The four bits are toggled in one after the other and they specify the following conditions: a. To get going, we send the DataIn line a high “start bit.” b. Next, we specify whether we are using single or differential mode. c. We need to specify which channel we want to use. d. We need to specify whether we want the LSB or the MSB read first. Once this has been done, we are ready to read in the information to a variable that will store what we read. After receiving these bits, the 3202 sends out a low (null) bit. We read it and discard it. The next 12 bits are the data we are interested in. Here’s what happens: 1. Each bit is read in by making the clock go high to low. 2. Each time the clock goes low, the next bit of data becomes ready on the DataOut
line. 3. We read the data into our variable. 4. We shift the bits in our variable left by one bit to make room for the next bit to be
read in. 5. We then make the clock go high and then low, and the next bit becomes ready to
read in. 6. We have to do all this 12 times to get all the 12 bits read in.
120 Reading a Potentiometer: Creating an Input We Can Vary in Real Time
The detailed code for reading the 3202 is shown in Program 16-3. This particular program also serves as an example of full documentation and line-by-line commenting. Program 16-3 Reading the MCP3202 Analog-to-Digital Chip to a 12-Bit Resolution
{{03 Nov 09 Harprit Sandhu MCP3202Read1.Spin Propeller Tool 1.2.6 Chapter 16 Program 3 All the code in this program is in Spin. This program reads channel 0 of the MCP3202 and displays the results on the LCD both as a decimal value and as a binary value so that you can see the bits flip as you turn the potentiometer. The 3202 chip is connected as follows: 1 Chip select 2 Channel 0 for voltage input from Pot 3 Channel 1 for voltage input from Pot, not used 4 Ground Vss 5 Data into 3202 for setup 6 Data out from 3202 to be read into Propeller 7 Clock to read in the data 8 Power 5 volts Vdd
P21 Pot wiper Ground it Ground P19 P22 P20 5 volts
The Potentiometer is connected as follows: Left Ground Center To pin 2 of the 3202 Right Power 5 volts I used a 50K Pot The 1 2 3 4 5 6 7 8 9 10 11 12 13 14
connections to the LCD Ground Power 5 volts Ground P16 P17 P18 Not connected, using 4 Not connected, using 4 Not connected, using 4 Not connected, using 4 Data high nibble Data high nibble Data high nibble Data high nibble
are as follows:
bit bit bit bit
mode mode mode mode
for for for for
data data data data
Xfer Xfer Xfer Xfer
(continued)
Advanced Techniques 121
Program 16-3 Reading the MCP3202 Analog-to-Digital Chip to a 12-Bit Resolution (continued)
STANDARD EDUCATION KIT SET UP.
Used as base
Revisions: Error Reporting: Please report errors to [email protected] }} OBJ LCD
: "LCDRoutines4" 'for the LCD methods
CON _CLKMODE=XTAL1+ PLL2X _XINFREQ = 5_000_000 BitsRead =12 chipSel = 19 chipClk = chipSel+1 chipDout = chipSel+2 chipDin = chipSel+3
'The system clock spec 'crystal spec
VAR long stack2[25] word PotReading word DataRead PUB Go cognew(Cog_LCD, @stack2) DIRA[0..7]~ DIRA[chipSel]~~ 'osc once to set up 3202 DIRA[chipDin]~~ 'data set up to the chip DIRA[chipDout]~ 'data from the chip to the Propeller DIRA[chipClk]~~ 'oscillates to read in data from internals repeat DataRead:=0 'Clear out old data outa[chipSel]~~ 'Chip select has to be high to start off outa[chipSel]~ 'Go low to start process outa[chipClk]~ outa[chipDin]~~ outa[chipClk]~~
'Clock MUST be low to load data 'must start with Din high to set up 3202 'Clock high to read data in
outa[chipClk]~ outa[chipDin]~~ outa[chipClk]~~
'Low to load 'High single mode 'High to read (continued)
122 Reading a Potentiometer: Creating an Input We Can Vary in Real Time
Program 16-3 Reading the MCP3202 Analog-to-Digital Chip to a 12-Bit Resolution (continued)
outa[chipClk]~ outa[chipDin]~ outa[chipClk]~~
'Low to load 'Odd = low channel 0 'High to read
outa[chipClk]~ outa[chipDin]~~ outa[chipClk]~~
'Low to load 'MSBF high = MSB first 'High to read
outa[chipDin]~ outa[chipClk]~ outa[chipClk]~~
'making line low for rest of cycle 'Low to load Read/discard the null bit 'High to read
repeat BitsRead DataRead L this bit BUSY_BIT := INA[DataBit7] 'the busy bit is bit 7 OUTA[Enable] := 0 'enable bit low = H>L toggle WHILE (BUSY_BIT == 1) 'do it as long as the busy bit is 1 DIRA[DataBit7..DataBit0] := %1111_1111 'done, port bck to output
Send Character Once we have positioned the cursor, we are ready to send the alphanumeric data we want to display to the LCD. The LCD is prepared for data reception by setting the three control lines as shown in Program 21-5. Each time the Enable line is toggled, the data on the bus is transferred to the LCD. The data must be sent a byte at a time. Program 21-5 Code Segment to Send a Single Character to the LCD
PRI SEND_CHAR (DISPLAY_DATA) 'set up for writing to the display CHECK_BUSY 'wait for busy bit to clear before sending OUTA[ReadWrite] := 0 'Set up to read busy bit OUTA[RegSelect] := 1 'Set up to read busy bit OUTA[Enable] := 1 'Set up to toggle bit H>L OUTA[DataBit7..DataBit0] := DISPLAY_DATA 'Ready to SEND data in OUTA[Enable] := 0 'Toggle the bit H>L
Send Instruction We also need to be able to send the LCD non-alphanumeric instructions. This is similar to the character routine and is shown in Program 21-6. Program 21-6 Code Segment to Send an Instruction to the LCD
PRI SEND_INSTRUCTION (DISPLAY_DATA) 'set up for writing instructions CHECK_BUSY 'wait for busy bit to clear OUTA[ReadWrite] := 0 'Set up to read busy bit OUTA[RegSelect] := 0 'Set up to read busy bit OUTA[Enable] := 1 'Set up to toggle bit H>L OUTA[DataBit7..DataBit0] := DISPLAY_DATA 'Ready to READ data in OUTA[Enable] := 0 'Toggle the bit H>L
168 Understanding a 16-Character-by-2-Line LCD Display
At this time, all these methods are defined as being private to this object. Later on we will make them public, and any method in another procedure will be able to call and use them. When we combine all the preceding code into a program, we get the listing in Program 21-7. Program 21-7 Minimal Program to Send Characters to the LCD
{{11 Sep 09 Harprit Sandhu LCDminimal.spin Propeller Tool Ver 1.2.6 Chapter 21 Program 7 PROGRAM TO BEGIN USING THE LCD A minimal LCD implementation to allow us to use the LCD in our experiments immediately. This program is an absolutely minimal implementation to make the LCD usable. You can work on improving it. ┌────────────┐ │ ┌────────┐ │ │ │ ┌────┐ │ │ │ │ │ │ │ │ POWER ETC: ┌─────────-───-───────────────┴─┴─┴─┴─┴─┴┐ │ │ │ BASIC CONNECTIONS │ 1 0 9 8 7 6 5 4│3 X X G│3 2 1 0 9 8 7 6│ │ │ │ FOR THE EDUCATION │ │ │ │ │ │ │ KIT ARE STANDARD │ PROPELLER │ │ CHIP │ │ │ │ CONNECTIONS AND ARE │ 0 1 2 3 4 5 6 7│G B R 3│8 9 0 1 2 3 4 5│ │ │ │ NOT SHOWN HERE └─────────────────────────┬─┬─┬─┬─┬─┬─┬─┬┘ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ┌─────┼─┼─┼─┼─┼─┼─┼─┼────┼─┼─┘ │ ┌───┼─┼─┼─┼─┼─┼─┼─┼────┼─┘ 5VDC │ │ ┌─┼─┼─┼─┼─┼─┼─┼─┼────┘ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ┌──────────┳─┼─┐ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ┌────┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─────---│ │ G 5 G S W E 0 1 2 3 4 5 6 7 │ │ ┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─ │ │ └─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─ │ │ ┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─ │ │ └─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─ │ └───────────────────────────────────────│ 16 CHAR BY 2 LINE LCD DISPLAY GND 8 BIT MODE (continued) Schematic
8-bit Mode 169
Program 21-7 Minimal Program to Send Characters to the LCD (continued)
Revisions
}} CON {{ Pin assignments are assigned as constants because the pins are fixed. These numbers reflect the actual wiring on the board between the Propeller and the 16x2 LCD display. If you want the LCD on other lines, that would have to be specified here. We are going to use 8-bit mode to transfer data. All these numbers refer to lines on the Propeller. }} _CLKMODE=XTAL1 + PLL2X _XINFREQ = 5_000_000 RegSelect ReadWrite Enable DataBit0 DataBit7 waitPeriod high low
= 16 = 17 = 18 = 8 = 15 =500_000 =1 =0
'The system clock spec 'the oscillator frequency
'set the wait period in Milliseconds 'define the High state 'define the Low state
{{ Defining high and low states will allow us to invert these when we use buffers to amplify the output from the prop chip. We will then make low=1 and high=0 thus inverting all the values throughout the program }} PUB Go DIRA[DataBit7..DataBit0]:=%11111111 DIRA[RegSelect] := High 'the DIRA[ReadWrite] := High 'the DIRA[Enable] := High 'the INITIALIZE_LCD waitcnt(5_000_000+cnt) CLEAR repeat clear repeat 4 SEND_CHAR ("A")
'the lines for the LCD are outputs lines for the LCD are outputs lines for the LCD are outputs lines for the LCD are outputs
'initialize the LCD 'wait for LCD to start up 'clear the LCD 'repeat forever 'print 4 'A's (continued)
170 Understanding a 16-Character-by-2-Line LCD Display
Program 21-7 Minimal Program to Send Characters to the LCD (continued)
repeat 4 SEND_CHAR ("b") POSITION (1,2) repeat 4 SEND_CHAR ("C") repeat 4 SEND_CHAR ("d") waitcnt(10_000_000+cnt)
'print 4 'a's 'move to POSITION: line 2, space 1 'print 4 'B's 'print 4 'b's
PRI INITIALIZE_LCD waitcnt(500_000+cnt)
'The addresses and data used here are 'specified in the Hitachi data sheet for 'display. YOU MUST CHECK THIS FOR YOURSELF OUTA[RegSelect] := Low 'these three lines are specified to write OUTA[ReadWrite] := Low 'the initial set up bits for the LCD OUTA[Enable] := Low 'See Hitachi HD44780 data sheet 'YOU MUST CHECK THIS FOR YOURSELF. SEND_INSTRUCTION (%0011_0000) 'Send 1st waitcnt(49_200+cnt) 'wait SEND_INSTRUCTION (%0011_0000) 'Send 2nd waitcnt(1_200+cnt) 'wait SEND_INSTRUCTION (%0011_0000) 'Send 3rd waitcnt(12_000+cnt) 'wait SEND_INSTRUCTION (%0011_1000) 'Sets DL=8 bits, N=2 lines, F=5x7 font SEND_INSTRUCTION (%0000_1111) 'Display on, Cursor on, Blink on SEND_INSTRUCTION (%0000_0001) 'clear LCD SEND_INSTRUCTION (%0000_0110) 'Move Cursor, Do not shift display
PUB CLEAR SEND_INSTRUCTION (%0000_0001)
'Clear the LCD display and go home
PUB POSITION (LINE_NUMBER, HOR_POSITION) | CHAR_LOCATION 'Pos crsr 'HOR_POSITION : Horizontal Position : 1 to 16 'LINE_NUMBER : Line Number : 1 or 2 CHAR_LOCATION := (HOR_POSITION-1) * 64 'figure location CHAR_LOCATION += (LINE_NUMBER-1) + 128 'figure location SEND_INSTRUCTION (CHAR_LOCATION) 'send the instr to position cursor PUB SEND_CHAR (DISPLAY_DATA) 'set up for writing to the display CHECK_BUSY 'wait for busy bit to clear before sending OUTA[ReadWrite] := Low 'Set up to read busy bit OUTA[RegSelect] := High 'Set up to read busy bit OUTA[Enable] := High 'Set up to toggle bit H>L OUTA[DataBit7..DataBit0] := DISPLAY_DATA 'Ready to SEND data in OUTA[Enable] := Low 'Toggle the bit H>L (continued)
Sophisticated Total LCD Control 171
Program 21-7 Minimal Program to Send Characters to the LCD (continued)
PUB CHECK_BUSY | BUSY_BIT 'routine to check busy bit OUTA[ReadWrite] := High 'Set to read the busy bit OUTA[RegSelect] := Low 'Set to read the busy bit DIRA[DataBit7..DataBit0] := %0000_0000 REPEAT 'Keep doing it till clear OUTA[Enable] := High 's get ready to toggle H>L this bit BUSY_BIT := INA[DataBit7] 'the busy bit is bit 7 of the byte read OUTA[Enable] := Low 'make the enable bit go low for H>L toggle WHILE (BUSY_BIT == 1) 'do it as long as the busy bit is 1 DIRA[DataBit7..DataBit0] := %1111_1111 PUB SEND_INSTRUCTION (DISPLAY_DATA) 'set up for writing instructions CHECK_BUSY 'wait for busy bit to clear before sending OUTA[ReadWrite] := Low 'Set up to read busy bit OUTA[RegSelect] := Low 'Set up to read busy bit OUTA[Enable] := High 'Set up to toggle bit H>L OUTA[DataBit7..DataBit0] := DISPLAY_DATA 'Ready to READ data in OUTA[Enable] := Low 'Toggle the bit H>L
Sophisticated Total LCD Control Now that we have an understanding of how to go about addressing the LCD, we can improve the routines that were created to make them more sophisticated and thus more useful. After we are done with the improvements, we will assign these methods to a separate file from where they can be called by all users and by all the procedures we create. This means that we will not have to include the methods as a part of our other programs. We will call these methods as we need them by including the relevant mother objects under the OBJ declaration in our programs. The new (8-bit) program, which lists all the new methods, is shown in Program 21-8. Program 21-8 Comprehensive LCD Control (Demonstration)
{{11 Sep 09 Harprit Sandhu LCDminimal2.spin Propeller Tool Ver 1.2.6 Chapter 21 Program 8 LCD control.
Comprehensive.
Here are the improvements to program Can now send DECIMAL values to the LCD Can now send HEX values to the LCD Can now send BINARY values to the LCD (continued)
172 Understanding a 16-Character-by-2-Line LCD Display
Program 21-8 Comprehensive LCD Control (Demonstration) (continued)
Delays in the print routines have been eliminated to speed things up. The output blinks "Hello world" and 1234567890"on the two lines. }} CON _CLKMODE=XTAL1 + PLL2X _XINFREQ = 5_000_000 DataBit0 = 8 DataBit7 = 15 RegSelect = 16 ReadWrite = 17 Enable = 18 waitPeriod =5_000_000 high =1 low =0
'The system clock spec 'the oscillator frequency 'Data uses 8 bits from 'lines 8 to 15 'The three control lines, register select 'Read Write and 'Enable line 'set the wait period, about 1/2 sec 'define the High state 'define the Low state
VAR long index long char_index
'used to count the chars in the string 'used to count the chars in the string
PUB START DIRA[16..18]~~ 'set these 8 lines to outputs INITIALIZE_LCD 'this initializes LCD DIRA[DataBit7..DataBit0] := %1111_1111 '11 lines LCD as outputs DIRA[RegSelect] := 1 'select the register for the LCD DIRA[ReadWrite] := 1 'set to write DIRA[Enable] := 1 'enable operation repeat 'this loops forever initialize_lcd 'init the LCD waitCnt(waitPeriod + cnt) 'wait to see it clear position (1,1) ' go to pos 1,1 PRINT(string("Hello world")) 'display text message POSITION (2, 1) 'pos to line 2 position 1 PRINT_DEC (1234567890) 'print the number waitCnt(waitPeriod + cnt) 'wait before looping PRI INITIALIZE_LCD waitcnt(500_000+cnt) OUTA[RegSelect] := 0 OUTA[ReadWrite] := 0 OUTA[Enable] := 0 SEND_INSTRUCTION (%0011_1000) SEND_INSTRUCTION (%0000_0001) SEND_INSTRUCTION (%0000_1100)
'The addresses and data used here are 'specified in the Hitachi data sheet for the 'display. YOU MUST CHECK THIS FOR YOURSELF. 'three lines are specified so we can write 'the initial set up bits for the LCD 'See Hitachi HD44780 data sheet 'Sets DL=8 bits, N=2 lines, F=5x7 font 'clears the LCD 'Display on, Cursor off, Blink off (continued)
Sophisticated Total LCD Control 173
Program 21-8 Comprehensive LCD Control (Demonstration) (continued)
SEND_INSTRUCTION (%0000_0110) 'Move Cursor, Do not shift display {this blank line ends this method} PRI CLEAR 'Clear the LCD display and go home SEND_INSTRUCTION (%0000_0001) ' clear screen, go home command {this blank line ends this method} PRI PRINT (the_line)
'routine handles more Chars at a time 'called as PRINT(string("the_line")) " 'the line" contains the pointer to the line. 'because we have to point to the line 'zero terminated but we will not use that. 'We will use the string size instead. 'This was is easier to understand index:=0 'Reset the counter to count chars sent repeat 'repeat for all chars in the list char_index:= byte[the_line][index++] 'contains the char/byte 'pointed to by the index SEND_CHAR (char_index) ' 'pointed to' char to the LCD while indexL OUTA[DataBit7..DataBit0] := DISPLAY_DATA 'Ready to READ data in OUTA[Enable] := 0 'Toggle the bit H>L PRI PRINT_DEC (VALUE) | TEST_VALUE IF (VALUE < 0) -VALUE SEND_CHAR("-") TEST_VALUE := 1_000_000_000
'for print vals in deci format 'if it is a negative value 'change it to a positive 'and print a - sign on the LCD 'we comp to this 'value REPEAT 10 'There are 10 digits maximum IF (VALUE => TEST_VALUE) 'see if our num > than testValue SEND_CHAR(VALUE / TEST_VALUE + "0") ' divide to get the digit VALUE //= TEST_VALUE 'figure for the nxt digit RESULT~~ 'result so we can pass it on ELSEIF (RESULT OR TEST_VALUE == 1) 'then division was even SEND_CHAR("0") 'so we sent out a zero TEST_VALUE /= 10 ' test the next digit
PRI PRINT_HEX (VALUE, DIGITS) VALUE L := D_DATA 'Ready to READ data in 'Toggle the bit H>L to Xfer the data
{{Sends a single character to the LCD in two halves }} PUB SEND_CHAR (D_CHAR) 'set up for writing to the display CHECK_BUSY 'wait for busy bit to clear before sending OUTA[ReadWrite] := 0 'Set up to send data OUTA[RegSelect] := 1 'Set up to send data OUTA[Enable] := 1 'go high OUTA[DataBit7..DataBit4] := D_CHAR>>4 'Send high 4 bits OUTA[Enable] := 0 'Toggle the bit H>L OUTA[Enable] := 1 'go high again OUTA[DataBit7..DataBit4] :=D_CHAR 'send low 4 bits OUTA[Enable] := 0 'Toggle the bit H>L {{Print a line of characters to the LCD uses variables index and temp }} PUB PRINT (the_line) 'This routine handles more than one Char at a time 'called as PRINT(string("the_line")) '"the_line" contains the pointer to line. Line is 'because we have to point to the line 'zero terminated but we will not use that. We will 'use the string size instead. Easier to understand index:=0 'Reset the counter we are using to count chars sent repeat 'repeat for all chars in the list temp:= byte[the_line][index++] 'temp contns char pointed by index SEND_CHAR (temp) 'send the 'pointed to' char to the LCD while index TEST_VALUE) 'see if our number is > than testValue SEND_CHAR(VALUE / TEST_VALUE + "0") 'divide to get the digit VALUE //= TEST_VALUE 'figure the next value for the next digit RESULT~~ 'result of what just did pass it on below ELSEIF (RESULT OR TEST_VALUE == 1) ' a 1 then div was even SEND_CHAR("0") 'so we sent out a zero TEST_VALUE /= 10 ' test for the next digit {{Print a Hexadecimal value }} PUB PRINT_HEX (VALUE, DIGITS) 'for printing values in HEX format VALUE divmax 'check div divider:=divmax 'clamp div outa[2..7]:=%011_010 'on off waitcnt(clkfreq/divider+cnt) ' outa[2..7]:=%100_001 'off on waitcnt(clkfreq/divider+cnt) ' outa[2..7]:=%010_010 'rev off waitcnt(clkfreq/divider+cnt) ' outa[2..7]:=%100_101 'off rev waitcnt(clkfreq/divider+cnt) divider:=divstart 'reset divider waitcnt(clkfreq/8+cnt)
The techniques that have been demonstrated can be combined with one another to provide the stepper control you would need for almost any application. The keys are proper motor selection and proper ramping. And making sure the system never stalls or slips.
This page intentionally left blank
27 Gravity Sensor Based Auto-Leveling Table
The simplest of construction is adequate for our purposes. The important thing is that you actually build a table. My table was made with cardboard and hot glue and bamboo skewers for the bearing shafts. In this project, we will use the Memsic 2125 (which was covered in Chapter 18) to build a table that stays horizontal while the base of the table is disturbed (within about 20 degrees) relative to the horizon.
Figure 27-1 An artificial horizon—a basic unadorned cardboard horizontal table with two plastic levels and a Memsic 2125 sensor 247
248 Gravity Sensor Based Auto-Leveling Table
Sensor Specifications Here is more detailed information about the Memsic accelerometer (from Parallax): “The Memsic 2125 is a low-cost, dual-axis thermal accelerometer capable of measuring dynamic acceleration (vibration) and static acceleration (gravity) with a range of ±2 g. For integration into existing applications, the Memsic 2125 is electrically compatible with other popular accelerometers.” Key features of the Memsic 2125 include the following: ■ Measure 0 to ±2 g on either axis; less than 1 mg resolution ■ Fully temperature compensated over 0°C to 70°C range ■ Simple, pulse output of G-force for X and Y axes ■ Analog output of temperature (T-Out pin) ■ Low current operation: less than 4 mA at 5 VDC
A sampling of possible BASIC Stamp module applications with the Memsic 2125 include: ■ Dual-axis tilt sensing for autonomous robotics applications ■ Single-axis rotational position sensing ■ Movement/lack-of-movement sensing for alarm systems ■ R/C hobby projects such as autopilots
Memsic (www.memsic.com) provides the 2125 in a surface-mount format. Parallax mounts the circuit on a PC board providing all I/O connections, so it can easily be inserted on a breadboard or through-hole prototype area. The actuators we use to move the table for horizontal position correction will be two radio control hobby servos.
Discussion We can mount the sensor to correct the tilt in two locations: We can mount the sensor on the base that is being tilted, or we can mount the sensor on the actual table that we want to keep level. If we mount the sensor on the base we will be tilting, we get error signals that we can interpret to make corrections to the target table position. We may have to create a lookup table if there is any nonlinearity either in the response of the sensor or in the mechanical linkages that connect the base to the top. In this case, the signal that we detect is absolutely related to the position of the base, meaning that we are reading the actual error at the base. What we do with the signal is up to us, and how we design the linkages to level the table is up to us. This is not the best method to use in most cases, but this may be the only way available to us in some situations.
Discussion 249
If we mount the sensor to the table top itself, the signal we get will be a measure of how far the table has tilted. We can make the table come back to horizontal if we keep making a correction until the table becomes horizontal, and we stop when the error signal goes to zero. It is a process integrated over time. (If we wanted to know how large the correction was, we would have to keep track of how far we had moved the table to get it back to horizontal, but we do not need this information in an integrating system.) We could also relate the error signal directly to the amount of correction needed and bring the table back to level in that way, but the bookkeeping required to do that is complicated. Simply stated, it is better to mount the detector to the actual tabletop because that is the surface we are interested in keeping level. As a general rule, the closer the sensor is to the actual error-signal-creating element, the easier it will be to know what the error signal means and the easier it will be to make a correction.
Setting Up the Hardware Connections The system we will create needs to read two inputs from the sensor and output two outputs, one to each servo. The inputs are in the form of two pulse widths that we will read from the X-Out and Y-Out connectors of the sensor, and our outputs from the Propeller are the two 1- to 2-millisecond pulses we will send to the radio control hobby servos 60 times a second. See Figure 27-2 for wiring details. Note There are four wires between the sensor and the system, and both sides of Memsic must be grounded.
We investigated the Memsic in Chapter 18. Review that chapter now if you need to. We will base our software in this chapter on the software created in Chapter 18, with additions and modifications. The Memsic puts out a fixed-frequency pulse with a variable duty cycle. On my sensor, I received a wave length of almost exactly 100,000 cycles, which is a frequency of
Figure 27-2 Wiring diagram for the table: connecting to the Memsic accelerometer to two servos
250 Gravity Sensor Based Auto-Leveling Table
100 Hz. At level, the duty cycle of the PWM signal was 50%, or 50,000 cycles. (As always, my system was running at 10 MHz.) The Futaba-compatible servos we are using require a center position pulse of 1,520 microseconds bracketed with a range of + or –750 microseconds (you have to check this on your specific servos). At 10 MHz, this is 15,200 + or –7,500 cycles. Here’s the equation for converting what we read into what the servos need: Output pulse length = 1,520 + (reading – 50,000)/10 microseconds We can implement these conditions with the following pseudocode for the operation of one of the axes on the table (you can expand it for full two-axis operation when you build your table): Initialize the system. Define all parameters and lines to be used. Read the X axis on the Memsic sensor. Compare it to the horizontal position. CASE If it is positive, move in the negative direction one step. If there is no error, do nothing. If it is negative, move in the positive direction one step. Repeat to read sensor. Advanced Options If you want to be able to adjust the position of the table with
respect to the true horizon, you can add two potentiometers to the hardware to act as final correction inputs. You may want to use the LCD to provide information about the conditions in the system during development and later to annunciate the system status.
The software that implements single-axis operation defined by the pseudocode is described in Program 27-1. Program 27-1 Program for Single-Axis Correction to Horizon Table
{{04 Jan 10 Harprit Sandhu MemsicTable.spin Propeller Tool Ver 1.2.6 Program 27-1 This program keeps the table horizontal in one direction. Both servos are connected but one is implemented. It uses a Memsic 2125 sensor and two R/C servos. COG_LCD manages the LCD output COG_0 measures the pulse COG_1 manages the servo }}
(continued)
Discussion 251
Program 27-1 Program for Single-Axis Correction to Horizon Table (continued)
CON _CLKMODE=XTAL1+ PLL2X _XINFREQ = 5_000_000 Xaxis Yaxis
= 26 = 27
'The system clock spec 'crystal frequency 'from Memsic 'for speaker
chipSel chipClk chipDout chipDin
= = = =
servo servo2
= 23 = 24
'to servo signal 'to servo2 signal
Stack[50] Stack1[50] startWave endPulse endWave PulseLen waveLen frequency servoPos
'FOR LCD COG 'FOR SERVO COG ' ' ' ' ' ' '
VAR long long long long long long long long long
19 chipSel+1 chipSel+2 chipSel+3
OBJ LCD : "LCDRoutines4" UTIL : "Utilities"
'for pots ' ' '
'These are the Objects we will need 'for controlling the LCD 'for general methods collection
PUB go cognew (COG_LCD, @Stack) cognew (SERVO1, @Stack1) DIRA[25]~ repeat repeat while ina[xaxis]==1 repeat while ina[xaxis]==0 startWave:=cnt repeat while ina[xaxis]==1 endPulse:=cnt repeat while ina[xaxis]==0 endWave:=cnt PulseLen:=endPulse-startWave waveLen:=endWave-startWave frequency:=clkfreq/waveLen
'Cog_0 'starting up Cog LCD 'starting up Cog OUT 'Make pin input 'Set up the control read loop 'wait for line 1 to go hi. See Manual 'wait for line 1 to go low. Manual 'read the timer count 'wait for line 1 to go hi. See Manual 'read the timer count for second time 'wait for line 1 to go low. Manual. 'end of wave cycle 'figure the pulse 'figure the wave Len 'figure the freq (continued)
252 Gravity Sensor Based Auto-Leveling Table
Program 27-1 Program for Single-Axis Correction to Horizon Table (continued)
PRI COG_LCD LCD.INITIALIZE_LCD repeat LCD.POSITION (1,1) LCD.PRINT(String("PL=")) LCD.PRINT_DEC((pulselen)) LCD.SPACE(2) LCD.PRINT_DEC((servoPos)) LCD.SPACE(2) LCD.POSITION (2,1) LCD.PRINT(String("WL=")) LCD.PRINT_DEC((wavelen)) LCD.SPACE(2) LCD.POSITION (2,11) LCD.PRINT(String("FR=")) LCD.PRINT_DEC((frequency)) LCD.SPACE(2)
'This is running in the new cog 'set up the LCD 'LCD routine loop 'Position LCD cursor 'Pulse 'print data 'write over old data 'print servo position 'write over old data 'Position LCD cursor 'Wave Length 'print value 'write over old data 'Position LCD cursor 'Frequency 'print value 'write over old data
PRI SERVO1 'servo positioning routine dira[servo]~~ 'set pin direction servoPos:=15000 'initial position repeat case pulseLen 'based on servo position 0..50700:servoPos:=servoPos+200 'move positive 50701..50800: 'no move needed 50801..100_000:servoPos:=servoPos-200 'move negative servoPos #>=6500 'limit to 6500 servoPos >4 'Ready to READ data in OUTA[Enable] := 0 'Toggle the bit H>L to Xfer the data OUTA[Enable] := 1 'Set up to toggle bit H>L OUTA[DataBit7..DataBit4] := D_DATA 'Ready to READ data in OUTA[Enable] := 0 'Toggle the bit H>L to Xfer the data {{Sends a single character to the LCD in two halves }} PUB SEND_CHAR (D_CHAR) 'set up for writing to the display CHECK_BUSY 'wait for busy bit to clear before sending OUTA[ReadWrite] := 0 'Set up to send data OUTA[RegSelect] := 1 'Set up to send data OUTA[Enable] := 1 'go high OUTA[DataBit7..DataBit4] := D_CHAR>>4 'Send high 4 bits OUTA[Enable] := 0 'Toggle the bit H>L OUTA[Enable] := 1 'go high again OUTA[DataBit7..DataBit4] :=D_CHAR 'send low 4 bits OUTA[Enable] := 0 'Toggle the bit H>L
320 LCDroutines4 and Utilities Object Listings
{{Print a line of characters to the LCD uses variables index and temp }} PUB PRINT (the_line) 'This routine handles more than one Char at a time 'called as PRINT(string("the_line")) '"the_line" contains the pointer to line. Line is 'because we have to point to the line 'zero terminated but we will not use that. We will 'use the string size instead. Easier to understand index:=0 'Reset the counter we are using to count chars sent repeat 'repeat for all chars in the list temp:= byte[the_line][index++] ' char/byte pointed by index SEND_CHAR (temp) 'send the 'pointed to’ char to the LCD while indexL if delay>610_000 'max permitted delay delay:=610_000 'clamp delay PotValue:=(delay/2000) 'reduces the value to 0-255 or 1 byte valutotal:=valutotal+potvalue 'figures total potvalue:=valutotal/repval 'figure average potvalue =0 result:=PotValue 'figure average PUB GetPotVal2 dira[PotLine2]~~ 'set potline as output valutotal2:=0 'clear total repeat repval2 'repeat dira[PotLine2]~~ 'set potline as output outa[PotLine2]~~ 'make it high so we can charge the capacitor waitcnt(4000+cnt) 'wait for the capacitor to get charged dira[PotLine2]~ 'make potline an input. line switches H>L startCnt2:=cnt 'read the counter at start of cycle and store repeat 'go into an endless loop while ina[PotLine2]~~ 'keep doing it as long as the potline is high EndCount2 := cnt 'read the counter at end of cycle and store delay2:= ((EndCount2-StartCnt2)-1184) 'cal time for line to go H>L if delay2>610_000 'max permitted delay delay2:=610_000 'clamp delay PotValue2:=(delay2/2300) 'reduce the value to 0-255 valutotal2:=valutotal2+potvalue2 'figures total potvalue2:=valutotal2/repval2 'figure average potvalue2