ECE 477 Final Report Spring 2008 Team 10 Global Pigeon Team Members: #1: David Collins_________________ Signature: ____________________ Date: _________ #2: Matt Ligocki_________________ Signature: ____________________ Date: _________ #3: Daniel Bixby_________________ Signature: ____________________ Date: _________ #4: Paul Ng _____________________ Signature: ____________________ Date: _________ CRITERION Technical content Design documentation Technical writing style Contributions Editing Comments: 0 0 0 0 0 1 1 1 1 1 2 2 2 2 2 3 3 3 3 3 SCORE 4 5 6 7 4 5 6 7 4 5 6 7 4 5 6 7 4 5 6 7 8 8 8 8 8 9 9 9 9 9 10 10 10 10 10 MPY 3 3 2 1 1 TOTAL PTS ECE 477 Final Report Spring 2008 TABLE OF CONTENTS Abstract 1 1.0 Project Overview and Block Diagram 2 2.0 Team Success Criteria and Fulfillment 5 3.0 Constraint Analysis and Component Selection 6 4.0 Patent Liability Analysis 11 5.0 Reliability and Safety Analysis 16 6.0 Ethical and Environmental Impact Analysis 21 7.0 Packaging Design Considerations 26 8.0 Schematic Design Considerations 31 9.0 PCB Layout Design Considerations 36 10.0 Software Design Considerations 40 11.0 Version 2 Changes 47 12.0 Summary and Conclusions 48 13.0 References 49 Appendix A: Individual Contributions A-1 Appendix B: Packaging B-1 Appendix C: Schematic C-1 Appendix D: PCB Layout Top and Bottom Copper D-1 Appendix E: Parts List Spreadsheet E-1 Appendix F: Software Listing F-1 Appendix G: FMECA Worksheet G-1 -ii- ECE 477 Final Report Spring 2008 Abstract The objective of Team Global Pigeon is to build a semi-autonomous RC plane capable of flying to GPS waypoints and taking photographs. The airframe chosen was a Multiplex Easy Glider Electric. It is effectively a foam glider with an electric motor for thrust. The design will be semi-autonomous as the plane will require human controlled take off and landing using a standard RC radio controller. Once at cruising altitude, the radio controller will send a signal to switch to autopilot mode. The plane will then fly to each of a series of GPS waypoints. Upon getting sufficiently close to each objective, the plane will begin triggering the attached digital camera to take photos. -1- ECE 477 Final Report Spring 2008 1.0 Project Overview and Block Diagram The design is built around the Multiplex Easy Glider Electric RC plane, which is effectively a foam glider using an electric motor for thrust. The plane was selected for its durability and crash resistance. A retail point-and-shoot camera is mounted on the plane. The shutter is wired to a microcontroller for automated photography. The takeoff and landing of the plane is controlled manually using a standard radio controller. As described in the abstract, it will be switched to autopilot mode once it has reached the desired altitude. From this point the microcontroller reads GPS waypoints which have been prewritten onto an SD card. These values are used as a reference for controlling the plane's flight. In addition the plane periodically writes its position to the SD card for later use, such as allowing the flight path to be read and mapped by a computer. Upon reaching the specified coordinates, the microcontroller triggers the camera to take a series of photographs before proceeding to the next waypoint. The photographs are stored in the cameras built in SD card. The design has the potential for improvements in the aerial photography field. It would greatly improve the cost and efficiency of aerial photography, as it eliminates the necessity of a human flying in a significantly larger plane. It could also improve the accuracy and precision with which photos are taken from the plane. The plane can also be used for small scale geographical surveying. Multiple planes could also be used in search and rescue missions to scour a large area. -2- ECE 477 Final Report Spring 2008 Figure 1.1: Global Pigeon Block Diagram -3- ECE 477 Final Report Spring 2008 Figure 2.2: Global Pigeon Final Assembly -4- ECE 477 Final Report Spring 2008 2.0 Team Success Criteria and Fulfillment 1. An ability to fly an R/C plane autonomously once airborne, based on pre-programmed waypoints. 2. An ability to decode and display GPS coordinates. 3. An ability to control motor speed and control surface position. 4. An ability to capture still images. 5. An ability to read waypoints from a MicroSD removable storage device. As of the writing of this report, PSSC’s two through five have been successfully completed and demonstrated. The first PSSC is currently partially completed. The plane is capable of becoming airborne with the additional weight load and flies stable. The microcontroller is currently not capable of controlling the plane during a real flight scenario due to RF interference emitted by the plane’s circuit board. Possible solutions to this problem are currently being developed. The remaining PSSC’s are demonstrated while the plane is on the ground. Criteria two is demonstrated by hooking up an external LCD screen to the plane and walking around outside. As the plane moves around, up to date latitude and longitude coordinates are displayed to the LCD. Criteria three and four are demonstrated by having a laptop send commands to the plane’s microcontroller which then controls the plane’s control systems and camera. Criteria five is demonstrated by first programming GPS coordinates to a microSD card using a laptop. The card is then inserted into the plane and the coordinates are read from the plane via the laptop’s serial connection. -5- ECE 477 Final Report Spring 2008 3.0 Constraint Analysis and Component Selection The objective of this project is to build a semi-autonomous RC plane capable of flying to GPS way points and taking photographs. This will be accomplished by modifying an existing RC plane. These modifications will include replacing components that are already part of the plane such as motor and battery pack as well as adding additional hardware to facilitate the plane’s ability to track its own location and heading. This additional hardware must not weigh the plane down to the point where it is no longer capable of attaining flight and must be evenly distributed within the limited space of the plane’s fuselage as to not affect the plane’s center of gravity. This section will explain the component selection rationale for the project in terms of its major design constraints. 3.1 Design Constraint Analysis The primary design constraint of this project is the weight of the additional hardware added to the plane. If the plane becomes too heavy, there exists the possibility that it will not be able to get off of the ground. With the additional weight comes the issue of how it is distributed within the plane’s fuselage. If the hardware’s weight is not evenly distributed, the plane will not fly level. A final consideration in hardware selection is size. The majority of the additional hardware must fit within the fuselage of the plane. This space is limited and excessive modification to the fuselage can weaken the plane’s structure. 3.2 Computation Requirements The plane’s microcontroller will be responsible for navigating between way points and making course adjustments as necessary. Course computations are made based off of data from the plane’s GPS module. The rate of these computations is limited by the GPS module which can only provide updated position information at a rate of five hertz [1]. The basic control algorithm will consist of checking the plane’s current position and heading, comparing this to where the plane needs to go, and then making any control adjustments as necessary. A possible advancement to this algorithm is to have the plane adapt for flight conditions. If the microcontroller notices that the plane is consistently drifting of course in a particular direction, it can have the plane compensate for this drift throughout the -6- ECE 477 Final Report Spring 2008 planned flight. This type of control algorithm would also be relatively simple to implement and would not require any severe computational power. 3.3 Interface Requirements The microcontroller will be required to interface with a variety of on board sensors and flight control components. The GPS module will interface to the microcontroller via RS-232 SCI [1]. The microcontroller will receive its GPS waypoints from a microSD card. This device will interface via a SPI bus [2]. The plane itself includes four servos for controlling the rudder, elevators and ailerons, a motor, and a RF radio receiver. All of the radio channels will interface to the microcontroller’s timer module for data recording. One unused radio signal will be used to determine if the plane is in automated or manual flight mode. During automated flight the microcontroller will be responsible for controlling the plane’s rudder and elevators. This will be accomplished by using PWM outputs. A digital output signal will be used as a select line to an external multiplexer to choose between the microcontroller and RF receiver control signals. The digital camera used to accomplish aerial photography will interface to the microcontroller using several digital outputs to control its power, shutter, and auto-focus. There will also be another digital input connected to the camera to detect if it has power. A detachable LCD screen will be used for preflight analysis and debugging. This screen will interface via RS-232 SCI and will also include a digital input pin used for detecting when the display is attached. Other miscellaneous interfaces include digital outputs for indicator LEDs and digital inputs for input switches. All of the electronic components selected utilize either 3.3V or 5V input voltage. Converting between these will be handled using level translation buffers. -7- ECE 477 Final Report Spring 2008 Peripheral Etek 5Hz GPS EB-85A microSD Servo and Drive output LCD Screen Auto/Manual Select output Camera control Camera power detection Auto/Manual PWM input Display connection detection Indicator LEDs Miscellanous I/O I/O Interface SCI SPI PWM SCI GPIO GPIO GPIO Timer Counter GPIO GPIO GPIO Number of Pins 2 4 4 2 1 3 1 5 1 3 1 Table 3.1: I/O Requirements 3.4 On-Chip Peripheral Requirements On-chip peripheral requirements are based off of the requirements of external components. The microcontroller selected will require at a minimum two RS-232 SCI, one SPI, four PWM channels, five timer channels, and ten general purpose I/O pins. This comes to a total pin requirement of twenty-seven pins. 3.5 Off-Chip Peripheral Requirements Several off-chip peripherals are required for the successful operation of the plane. The first set of peripherals is the plane’s control systems. This includes the control surface servos, motor, and radio receiver. These parts come with the plane but the motor will be upgraded to give the plane more power and the radio receiver will be upgraded to allow the extra control signal required to switch from manual to automated flight. A multiplexor will also be required to switch between the radio receiver control signals and those generated by the microcontroller. The second set of off-chip peripherals is the navigation equipment. This includes the GPS module and microSD card. The GPS module will be required to have decent accuracy in terms of both position and altitude measurement. The final off-chip peripheral is the digital camera. The camera is required to be light weight and small to allow it to be easily mounted to the plane. -8- ECE 477 Final Report 3.6 Spring 2008 Power Constraints The plane is powered by an onboard battery pack. The plane’s motor will be the largest power draw on the battery. The hardware added to the plane will add weight to the plane increasing the required strain on the motor and therefore decreasing the plane’s battery life. This additional hardware will also draw power from the plane’s battery but is considered insignificant compared to the draw from the motor. Compensating for these extra power requirements will involve replacing the plane’s standard battery pack. The new battery pack must be able to fit in the plane in the same location as the existing battery and must not add any more weight to the plane as to negate its benefits. 3.7 Packaging Constraints The packaging of the project is the plane. Since no one on the team is an experienced RC plane pilot, the plane chosen for the project is the Multiplex Easy Glider. This plane is recommended by RC plane enthusiasts as the perfect plane for beginners due to its stability in flight and ability to self correct. The plane is also designed to survive crashes with little to no damage. There are built-in compartments within the fuselage to hold the necessary electronic components. The plane is also made of foam allowing easy modification to the body. 3.8 Cost Constraints We currently know of no commercial aerial reconnaissance drones available to the general public. There are known modifications to RC planes performed by other enthusiasts to perform aerial reconnaissance. Since these are not commercial products we cannot perform a cost comparison. The only known aerial reconnaissance drones that we know of existing are the MQ1 Predator and the RQ-4 Global Hawk currently deployed by the US military. These planes cost $4 million and $123.2 million each respectively [3] [4]. The operational range and altitudes of these planes far exceed the capabilities of our own design. These planes also have the capability to be armed with missiles. Due to federal regulations we will not be able to turn our plane into an aerial weapons platform. -9- ECE 477 Final Report 3.9 Spring 2008 Component Selection Rationale It was initially decided that our microcontroller would be one of the variants of the Freescale HCS12 family. Due to our peripheral interfacing requirements this limited our possible selections either a HCS12E or HCS12A. Both provide all of the required interfaces with the “E” variant providing one extra SCI interface [5] [6]. The downfall of the “E” variant is the fact that its PWM only has 8-bit accuracy while the “A” has 16-bit accuracy [5] [6]. This would severely limit to number of positions we could set our plane’s servos to. After deciding on the HCS12A we then decided on the exact part. The microcontroller comes in 80 and 112 pin packages. Due to our component size limitations it was decided to use an 80 pin variant. Our final selection ended up being the MC9S12A64CFUE due to it providing the largest amount of flash memory in for the package size. Our inspiration for the selection of our GPS module and digital compass comes from a senior design project from a previous semester [7]. Since this team had already found relatively cheap and accurate devices, we used their component selections to decrease our research time. Our project constraints required that are GPS module be mounted within the fuselage of the plane and preferably be a bare unpackaged product. This limited us to the GPS 15 and Etek EB85A [1] [8]. The GPS 15 provides decent accuracy (<15m positional error) and is cheap [8]. The EB-85A provides greater accuracy (<3m positional error) but with an increased cost [1]. It was decided that the improvements in accuracy of the 15L outweighed the cost increase and was therefore chosen. 3.10 Summary The most important consideration we must keep in mind when developing this project is the plane must maintain the ability to fly when we are complete modifying it. We have chosen parts that are overall small in size and use simple interfaces to minimize the overall amount of circuitry required while still maintaining necessary levels of accuracy. Overall, the project has no one overall complex element but instead consists of many relatively simple components. In the end these components must work in harmony with each other in order for the project to be successful. -10- ECE 477 Final Report Spring 2008 4.0 Patent Liability Analysis The goal of Project Global Pigeon has been to modify an existing radio-controlled plane and to make it into an unmanned aerial vehicle. This section seeks to analyze patents whose functions are similar to ours, and to determine the possibility of infringement upon each of them. 4.1 Results of Patent and Product Search 4.1.1 System and method for automatically collecting images of objects at geographic locations and displaying same in online directories [10] Filing Date: Mar. 24, 2004 Condensed Abstract: A camera and a GPS receiver are both mounted on a vehicle and receive time information from a synchronized clock. The camera captures images while the GPS receiver determines the geographic location. Both events are time-stamped, and as a result each image can afterward be correlated with a street address based on the corresponding GPS data. Claims with Potential for Infringement: Claim 1: “A method of preparing images of objects at geographic locations for use in an online directory, comprising: (a) receiving images of objects, wherein each image is associated with a geographic location; (b) automatically correlating each image with a street address based on each image's associated geographic location, wherein one or more images are correlated with each street address; and (c) providing an image for display with a listing in an online directory based on a street address in the listing.” [10] Claim 4: “The method of claim 1, wherein receiving images of objects further comprises: (i) receiving time-stamped images captured by a camera; (ii) receiving time-stamped geographic locations as determined by a GPS receiver that is located with the camera; and (iii) automatically associating each image with a geographic location based on corresponding respective time-stamps.” [10] Claim 7: “The method of claim 4, wherein the time-stamped images are captured using a digital still camera.” [10] Description of preferred embodiment: “The vehicle 9 may be an automobile, as illustrated, but may be of any other type apparent to one skilled in the art, such as a bicycle, bus, or airborne vehicle such as a manned or unmanned airplane.” [10] -11- ECE 477 Final Report Spring 2008 4.1.2 Precision Approach and Control [11] Filing Date: Sept. 19, 2006 Condensed Abstract: A camera is mounted on an aircraft, along with a navigation system and a computer/controller for determining and executing the movement of the aircraft. The camera and navigation system work in tandem to determine the angle and distance to a fixed point on the ground. This data is fed to the controller which then moves the plane accordingly in order to achieve a perpendicular distance to the ground point. Claims with Potential for Infringement: Claim 1: “An aircraft command and control system, comprising: a camera, including a rangefinder, disposed aboard the aircraft for measuring an azimuth angle, an elevation angle and a slant range from a fixed point on the aircraft relative to a selected target point on a surface located below the aircraft; a navigation system disposed aboard the aircraft for measuring a latitude and a longitude of a point on the surface that is disposed perpendicularly below the fixed point on the aircraft; a computer for computing the position of the fixed point on the aircraft relative to the target point on the surface from the respective measurements of the camera and the navigation system; and, a controller for controlling the movement of the aircraft such that the fixed point on the aircraft is positioned at a selected azimuth angle, elevation angle and slant range above the selected target point on the surface.” [11] Claim 4: “The system of claim 1, wherein the navigation system comprises a Global Positioning Satellite (GPS) system, an Inertial Navigation System (INS), or both a GPS and an INS.” [11] Claim 5: “The system of claim 1, wherein the aircraft comprises a helicopter or an aerial vehicle.” [11] Claim 6: “The system of claim 1, wherein the aircraft is unmanned.” [11] 4.1.3 Unmanned airborne reconnaissance system [12] Filing Date: July 12, 2002 Condensed Abstract: The system includes a lightweight, portable aircraft which fits in a box alongside a foldable launch rail. The rail and one of two launching methods are used to get the plane in the air. Once airborne, the craft is guided by remote control and/or by a programmed onboard computer. The craft contains a camera for recording and transmitting ground images. -12- ECE 477 Final Report Spring 2008 Claims with Potential for Infringement: Claim 1: “An airborne reconnaissance system comprising: an unmanned aircraft system adapted to be disassembled; a launch system for said unmanned aircraft system, said launch system adapted to be disassembled; a remote control system for remote control of said unmanned aircraft system; said remote control system being detachable from said unmanned aircraft system and said launch system; a container for receiving said unmanned aircraft system and said launch system in their disassembled states; said container containing said unmanned aircraft system and said launch adapted to be carried as a backpack; and means for assembly and disassembly of said unmanned aircraft and said launch; wherein said reconnaissance system is transportable, fielddeployable, and operational by one person.” [12] Claim 6: “The reconnaissance system of claim 1 wherein the remote control system is controllable in real time.” [12] Claim 7: “The reconnaissance system of claim 1 wherein the remote control system is programmable.” [12] 4.2 4.2.1 Analysis of Patent Liability Analysis of Liability involving invention of [10], System and method for automatically collecting images of objects at geographic locations and displaying same in online directories The inventors of [10] have developed a method of collecting images in a way that enables the eventual automatic association of a given address with said images. With the existing lookup tables that correlate addresses with GPS locations, this allows each image, which through timestamping is already associated with the corresponding time-stamped GPS location, to be assigned to the address corresponding to that location and entered into an online directory like yellowpages.com. Project Global Pigeon’s goals and features do not include any form of “displaying [images of objects at geographic locations] in online directories”; therefore we are not literally infringing upon [10]. As to the doctrine of equivalents question, our project is similar to [10] in that it utilizes both an on-board digital still camera and a GPS receiver in the image collection process. However, in our project the images are captured only upon reaching specific GPS locations and are not time-stamped. The images we collect are associated with the -13- ECE 477 Final Report Spring 2008 GPS data through human methods, i.e. noting the number of pictures to be taken at each pre-set location and afterwards ordering them in accordance. 4.2.2 Analysis of Liability involving invention of [11], Precision Approach and Control Project Global Pigeon does not literally infringe on [11], as the selected camera does not include a rangefinder and is not involved in the approach to a specific GPS waypoint. Like [11], our plane's flight is based upon a target point, in our case GPS. The microcontroller on board our plane constitutes both the “computer” and “controller” described in Claim 1. Similar to [11], we use the present and target GPS locations as inputs to the micro, which then directs the movement of the plane accordingly to approach the target point. Were we to select an upgraded camera that included a rangefinder and use it to measure the distance and angle to the target points – improving the precision of the approach - it could combine with the previous similarities to constitute infringement under the doctrine of equivalence. However, our camera is only used in the eventual image capture, not as an assistant in the navigation of the plane. The inventors of [11] have not claimed an approach method that uses only GPS data, nor have they made the camera's rangefinder feature optional which would allow for the use of our regular still camera. 4.2.3 Analysis of Liability involving invention of [12], Unmanned airborne reconnaissance system This patent simultaneously displays the broadest and most vague language of the three selected. We make no use of mechanics in our launch system; thus our project does not literally infringe on [12]. Our plane is simply launched with one person throwing it into the air while another holds the radio transmitter. By using the JR XP652 Radio Set, Project Global Pigeon displays the features of claims 6 and 7 regarding the remote control system. Both of these are derived from the system of claim 1 which has similarities and differences to our project. Our plane, the Multiplex Easy Glider, can run unmanned and be disassembled to an extent; however the latter includes only the wings and cockpit plug once construction is complete. Finally, the inventors have not included a still camera like ours in any of their claims, with each reference being made to a video camera specifically. -14- ECE 477 Final Report 4.3 Spring 2008 Action Recommended Project Global Pigeon is not literally infringing upon [10], [11], or [12]. By refraining from any sort of time-stamped image capture and/or the association of images and GPS data for storage, we have avoided infringing upon [10] by the doctrine of equivalents. By not attempting to improve the precision of our waypoint approach by using a rangefinder we avoid infringing similarly upon [11]. Finally, we have avoided doctrine-of-equivalence infringement on [12] by refraining from the development of either a mechanical launch system or the upgrade to a continuous capture camera. 4.4 Summary This report presented three patents/products whose functions were similar to those of Project Global Pigeon. It analyzed the potential of each for both literal infringement and infringement according to the doctrine of equivalence, and prescribed a course of action in each case. For all of them, there were similarities and differences, but we have been able to avoid - or design around - the features that could constitute infringement. -15- ECE 477 Final Report Spring 2008 5.0 Reliability and Safety Analysis The safety of the operator and any bystanders is the primary concern in the failure analysis. The aircraft has three major sources of danger beyond the typical heat issues from shorts on the circuit board. The first is simply the fact that it is a large flying object that could crash into a person. The next source of danger is the plane’s power source. A lithium-polymer battery was chosen thanks to its extremely high energy density; unfortunately, they are also prone to catching on fire. The final source of danger is the propeller on the front of the aircraft. It could cut the user if it started unexpectedly on the ground. The following analyses elaborate on failure modes and the reliability of specific components which would contribute to the failures. 5.1 Reliability Analysis Reliability analysis was performed on three particular components on the circuit board of the Global Pigeon project. The microcontroller used on the board, an MC9S12A64CFUE [13], was chosen for reliability analysis because it is by far the most complex component. It also has the highest pin count, which increases the failure rate. The Military Reliability Prediction of Electronic Equipment Handbook [14] was referenced to determine a failure model of the microcontroller as well as the other components. The most fitting model for the microcontroller is that of a microcircuit as described in Section 5.1 of the handbook [14]. The model defines the failure rate to be: P (C1 T C 2 E ) Q L failures per million hours of operation. Each term in the equation corresponds to a contributing factor in failure. C1 is the die complexity failure rate. In the case of the 9S12A64, C1 = 0.28 because it is a MOS device that can operate with 16 bit integers. The term T is the temperature factor. It can be approximated based on TJ, the junction temperature, and the logic family using the table in section 5.8 of the handbook [14]. It was assumed that the maximum power draw is 250mW in accordance with the datasheet [13] along with JA =51°C/W. JA is the thermal resistance between the junction and ambient. The maximum junction temperature was calculated according to the following equation at room temperature: TJ JA P TA . This lead to a value of TJ = 35°C which in turn corresponds to T = 0.16 for a MOS device [14]. -16- ECE 477 Final Report Spring 2008 The next term in the failure rate equation is C2, it represents the package failure rate. Assuming that the package is non-hermetic, the 80 pin package corresponds to C2 = 0.041 [14]. The environment factor, E , was assumed to have a value of 5.0. This corresponds to the environment of an unmanned cargo aircraft. This environment was chosen because the Global Pigeon will fly and could have to deal with shock from rough landings. The quality factor, Q , was chosen to have a value of 10 because the IC is a commercial, not military product. The learning factor, L , was assumed to be 1 because this component has been in production for more than two years. Inserting all of these values into the failure rate equation yields: P = 2.50 failures / Mhr. This corresponds to a mean time to failure, MTTF, of 45.7 yrs. The next component, a 5 V switching regulator, part number LM2679SD-5.0 [15], was initially modeled as a linear MOS device, using the same equation and assumptions as above. This resulted in P = 0.85 and MTTF = 135 yrs. However, given the high power nature of this device, the failure rate seemed low. The calculations were repeated by modeling it as a low frequency Si FET. This model is valid because the datasheet [15] claims that the output of the regulator is switched by a DMOS FET at 260 kHz. Therefore, the failure rate is defined as: P b T A Q E [14]. The later four terms have the same meaning as in the preceding set of calculations. The term b is the base failure rate. In the case of this device, b = 0.012 because it is a MOSFET. Assuming a 5 V supply voltage and 2 A max current draw along with 89% efficiency, the regulator should dissipate at most 1.1W of heat. Based on the small onboard heat sink, the thermal resistance of the chip is JA = 56°C/W [15]. This leads to a maximum junction temperature of 85°C which results in T = 3 according to the table in section 6.4 of the military handbook [14]. The term A is assumed to have a value of 4 because this component is rated to a maximum supply of 5 A at 5 V or 25W. The quality term Q = 8.0 because the casing is plastic and does not meet military specifications. The final environment term, E , was chosen to have a value of 20 due to the operation conditions described for the microcontroller. Multiplying all of these terms together results in an expected failure rate of P = 23.04 failures per million hours of operation. This in turn leads to an MTTF of 4.95 yrs. This is a clearly much more conservative lifetime estimate than when modeled as a microcircuit. -17- ECE 477 Final Report Spring 2008 The final component chosen for analysis was the servo signal multiplexer. It has a part number: SN74CBT3257 [16]. This component was chosen for analysis because if it were to fail, the plane would immediately crash as it directly feeds the control signals to the servo motors. The analysis began by assuming that the multiplexer is a digital MOS microcircuit with less than 100 gates. This leads to a C1 die failure rate of 0.010. The overall failure model is the same as that used in the microcontroller: P (C1 T C 2 E ) Q L . The part datasheet [16] provides a thermal resistance value JA = 90°C/W for the SOIC package. Assuming a maximum current draw of 15 mA at 5 V, the junction temperature should be about 30°C. This corresponds to T = 0.13 for a digital MOS device [14]. C2 is given a value of 0.0072 because the package has 16 pins and is a non-hermetic SMT. The final three parameters have the same set of assumptions and values as those stated for the microcontroller namely: E = 5.0, Q = 10, and L = 1. Combining all of the terms together results in an expected failure rate: P = 0.373 failures / Mhr. The mean time to failure is 306 yrs. Component MC9S12A64CFUE LM2679SD-5.0 SN74CBT3257 Table 5.1 – Component Failure Rates λp (Failures / Mhr) 2.50 23.04 0.37 MTTF (yr) 45.7 4.95 306 Given the possible manners in which a failure of the Global Pigeon would lead to bodily harm, the failure rate of the first two components is much too high. These results show without a doubt that more safety features are needed in the system. A failure of any of these components would lead to the plane crashing, and possibly hitting a person in the process. The circuit design could be improved if there was redundancy and self testing built in at all stages. Adding redundant and more varied sensors would be an important step as the microcontroller has no choice but to trust the reading coming in. A first improvement would be to add a gyro, accelerometer, and barometric altimeter. The values from these sensors could then be contrasted with the readings coming in from the thermopiles and GPS receiver to get a more accurate view of the plane’s position and orientation. Another good step would be to have redundant processing in the form of a second microcontroller. Each would read from the inputs and share -18- ECE 477 Final Report the outputs. Spring 2008 The output servo multiplexer had a relatively low failure rate, but adding a watchdog of some sort would be good to reduce the likelihood of its failure crashing the plane. 5.2 Failure Mode, Effects, and Criticality Analysis (FMECA) For the purposes of failure mode analysis, the circuit diagram of this project was divided into six blocks, A through F. Higher criticality blocks are addressed first. Block A contains the microcontroller. Block B consists of the voltage regulators and battery sensing circuit. Block C holds the radio input circuitry and the servo output multiplexer. Block D is just the thermopile amplifiers. Block E contains both the GPS and MicroSD interface circuits. The final block, Block F holds the camera and LCD interface circuits. Three levels of criticality were used in the analysis: high, medium, and low. High criticality failures are those which could result in personal injury. The Global Pigeon, by its nature has many high criticality failure modes. Some of these modes include: the lithiumpolymer battery catching on fire, the plane crashing into a person, and an unanticipated start of the propeller. Medium criticality failures are those which are unlikely to cause injury, but which inhibit the ability to fly autonomously. An inability to communicate with the MicroSD card, or GPS module would constitute a medium criticality failure as the system would not allow the user to switch into autonomous mode. Low criticality failures do not cause injury nor do they inhibit the ability to fly autonomously. A loss of camera or LCD control would fall into this category. Individual failure modes are listed in the tables of Appendix G. Ideally, the failure rate for high criticality failures would be less than 10-9. Medium criticality failures would have a rate between 10-6 and 10-9. Low criticality failures would then have a rate between 10-4 and 10-6. Based on the results of component reliability analysis, these goals have not been met with the current circuit design. Many safety features would need to be added to reduce the failure rates before this product could be considered for production. Additionally, it was assumed that failures would only occur on the custom PCB of the system. Given the complexity of the system overall, it would be important to determine the reliability of the devices connected to the PCB during the safety redesign process. -19- ECE 477 Final Report 5.3 Spring 2008 Summary The failure rate analysis has shown the steps involved in determining reasonable reliability predictions for the most critical components on the circuit board of the Global Pigeon. These components consist of the microcontroller, voltage regulators, and radio multiplexer. The results of the reliability analysis indicate that further refinements are needed to add redundancy and failure detection into the system. This need is reinforced by the findings of the failure mode analysis. Many of the components are single points of failure. This setup is unacceptable from a safety point of view. Further design revision would be needed before production of this system could begin. -20- ECE 477 Final Report Spring 2008 6.0 Ethical and Environmental Impact Analysis Global Pigeon is an Unmanned Aerial Vehicle that has the ability to fly to preprogrammed GPS points and take pictures at those locations. The product utilizes a GPS module, a radio receiver, a RC model motor, Lithium Polymer battery and several servos to control the direction of the plane. These all plug into the PCB which hosts the microcontroller. With each part of the product, comes its own set of environmental and ethical problems. For the ethical aspect of the project, the reliability of construction, operation use and misuse are taken into consideration. For the environmental aspect, pollution and wastes during three phases of the product life, manufacturing, normal use and disposal/recycling, are taken into consideration. Furthermore, the electrical consumption of the product will also be taken into consideration. 6.1 Ethical Impact Analysis The ethical challenges faced by the team to bring the project to the market would be mostly how to deal with misuse. The goal of Global Pigeon is to offer a reliable UAV that has the ability to take pictures remotely. This aspect of the plane can be put to relatively good use such as crop monitoring or land surveying. Two markets have to be considered when discussing the ethical issues in correlation to the product. The first market is the general public. This market is currently the intended market for the product. Since this is the general public we are talking about, there are very few restrictions that can be put on the sale of the plane. As a result, unexpected use of the plane for such as usage of the plane by stalkers cannot be predetermined. Little or nothing can be done against such offenders of the law. As such, a disclaimer should be placed in the user manual to say that the developers or manufacturers should not be responsible for the actions of the private end user party. A relatively big problem that can arise from end user error is that the user flies the plane into restricted airspace such as an airport. The plane can interfere with air traffic in restricted airspace. Furthermore the radio receiver, although unlikely, might cause interference with the traffic control tower. This is a problem faced not only by our product but by any standard RC plane. However the possibility of a GPS malfunction and the product flying into restricted airspace still exists. To resolve the problem of a malfunction or even eliminate the possibility of such an occurrence, we can hardcode the GPS locations of such locations onto the software used -21- ECE 477 Final Report Spring 2008 to upload the GPS coordinates to the module to prevent the user from programming such locations in. The software would have to include an update feature to check keep the location list current. These measures will be applied if the prototype goes into full scale production. Another problem is the susceptibility to explosion of the lithium polymer battery utilized in the product. Lithium based batteries have the potential to explode if damaged or overcharged. This has the ability to cause harm to the user. However if used properly the batteries should not pose a significant problem unless it contains a manufacturing defect. This problem can be solved by instructing the end user with the correct method of operation and document procedures inside the user manual. Furthermore, stickers should be placed on the battery itself indicating danger and the asking the user to refer to the manual. The other market to take into consideration would be for military or private company usage. In this event the product can be limited to selected personnel whom are specifically trained to use the equipment therefore limiting the amount of misuse by the end user. However this scenario would be unlikely since the product was not design with this market in mind nor is it built to military required specifications. The product would have to undergo extensive modification in order to meet the required specifications. Another factor to take into consideration would be the durability of the construction of the plane. As this is a novel RC plane product, many crashes can be expected and some level of durability should be expected by the end user. Since the body of the plane is not manufactured by us, we have chosen a model of plane that has received relatively high reviews of durability and susceptibility to damage. Since any damage to the body can easily result in the internal battery module being damaged and exploding, it is required by the IEEE code of ethics [17] that we provide a decision that is consistent with the safety, health and welfare of the public. Consequently we selected a durable body for the product. 6.2 Environmental Impact Analysis Multiple items have to be considered for an environmental impact analysis. The most critical items are the PCB, the foam body of the plane, the lithium polymer battery, the electric motor used, the external LCD display and the radio controller. Incentives for the user to recycle will be discussed later in the section. -22- ECE 477 Final Report Spring 2008 6.2.1 Manufacturing Phase In the manufacturing phase of the life cycle, the PCB requires multiple toxic chemicals to be used. The process produces multiple air emissions including various acids, chlorine, ammonia and solvent vapors. It also produces effluents such as organic solvents, vinyl polymer, stannic oxide and solid wastes such as metal plating and hydroxide sludge [18]. If the product is placed in full scale manufacturing, air scrubbers and waste reclaiming will be needed in order to reduce the pollution output. Items such as the fibers used for the board layer can be recycled, whereas chemicals used can be reclaimed through chemical techniques. Manufacturers such as Advanced Circuits [19] offer RoHS compliant PCB Manufacturing with appropriate waste disposal facilities. The foam body of the plane although not manufactured by us also produces pollution and therefore should be accounted for. The manufacturing process requires chemicals such as hydrogen fluoride which is highly toxic and corrosive. The hydrogen fluoride will have to be treated before being released into water sources. With regards to the electric motor, dioxin fumes are produced during the manufacturing phase especially during the smelting phase of to produce metal to fabricate the motors with. The LCD display used is a simple 20X4 text display. During the production stage of the LCD, sulfur hexafluoride, a greenhouse gas is produced [21]. The process also utilizes chemicals that need to be treated before being released. Finally the radio controller contains its own PCB, LCD and plastic casing. The production of the radio controller will contribute to all the pollution factors as stated above since it a device in itself. 6.2.2 Normal Use During the normal operation phase, the PCB the will not be producing any pollutants since the board will be completely RoHS compliant. None of the onboard components used emit high levels of EM radiation since no RF circuitry is used. The foam body of the plane will not contribute to pollution during normal use. The lithium polymer battery can pose a potential environmental hazard due to the dangerous chemicals used in it. The main chemical in the battery lithium is deadly if consumed. -23- ECE 477 Final Report Spring 2008 The battery itself poses the potential to be a fire hazard if punctured or incorrectly used. This means that should the plane crash in a forested area, it has the potential to start a forest fire. During normal operation, the motor poses no extra pollution since it does not consume any fossil fuels directly. The LCD screen does not contribute to pollution during normal usage either. During its operation, the controller will contribute to EM pollution, Since it utilizes radio waves. It is unlikely that the EM pollution would have any adverse effects on humans. 6.2.3 End of Life Cycle The PCB is one of the products that contribute highest to e-waste. Especially deadly is the lead used in the manufacturing of the board which if not properly dealt with can pollute ground water. Lead poisoning is known to cause blindness, impotency and neurological damage [20]. Fortunately, companies such as TCI Inc. [22] offer recycling for PCBs. In the event of disposal, the user should be notified of the proper disposal methods in order to send the board for recycling. To facilitate this, the sales package should include a PCB recycling package to promote recycling. At the end of its life, the foam body has the potential to be the largest object to contribute to landfill pollution since it is non biodegradable. To rectify this, the foam body should be recycled. Companies such as Foam Recycle Center offer foam recycling services for certain states. A directory of local foam recycling companies will be provided in the user manual. If incorrectly disposed of, excessive lithium chemicals from the battery can leak into ground and contaminate groundwater. In this event, harm can be caused to the individuals that consume the groundwater. Companies like Toxco Inc [23] offer lithium battery recycling services through chemical processes. Proper disposal methods will be included inside the user manual in addition to a sticker on the battery to advise the end user on the proper disposal techniques of the battery. Due to the rising awareness of the general public of the problems with not recycling batteries, there are many local places provide this service. A list of such places can be found on the Rechargeable Battery Recycling Corporation’s website. At the end of its life, the motor can be scrapped and sent to be recycled. Most garbage processing facilities already do this therefore there should be no additional concern on the user’s end. -24- ECE 477 Final Report Spring 2008 At the end of its functional lifespan, the LCD should be recycled to reduce e-waste. Furthermore, the lead used in the PCB of the LCD display can cause similar problems such as those stated above. The liquid crystals can be extracted and reused however it is more likely that the product will end up at a land fill. In order to rectify the situation, guidelines to recycle the LCD will be given in the user manual and a sticker will be placed to inform the user of proper recycling techniques. In all likelihood, the user would probably dispose of the radio controller without separating its components at the end of its use. As a result, we would have to provide a service specific to the device if we want to do any recycling for this specific item. However providing such a service would be costly and a solution to this would be to inbuilt the cost of the recycling into the sale cost. Unfortunately, even given the proper guidelines, it is more than likely that the end user would dispose of the product in an inappropriate manner however non-environmentally friendly it is. To properly dispose of all the components, the manufacturer can include a recycling package with the sale package with mailing cost provided. This would encourage end users to recycle their products. The product will utilize a lithium polymer battery that provides 11.1 volts. Depending on the usage of the product, the user might be required to recharge the battery several times a day. However in reality, the user will probably be not utilizing the product on a daily basis. Therefore the electrical footprint of the product is minute and does not contribute much to electrical pollution by power plants. 6.3 Summary As a household product, Global Pigeon will face multiple environmental and ethical problems that will have to be resolved. In order to resolve these issues, adequate user intelligence must be established. Therefore the product should be sold to users of a certain age criteria. By establishing user intelligence, the product, in all hopes, will be used in a public approved manner. By providing the necessary facilities and services to dispose of the product, the carbon footprint of the product can be reduced. These include using RoHS compliant devices and alternative manufacturing techniques produce fewer pollutants. If all the above criteria are met, they will minimize both ethical and environmental impact that the product will have on society. -25- ECE 477 Final Report Spring 2008 7.0 Packaging Design Considerations The goal of our design project is to modify an existing radio-controlled plane in such a way that it can fly to pre-programmed GPS waypoints and take photographs with a digital camera mounted beneath the plane. During the first stage of the flight, the plane will be controlled manually. Upon reaching the desired altitude, the plane will be switched to auto-pilot. Starting from this point and running until the user is ready to land the plane, it will be controlled by the PCB. This board will be installed in the fuselage of the plane. This report will present the packaging considerations and specifications for our project, along with a look at some commercial unmanned aerial vehicles and how their packaging influences or compares to our planned implementations. 7.1 Commercial Product Packaging Initially, we had trouble locating commercial unmanned aerial vehicles with which to compare packaging methods. The U.S. Air Force uses the MQ-1 Predator and RQ-4 Global Hawk, which are multi-million dollar reconnaissance drones and not available to the public. There are many online examples of RC enthusiasts modifying their planes to accommodate onboard cameras (both wireless and hard-wired to the microcontroller). In the past week we located an online social networking platform, named DIY Drones, which is devoted to amateur UAV’s and includes a forum for the hobbyists to interact. The next two sections present two of the projects whose objectives were similar to our own. -26- ECE 477 Final Report Spring 2008 7.1.1 GeoCrawler 5 Figure 1: GeoCrawler 5 with GPS-guided autopilot The GeoCrawler 5 uses the Predator airframe along with the Picopilot autopilot. The finished project includes 20 pre-set GPS waypoints and a camera (not shown) with a programmable time-lapse function [24]. During flight, a gyroscope stabilizes the camera, keeping it pointed straight down. The maker attached a pair of spruce rails to the planes underside, where he judged the center of gravity to be. He then put four screws into the rails to form the payload attachment point. From there he used the wonders of rubber bands to mount his camera. A video of the stabilized camera has been posted on his blog [25]. The maker was pleased with the amount of room inside his fuselage, where he stored all of his electronics. Like him, we plan to keep our own components inside. Our Multiplex Easy Glider plane, however, does not include landing gear. Attaching the digital camera directly underneath, as was done here, could potentially cause damage to the camera upon landing. We did choose the underneath method and constructed a foam case to protect the camera. -27- ECE 477 Final Report Spring 2008 7.1.2 Multiplex Easy Star aerial photography platform Figure 2: Digital camera shown mounted on top (left) and bottom (right) of Multiplex Easy Star. The second photo shows the lens poking through the pre-cut hole in the fuselage. The website also included a project which used the Multiplex Easy Star [26], a foam plane used frequently by beginning RC hobbyists. The maker of this project displayed two methods of mounting the camera, both of which have the electronics mounted inside the fuselage (Figure 2). Mounting the camera on top after removing the canopy leaves a greater amount of room for the electronics; however it is completely unprotected against crashes into trees, hills, etc [27]. Seeing as we have supplied our own digital camera, we would like to keep it as protected as possible. The second method is closer to our original liking. Presumably the room in the fuselage is significantly reduced. Still, the project maker made no complaints of struggling to fit his electronics alongside the camera. In addition, our camera has been stripped of all unnecessary features and would take up less space than the fully-intact one shown. But as a final blow, the fuselage on the Easy Glider is significantly narrower than that of the Easy Star. Due to this and the components already occupying the fuselage, we elected to mount the camera outside as described in section 7.2. 7.2 Project Packaging Specifications The packaging for our project is the RC plane itself. Due to the narrowness of the Easy Glider’s fuselage, our PCB is mounted upon the edges of the cockpit area above the rudder and elevator servos. This required some hollowing out of the cockpit plug due to the height of the component headers. The two servos controlling the plane’s ailerons are fitted into the wings -28- ECE 477 Final Report Spring 2008 themselves. There is a pre-cut slot for the battery in the fuselage between the wings, which needed to be widened to make room for the 3-cell selection. A pre-cut slot in the nose of the plane is meant to house the drive motor. In the default setup, the motor shaft sticks out from a small hole in the the nose and attaches to the propeller. With the added weight due to the PCB, digital camera, and the major components listed in the design constraints report, we chose to upgrade the existing SPEED 400 motor to a Mega 16/15/4 brushless motor. When compared to the SPEED 400, it is 1.7 millimeters shorter in length and just 0.7 millimeters greater in diameter while weighing close to 0.3 ounces more [28][29]. This would fit nicely into the existing slot; however a gearbox was required to keep the rotational speed of the prop beneath its maximum, which required a certain amount of modifications to the inside of the plane nose. Appendix A includes some scale drawings showing how the components compare to the overall plane size. Due to the absence of landing gear it would have been convenient to fit the camera in the fuselage, as was done for the Easy Star in Figure 2. The fuselage was too narrow, however, and we ended up constructing a hideous foam case to house and protect the camera on the underside of the plane. Despite its size and un-aerodynamic structure, the plane still flew successfully with the case hanging off of the bottom. Smaller foam boxes were used to mount the thermopiles and GPS module onto the top and tail of the plane, respectively. These also protected the components well during flight. 7.3 PCB Footprint Layout Nearly all of the major components listed in the Design Constraints homework are connected to the PCB through connector headers as shown in Appendix C. The footprint selected for the microcontroller is simply the one in the OrCAD parts library matching our 9S12A64 (80QFP version) [6]. As for the IC’s, smaller was better when it came to footprints, enabling us to keep the board size minimized. That size came to be 2.5 inches by 3.5 inches. 7.4 Summary As far as packaging goes, our main consideration was that we were modifying an existing RC plane through the addition and upgrade of components. We wanted to include the electronics and camera without having to make excessive modifications to the structure of the plane, or to -29- ECE 477 Final Report Spring 2008 expose them to unnecessary in-flight risks. By all accounts this was accomplished, although the modifications were far from works of art. It was essential that we knew our modifications will fit the selected plane package before we proceeded to the advanced stages of our design. -30- ECE 477 Final Report Spring 2008 8.0 Schematic Design Considerations The project is to construct an Unmanned Aerial Vehicle using a standard RC Plane. The RC plane will be bought from a commercial outlet and then modified to suit our purposes. The plane will fly autonomously using GPS coordinates and at predefined waypoints will initiate a picture taking process. The coordinates will be stored on an onboard microSD card. The onboard microcontroller will control all the servos and motor speed in order to steer the plane in the right direction. The plane will use a GPS receiver to acquire GPS coordinates, altitude and velocity. The plane will not take off autonomously and will need a manual controller. A six channel radio transmitter and receiver will be used to send manual servos and motor control data as well as a signal that initiates the switch to automatic mode. A tilt sensor using thermopiles enable the plane to balance itself while in midair. The circuitry onboard the plane is limited to a small amount due to the fuselage of the plane and the limited lift achieved using a small RC plane. The intended use for the project is for aerial photography. This can be especially useful to land surveyors and enthusiasts in the field. All they would have to do is supply the GPS coordinates and launch the plane nearby and wait for it to return. 8.1 Theory of Operation 8.1.1 Microcontroller The microcontroller selected for this project was the Freescale 9S12SA64CFUE [13]. This specific MCU was selected because the team was familiar with the S12 series of microcontrollers from previous classes. The microcontroller will be operating at a frequency of 8MHz. This speed is suitable since the MCU will be powered by Li-Po batteries and conserving power is important. Also the speed is fast enough to accommodate all our needs. The microcontroller is the heart of the project and will be responsible for acquiring data from the sensors and receivers and directing the plane via the servos and motors. 8.1.2 Power Supply The plane will be powered by a 3-Cell Lithium Polymer battery. The battery provides a nominal 11.1V source since it is required by the Electronic Speed Controller to power the motor. To achieve the 5V rail and 3.3V rail, the LM2679-5.0[15] and LM2679-3.3[15] non synchronous -31- ECE 477 Final Report Spring 2008 buck converters will be used to regulate the voltage. The regulators provide up to 5A of current and an efficiency of up to 92%. High efficiency regulators are needed due to the limited amount of power we are working with. The high amount of current they provide are suitable for our needs since we will be powering 4 servos, a camera and a radio receiver which can draw a substantial amount of current. 8.1.3 JR R600 Radio Receiver The radio receiver was donated to the team by a member of the local Cloud Jockey RC club. The receiver is manufactured by JR radios and features 6 channels for us. We will be using one channel exclusively for the autopilot toggle. We require another 4 channels for servo controls. The remaining one channel can be used for manual camera trigger. The receiver uses 5V and draws a current of 12mA. 8.1.4 GPS Receiver The GPS receiver selected by the team is the Etek EB-85A [1]. The module initially found was the Garmin 15L. The Etek features an onboard antenna thus effectively saving us the need for another external component. Weighing in at 15 grams, the weight of the module is also substantially less than the Garmin 15L.The Etek updates at 5 Hz and features a sensitivity of 158dbm. It uses a UART to communicate with the MCU serially. Upon intialization it constantly updates itself and transmits data to the MCU. It requires a 3.3-5V power supply and consumes an initial acquisition current of 59mA and 33mA after 20 minutes of tracking. The default baud rate of the module is 4800 bps. The module will interface with the MCU using the 64AFCUE’s onboard SCI Module. 8.1.5 microSD Card The microSD card interfaces with the MCU via the SPI interface. The card uses a logic level of 3.3V. To compensate a voltage level translator will be used to interface the microSD card to the MCU. The GPS coordinates and flight data are all stored on the microSD card. Information on how to access the microSD card and write to it was found at the several websites [30]. -32- ECE 477 Final Report Spring 2008 8.1.6 Melexis Thermopile Tilt Sensor The tilt sensor is a setup that requires two thermopiles pointed 180 degrees from each other. The logic behind this is that the black body radiation coming from the ground is higher than that of the sky [31]. Therefore using thermopiles, the system is then able to detect the angle of tilt. Since the thermopiles only provide a 47 microvolts/degree resolution, the signal will be amplified and passed to the microcontroller using the ATD converter. The thermopiles selected are the Melexis MLX90247 [32]. 8.1.7 Servos The system will require the use of four servos in total. The plane will require 2 servos for ailerons, one for the rudder and one for the elevator. Each servo requires 5V to power and a pulse width modulated signal to determine the angle of rotation. The PWM signal will be provided by the MCU upon triggering the autopilot mode. If not in autopilot mode, a mux automatically selects the manual mode of the plane and the signals from the R600 Radio Receiver are directly transmitted to the servos. 8.1.8 HP Photosmart R707 The UAV will use a commercially available HP Photosmart R707 that has been stripped of its case and battery to take pictures at the designated waypoints. The camera is activated by pulling the required switch low. This is achieved by using a ULN2003A High-Voltage HighCurrent Darlington Transistor Array [33]. By connecting the collector to the contact of the pin and the base of the transistor to the MCU, functions such as turning on the camera, auto-focus and image capture can be done. Upon require the specific function, the MCU turns on the transistor thus sinking the pin and activating the camera. Pictures taken will be stored on an SD card on board the camera. 8.1.9 External LCD Interface A 20X4 LCD [35] using the Hitachi HD44780 [34] interface will be placed externally for diagnostics and data representation purposes. The LCD interface will use a serial RS-232 backpack to accept data. The LCD will be powered via the plane’s power supply. The LCD will -33- ECE 477 Final Report Spring 2008 be connected using the UART module available on the MCU. The default baud rate of transmission is 9600bps. 8.1.10 Brushless DC Motor A brushless DC motor will be used to replace the standard brushed DC motor on the plane due to higher voltage efficiency and lighter weight. Much similar to the servos, the DC motor is controlled by a PWM signal which will be provided by the MCU. The motor will also feature a manual override feature which will allow the user to take control of the plane during takeoff or landing. 8.2 Hardware Design Narrative The microcontroller serves as the control for directing the plane and controlling the motor speed. It will also balance the plane while the plane is in midair. The microcontroller will interface with the LCD, GPS receiver and microSD card via SCI (I2C and UART) and SPI. It will output to the servos and motor control via PWM signals and use general I/O pins for the camera. The ATD converter module is used to sample the thermopiles for tilt sensor data. 8.2.1 SCI The UART module will be used to receive data from both the GPS module and to transmit data to the external LCD. A baud rate of 9600 bps will be used for the LCD and 4800 bps for the GPS module. They use port pins PS0/RXD0, PS1/TXD0 and PS2/RXD1. 8.2.2 SPI The microSD card will utilize the SPI interface on the MCU. It uses PM5/SCK0, PM4/MOSI0, PM3/SS0, PM2/MISO0 and PM1. 8.2.3 PWM The PWM module will be used to control four servos; these will be assigned to port pins PP0, PP1, PP2 and PP3. The PWM module will also be used for motor speed control which is assigned to PP4. -34- ECE 477 Final Report Spring 2008 8.2.4 ATD The onboard ATD module will be used to sample data from the thermopiles to determine tilt angle and to check the voltage level of the system. The tilt sensing system requires 4 ATD ports which are assigned to PAD00/AN00, PAD01/AN01, PAD02/AN02 and PAD03/AN03. The voltage checking system requires one port and is assigned PAD04/AN04. 8.2.5 TIM The timing module on the system will be used to accurately keep flight time for data logging purposes. 8.2.6 General I/O General I/O pins will be used to control the camera and for diagnostic purposes. IOC pins will be used as inputs for the radio receiver. The IOC pins assigned to the radio receiver are PT0 through PT5. The pins used for the camera are PB0 through PB4. Pins PB5 and PB6 are used for diagnostic LEDs. 8.3 Summary Our most important design consideration in designing was the weight and the efficiency of our circuitry. Weight is a very big problem due to the limited lift we can achieve from the RC plane and efficiency limited our flight time. We also considered circuit size due to the limited space available on board the plane. As of such we had relatively tight constraints to work within but the team managed to come up with a reasonable design. As a result multiple iterations of designing were done to come up with an optimized design. If the design constraints are met and all flight conditions are optimal, the RC plane should achieve a reasonable amount of flight time. -35- ECE 477 Final Report Spring 2008 9.0 PCB Layout Design Considerations The purpose of Global Pigeon is to build a semi-autonomous RC plane capable of flying to GPS way points and taking photographs. To accomplish this goal, all of the planes control systems and a variety of sensors will be interfaced to a microcontroller. The microcontroller will be mounted to a PCB along with the power regulation system, SD card interface, and the IC’s required to communicate with the other components. All components except those previously mentioned are not attached to the PCB and will be mounted throughout the plane. There are two primary constraints to the design of the PCB. The first constraint is board size. Since the board must be contained within the fuselage of the plane, the board is limited to a size of 3.5”x2.5”. The second constraint is power. Every component within the plane except for the motor will be powered from the PCB. This will cause peak current draws of 3A from each power rail. This report will explain how the PCB will be designed with these constraints while still maintaining proper signal integrity and manufacturability. 9.1 PCB Layout Design Considerations – Overall The PCB layout is divided into the following major areas: digital control, digital data, analog, power, and clocking. These major areas surround the microcontroller. The primary purpose of this organization is to isolate various signals from each other in order to minimize noise [36]. All of the major IC’s and signal routing will be done on the top layer of the board. Signal routing will only be done on the bottom layer when absolutely necessary. The bottom layer will be reserved for placing passive components and power routing. All signal traces on the board will be routed with 12mil width with 12mil inter trace spacing. Due to the board’s size constraints, making the traces any wider or further apart could make it impossible to route all of the signals. Making the traces any narrower or closer together can introduce the risk of manufacturing defects. Changes to the default trace width and spacing will only be made when absolutely necessary for noise reduction purposes. The digital control area consists of the camera, radio receiver, and servo/throttle interfaces. These signals consist of general purpose I/O signals and PWM generated signals. These signals are not particularly sensitive and should be able to tolerate a minimal level of interference without any major repercussions to the system. None of these interfaces have any special component placement or routing considerations. -36- ECE 477 Final Report Spring 2008 The digital data area consists of the SPI interface to the SD card slot, and two SCI interfaces, one going to the GPS and the other to an external LCD screen used for debugging purposes. The traces used for these signals are routed as directly as possible to their respective headers. Extra consideration is taken in ensuring that no other possibly noisy traces come in proximity to these signals. Any traces which pass under these signals on another layer are routed to cross so they are perpendicular to each other. The SPI bus utilizes a clock signal which must be isolated from other signals on the board and be as short as possible. The analog area consists of the thermopile sensor interface and a voltage sensing circuit for measuring battery life. The thermopile sensors provide temperature readings by comparing the sensor’s temperature with the ambient temperature. The sensor transmits this reading by outputting an analog electrical signal which is offset from a central bias by 46 micro volts per degree Celsius [32]. These signals are fed into differential amplifiers and then sent to the microcontroller’s analog to digital convertor for reading. Due to the small voltage offset per degree temperature, the smallest amount of noise introduced to these traces can greatly throw off the reading. The operational amplifiers used in this circuit will be placed as close as possible to board headers to minimize the total distance the unamplified signal has to travel. The traces used will be wider and have increased spacing to further decrease noise. A copper pour attached to ground will also be utilized to help noise immunity [36]. Copper pours will also be utilized in the other areas of the board but will be isolated from the pour in the analog section. Component size is also a major consideration for this board. Most of the IC’s on the board come in a variety of packages. The smallest package type for each IC was chosen as long as the pin pitch was at least .5mm. A smaller pin pitch could lead to issues during board assembly with pins being shorted. The placement of the components relative to each other is another consideration. The limited area of the board forces components to be placed at close distances relative to each other. While this is good from a routing perspective, it can make it difficult to solder components to the board. All components are placed on the board in a method to ensure that one component won’t prevent the soldering of another component. There are also several surface mount resistors and capacitors that will be soldered to the bottom layer of the board. Most of these components will be 1206 size but any component which there is a large number of (such as 1k pull-up resistors) will be ordered as 0805 size to minimize area. -37- ECE 477 Final Report 9.2 Spring 2008 PCB Layout Design Considerations – Microcontroller The microcontroller utilizes six bypass capacitors in the range of 100nF to 220nF [13]. These capacitors are located directly beneath the microcontroller and have trace lengths to their respective power and ground pins of a few millimeters. The grounding system for the microcontroller must be centered on the VSSR pin and the VSSPLL pin must be directly connected to VSSR [13]. All of the ground connections must consist of low ohmic low inductance connections [13]. All of these grounding requirements will be accomplished through the use of a ground copper pour under the microcontroller. The oscillator and PLL circuits have a dedicated location on the board located directly below the microcontroller. The components used in these circuits are placed to allow direct trace connections with the minimum distance possible. No other signals can be routed through this area [13]. The crystal oscillator casing will also be connected to ground to further reduce noise in the circuit [36]. 9.3 PCB Layout Design Considerations - Power Supply The board has two primary supply voltages: 3.3V and 5V. These supplies are managed by two switching regulators. Each of these regulators has specific layout considerations. The catch diode and input capacitor must be placed close to the regulator [37]. A ground plane will be used and connected to the tab on each regulator [37]. The last specific requirement is the feedback trace for each regulator must be routed away from noise sources such as the regulator’s inductor and diode [37]. All other components related to the regulators are to be placed as close as possible [37]. Two other linear regulators will be placed on the board. These regulators will provide 2.5V and 2.8V reference voltages used by other parts on the board. The regulators require no external parts and will have at most 100mA of current draw each. These regulators will stepdown from the boards 5V supply. The board’s grounding system will consist of copper pours to create ground planes. The analog and digital sections of the board will have separate ground planes which will converge at the power supply. The digital ground plane will be further broken down. The majority of power routing will occur on the bottom layer of the board. The camera and SD card are the only components which utilize the 3.3V supply. The camera has the largest power draw of any device -38- ECE 477 Final Report Spring 2008 on board the plane at 2A. The power connector for the camera will be located next to the voltage regulators to deal with this current draw and to minimize the amount of trace routing for the 3.3V supply. All power traces will be 100mil in width. There will be a single 3.3V trace going from the power supply to the SD connector. The 5V rail will utilize a single point design. Two traces will be split off from the power supply, one leading to the analog components with the other leading to the microcontroller. The later trace will then star out to the other digital components on the board. 9.4 Summary The PCB layout is a critical component to the project’s success. The only major constraints to the PCB design are the board’s small area and current draw. These issues will be dealt with by careful component placement and allowing as much area as possible for power traces. There are few sensitive signals on the board which can be easily isolated to prevent noise issues. The power system will make extensive use of ground planes to further help noise immunity and simplify routing. Overall, the PCB layout is relatively straight forward with only a few minor issues that need to be accounted for. -39- ECE 477 Final Report Spring 2008 10.0 Software Design Considerations The majority of the software work for the project consists of interfacing to all of the peripherals. The connected devices operate on very different time scales and thus require a variety of software organization types. The tight servicing time constraints of the GPS receiver for instance, require interrupted operation whereas polling interaction is sufficient for devices like the MicroSD card. The software development began on a Freescale 9S12C32 microcontroller. This platform was chosen because it was on-hand and very similar to the 9S12A64 microcontroller [13] being used in the project. Eventually a prototype board was created with a 9S12A64 microcontroller to facilitate the porting of source code. The serial monitor application provided by Freescale was utilized to allow easy reprogramming of the microcontroller over a serial connection. 10.1 Software Design Considerations The main software design constraints in the project revolve around the communication requirements of the connected devices. Some of the devices must operate in a near real time fashion such as the GPS receiver and the radio receiver. Both of these must then be serviced using interrupts. An SCI receive interrupt ensures all of the bytes sent by the GPS receiver are stored into a buffer for later processing. Input capture interrupts are used to precisely measure edge arrival times in order to calculate the duty cycle of the radio signal. On the other hand, the MicroSD card has no real time constraints because it operates in a manner that is continuous to the SPI clock. This leads to a set of functions for SD interaction that work in a polling manner. Timing analysis indicates that SD operations take 7 ms at worst so no processing delays should arise. Like the SD interface, the camera interface has no precise timing constraints. In fact, it has an issue that is completely opposite of the other devices. Since it was designed for human use, the signals operate in human time scales. This means that signals to it must be strobed for upwards of 500 ms. The PWM and digital I/O connections can all be used in a polled manner. The overall operation of the application code is best described as flag driven. The main function runs an infinite loop that polls simple inputs as well as checking for flags set by the interrupt service routines. When one of these flags is set, a handler function is called in the main loop to process the new data. This overall setup allows for the most efficient utilization of the -40- ECE 477 Final Report Spring 2008 processor while still ensuring that input is always read correctly. A pure polling organization would lead to lost bytes from the GPS receiver and imprecise duty cycle values for the radio receiver. A purely interrupt driven solution is also not called for as many of the devices do not operate in a time critical manner. Figure F.1 contains a flowchart illustrating the basic flow of the main function. Next the operating mode of each device will be discussed. This project uses almost all of the external interfaces provided on the 80 pin package of the 9S12A64. Table 2.1 lists the port used by each device. The operating mode and initialization requirements varied between the devices. Port T0-5 is initialized to operate in input capture mode. The ISR for each of the IOC pins is written so that the trigger edge swaps on each interrupt. This allows measurement of the incoming PWM signal from the radio receiver. The PWM module in Port P is set up to output four 16 bit PWM signals at a frequency of 50 Hz. The duty cycle is varied to communicate with the servo motors. The PWM channels are set to 16 bit because the effective duty cycle for servo signals is only 5-10% [38]. Using 8 bit PWM channels would not allow for enough servo positions. The interface to the digital camera on Port B uses simple digital I/O. Port B0-2 pins are initialized as input with pull-up resistors enabled. These read the state of the camera. Port B3-6 pins are set up as output. These outputs are strobed to cause various actions in the camera. Port AD is initialized to operate as a group of ATD pins. The ATD module runs at the highest clock rate and produces 10 bit output values. Due to the relatively low frequency of ATD value requests, the ATD module operates in single channel, single conversion mode. The SCI port for the GPS receiver operates using a receiver interrupt. It is initialized to transfer at 38400 baud which is specified by the GPS manufacturer [1]. The SCI port for the 4x20 LCD display is set to communicate at 19200 baud. Both ports use 1 stop bit, no parity, and no flow control. The SPI module in Port M is used to communicate with the MicroSD card. The clock frequency is first set to 400 kHz during the card initialization phase, and then raised to 6 MHz for data transferring. The clock select line is set to be software controlled as it must be asserted for the entire duration of data transactions [39]. Port M0 is set up as a digital input with pull-up resistor enabled. It is used to detect MicroSD card insertion. The pins used for LED indicators and the autopilot selector are simple digital outputs. The LCD pushbuttons for user input are initialized as digital inputs with pull-up resistors enabled. -41- ECE 477 Final Report Spring 2008 Additionally, the timer module is initialized to cause an overflow interrupt which is used for time-stamping throughout the application. Table 10.1 – External Device Map Device Radio Receiver Servo Output Digital Camera Thermopiles GPS LCD MicroSD Indicator LEDs LCD Pushbuttons Autopilot Selector Port Port T (IOC) Port P (PWM) Port B Port AD SCI0 SCI1 Port M (SPI) Port A Port J Port T6 The memory mapping used in the software development of this project is relatively straight forward. A small memory model was utilized to remove the overhead of dealing with banked memory accesses. Although this choice limits the total amount of flash memory that is accessible for application code, no ill effects are expected as the code should be able to easily fit into the smaller amount of memory. Using the single chip operating mode, two 16 kB blocks of flash memory are available along with 4 kB of SRAM. Table 2.2 illustrates the location of each item in the address spaces. These locations were chosen in accordance with the manufacturer requirements [13]. The upper 2 kB of the second flash memory block is reserved for the serial monitor application code which allows reprogramming over a serial connection. Both instructions and static data will be stored in the flash blocks. The stack will grow down from 0x4000. Since the application does not utilize dynamic data allocation, no heap is required. Table 10.2 – Memory Map 0x0000 - 0x03FF 0x3000 - 0x3FFF 0x4000 - 0x7FFF 0xC000 - 0xF7FF 0xF800 - 0xFF7F 0xFF80 - 0xFFFE Device Registers RAM ROM 1 - Application Code ROM 2 - Application Code ROM 2 - Serial Monitor Interrupt Vectors -42- ECE 477 Final Report Spring 2008 It would be relatively simple to add a self testing mode into the final application; however, no provision currently exists. Alternatively, a compile time debugging scheme is being employed. This utilizes conditionally compiled SCI output statements to enable the printing of debug messages and other values while developing the software. Conditional compilation ensures that there is no overhead when not debugging. The BDM connector can also allow for debugging while in lab. 10.2 Software Design Narrative 10.2.1 Main The main function for the project has been used to test and ensure proper functionality of all of the code modules. It consists of a main loop that runs forever. This loop responds to flags set by interrupts as well as to poll various I/O devices. The main module maintains several state variables which are modified using functions from the other modules. This practice leads to writing as much code as possible in the other modules instead of in the main function. The current setup logs GPS coordinates, thermopile readings, and radio inputs to the MicroSD card every 0.1s. It also allows photographs to be taken manually using the switches on the radio transmitter. 10.2.2 Radio The radio module provides an interface to the radio receiver. The radio receiver outputs 6 servo signals. Each signal consists of a 1-2ms pulse every 20ms [38] which corresponds to the position of the joystick on the radio transmitter. The radio module software contains an input capture interrupt function for each of these radio channels. Each interrupt initially triggers on a rising edge, then toggles between triggering on rising and falling edges as execution continues. This technique is required instead of triggering on either edge so that microcontroller always knows that it is measuring the 1-2ms on pulse instead of the 18-19 off pulse. When an interrupt occurs, the value of the input capture register is saved. On each falling edge event capture, the difference between times is calculated and stored. Finally, a flag is set which can be monitored with a public function to signal the main loop that new data is available. A further function is -43- ECE 477 Final Report Spring 2008 provided to read the values. If radio pass through has been enabled using another function, then the measured input values are immediately passed to the PWM module to drive the servos. 10.2.3 Servo The servo module contains an initialization function to set up the 8 8-bit PWM channels to operate in concatenation mode as 4 16-bit PWM signals. Each has its clock and period registers set to achieve 50 Hz output in accordance with the servo standard. The 16-bit PWM signals are needed to ensure that the microcontroller has fine control of the servo motor positions. Several private helper functions are included to simplify the coding. The only important public function is used to set the servo positions. It accepts a signed input value then shifts and scales it appropriately before using it to set a PWM duty cycle register. 10.2.4 Camera This module provides a simple interface to an HP Photosmart R707 digital camera. The microcontroller must be able to hold signals going to the camera high for around 500 ms without wasting time that could be used in more time critical functions. The technique used in this module is to maintain a queue of commands to issue to the camera. It contains a function that is called periodically in the main loop which checks how long the current command has been occurring. If a sufficient time has elapsed, the signal associated with the command is deasserted and the next command is issued. A second function can be called to issue new commands. The commands correspond to characters in a circular buffer. Strobe timing is achieved using the timestamp function provided in the timer module. The microcontroller is able to turn the camera on and off, make it auto focus, trigger the shutter, and record video clips. 10.2.5 SCI This is a pretty straight forward module. It provides a wrapper around the SCI registers in order to give calling functions simple access to serial communications. Functions are provided to input and output characters. Additional functions allow for the output of unsigned 16-bit integers, unsigned 32-bit integers, signed 16-bit integers, signed 32-bit integers and hexadecimal characters. -44- ECE 477 Final Report Spring 2008 10.2.6 GPS The GPS module interacts with an ETek EB-85A 5Hz GPS receiver. The initialization function sends out a control string which tells the GPS receiver to output a minimal set of NMEA sentences in accordance with the user manual [1]. The module contains an SCI receiver interrupt to handle the buffering of incoming NMEA sentences. It is designed to begin buffering when a NMEA preamble is received. It sets a flag when the NMEA sentence ends and begins filling a different buffer. A second function is used to parse the NMEA sentences into useable data. It loops over the characters and forms integer values. The main loop is then able to use this data for navigation. 10.2.7 MicroSD The code for this module was based off of shareware code found on the FlashGenie website [40]. The code was adapted to this project by removing unneeded features and simplifying function execution. Three major functions are provided to initialize an SD card, to perform a block read, and to perform a block write. The SD card can only operate with 512 byte blocks of data. Each of these functions repeatedly sends commands to the SD card until an appropriate response is received. In the case of the write function, 512 bytes are shifted out of the SPI register after receiving a valid response from the SD card. The read function operates in a similar fashion except that it shifts data in instead of out. 10.2.8 Timer This module contains a timer overflow interrupt to increment a counter, several blocking wait functions, and a time-stamping function. The time-stamping function returns a 32-bit integer that is the concatenation of the count maintained by the TOF interrupt and the free running clock, TCNT. 10.2.9 Navigation The navigation module is used to level the plane based on the thermopile readings as well as to turn the plane in order to reach GPS waypoints. Both of these tasks are accomplished using closed loop control algorithms. The navigation module contains a generic PID updating function used for both navigation and stabilization. The coefficients required for each action have to be -45- ECE 477 Final Report Spring 2008 determined experimentally based initially on recorded manual flight data. An RTI interrupt is used to measure the thermopile values at 325Hz. The last 8 values for each thermopile are averaged together then an output control effort is calculated at 10Hz. Navigation control changes occur at 10Hz as well. The change between autopilot and manual control occurs when the user flips a switch on the radio transmitter which is connected to an auxiliary radio channel. Figure F.2 shows the overall hierarchy of these modules. 10.3 Summary The software development for this project mainly consists of writing drivers for the plethora of external devices utilized. The overall organization of the application code was determined by the timing requirements of these devices. Devices with tight timing constraints are serviced by interrupts. Other devices are polled for data. The state of the software is quite far along. Almost all of the driver code has been written and is working properly. The only major tasks remaining are the writing of stabilization and navigation algorithms as well as writing a finalized main function. -46- ECE 477 Final Report Spring 2008 11.0 Version 2 Changes The most obvious required change to the project would be to provide better shielding and isolation between the various electronic components. The largest problem encountered with the plane was one of RF interference. This single problem prevented the necessary field testing required in order to design and calibrate the navigation and stabilization software. This stopped the project from meeting the final success criteria. Another change to the project would be to utilize a barometric altimeter for altitude measurements instead of relying on the GPS. The GPS module can provide the necessary altitude information but does not have the needed level of accuracy and consistency required. Due to the inability to go airborne with the plane’s circuit board active we were unable to determine if the thermopile tilt sensing system would work properly. Possible changes to this system include utilizing either commercially available tilt sensors or gyroscopes instead of the thermopiles. The major setback to any of the above changes to the design is that they add additional cost to an already expensive project. Choosing a different airplane or camera would have been useful as well. The chosen mounting method is both not aerodynamic and not elegant. Placing the camera inside of the fuselage would be a much cleaner approach. If the project were to be used for long duration flights, a higher capacity battery would be useful. -47- ECE 477 Final Report Spring 2008 12.0 Summary and Conclusions Throughout the semester we utilized a variety of hardware and software design skills and learned many aspects of real world product development. Our previous ECE coursework provided us with the foundations of good engineering design practices culminating with this course which taught us to bring everything together. One of the important new hardware skills we learned is how to create a printed circuit board from a hardware schematic. This required us to learn how to fully utilize commercial design software to create the circuit board. An important aspect learned during the PCB development is that even though a design looks good on a schematic, it still must be able to translate into something physical to be useful. -48- ECE 477 Final Report Spring 2008 13.0 References [1] Etek, “EB-85A User’s Manual,” [Online Document], September 2006, [cited 28 January 2008] http://www.sparkfun.com/datasheets/GPS/EB-85A_UserManual.pdf [2] “microSD Card Pinout,” [Online Document], 2008 January, [cited 28 January 2008], http://www.interfacebus.com/MicroSD_Card_Pinout.html. [3] “Factsheets: MQ-1 Predator Unmanned Aerial Vehicle,” [Online Document], 2007 September, [cited 30 January 2008], http://www.af.mil/factsheets/factsheet.asp?fsID=122. [4] Merle, Renae, “Price of Global Hawk Surveillance Program Rises,” The Washington Post, [Online Document], 7 December 2004, [cited 30 January 2008], http://www.washingtonpost.com/wp-dyn/articles/A41769-2004Dec6.html. [5] Freescale, “S12E Product Summary Page,” [Online Document], [cited 30 January 2008], http://www.freescale.com/webapp/sps/site/prod_summary.jsp?code=S12E&nodeId=016246 8636K100. [6] Freescale, “S12A Product Summary Page,” [Online Document], [cited 30 January 2008], http://www.freescale.com/webapp/sps/site/prod_summary.jsp?code=S12A&nodeId=01624 68636K100. [7] “Autocar Project, [Online Document], 2007 August, [cited 30 January 2008], http://autocar.sourceforge.net/. [8] Garmin, “GPS 15 Technical Specifications,” [Online Document], 2004 April, [cited 30 January 2008], http://www8.garmin.com/manuals/GPS15_TechnicalSpecification.pdf. [9] “Digi-Key – 342-1041-5-ND (Honeywell SSEC – HMC6352),” [Online Document], 2008 January, [cited 30 January 2008], http://search.digikey.com/scripts/DkSearch/dksus.dll?Detail?name=342-1041-5-ND. [10] Dorfman B.M., Manber U., Gold J.A., “System and method for automatically collecting images of objects at geographic locations and displaying same in online directories,” U.S. Patent No. 7155336, Mar. 24, 2004. [11] Dockter G.E., Caldwell D.G., Graham J., “Precision approach and control,” U.S. Patent No. 20080071431, Sept. 19, 2006. [12] Cox B., Dews H., Nyroth N., “Unmanned airborne reconnaissance system,” U.S. Patent No. 7014141, July 12, 2002. [13] Motorola, “MC9S12DJ64 Device User Guide,” Apr. 2005. [Online]. Available: http://www.freescale.com/files/microcontrollers/doc/data_sheet/9S12DJ64DGV1.pdf [Accessed: Apr. 2, 2008]. -49- ECE 477 Final Report Spring 2008 [14] Department of Defense, “Military Handbook – Reliability Prediction of Electronic Equipment,” MIL-HDBK-217F, Feb. 1990. [Online]. Available: http://cobweb.ecn.purdue.edu/~dsml/ece477/Homework/CommonRefs/Mil-Hdbk-217F.pdf [Accessed: Apr. 2, 2008]. [15] National Semiconductor, “Simple Switcher 5A Step-Down Voltage Regulator with Adjustable Current Limit,” LM2679, Feb. 2008. [Online]. Available: http://cache.national.com/ds/LM/LM2679.pdf [Accessed: Apr. 2, 2008]. [16] Texas Instruments, “4-Bit 1-of-2 FET Multiplexer/Demultiplexer,” SN74CBT3257, Jan. 2004. [Online]. Available: http://focus.ti.com/lit/ds/symlink/sn74cbt3257.pdf [Accessed: Apr. 2, 2008]. [17] IEEE, “IEEE Code of Ethics,” [Online Document], 2006, [accessed April 11, 2008], http://www.ieee.org/portal/pages/iportals/aboutus/ethics/code.html [18] J. Wang and J. Xu, “Environmental Implications of PCB Manufacturing in China,” in Electronics and the Environment, 2004, Conference Record, 2004, pp 156-158. [19] Advanced Circuits RoHS, “RoHS Compliance Printed Circuit Boards,” [Online Document], 2007, [Accessed April 24, 2008], http://www.4pcb.com/index.php?load=content&page_id=17 [20] National Safety Council, “Lead Poisoning,” [Online document], 2004, [accessed April 10, 2008], http://www.nsc.org/library/facts/lead.htm [21] GRIST environmental news & commentary, “Making green computing even greener,” [Online document], 2007, [accessed April 11, 2008], http://gristmill.grist.org/story/2007/2/26/112028/857 [22] TCI Inc, “Services,” [Online Document], 1998, [accessed April 25, 2008], http://www.tcipcb.com/service.html [23] Toxco Inc, “About Battery Recycling”, [Online Document], 2003, [accessed April 25, 2008], http://www.toxco.com/aboutrecycle.html [24] Chris Anderson, “Geocrawler 5 (Predator airframe and Picopilot autopilot,” Posted to http://diydrones.com/profiles/blog/show?id=705844%3ABlogPost%3A787, June 16, 2007. [25] Chris Anderson, “Auto-stabilized camera mount 2.0: better, cheaper, faster,” Posted to http://diydrones.com/profiles/blog/show?id=705844%3ABlogPost%3A2525, December 8, 2007. -50- ECE 477 Final Report Spring 2008 [26] Chris Anderson, “Turning an EasyStar into a proper camera platform,” Posted to http://diydrones.com/profiles/blog/show?id=705844:BlogPost:4251&page=1#comment705844:Comment:4289, September 17, 2007 [27] Chris Anderson, “World’s cheapest aerial video platform,” Posted to http://blog.wired.com/geekdad/2007/03/worlds_cheapest.html, March 19, 2007. [28] Hobby Lobby, “Graupner SPEED 400 Electric Motors from Hobby Lobby,” [Online Document], [cited 7 February 2008], http://www.hobby-lobby.com/speed400.htm [29] RC Universe, “Mega 16/15/4,” [Online Document], [cited 7 February 2008], http://www.rcuniverse.com/product_guide/enginespecs.cfm?engine_id=1106 [30] Chan, “How to Use MMC/SDC,” [Online Document], Unknown Publication Date, [Accessed 14 February 2008], http://elm-chan.org/docs/mmc/mmc_e.html [31] B. Taylor, C.Bil, S. Watkins and G. Egan, “Horizon Sensing Attitude Stabilisation: A VMC Autopilot,” in 18th International UAV System Conference, 2003, pg 1-9. [32] Melexis, “MLX90247 family Discrete Infrared Thermopile Detectors,” [Online Document], October, 2007, [Accessed 14 February 2008], http://www.melexis.com/Asset.aspx?nID=4763&sCmd=download [33] Texas Instruments, “ULN2001A, ULN2002A, ULN2003A, ULN2004A, ULQ2003A, ULQ2004A High Voltage High Current Darlington Transistor Array,” [Online Document], June, 2004, [Accessed 14 February 2008], http://www.ti.com/lit/gpn/uln2003a [34] XIAMEN OCULAR, “GDM2004D Specifications of LCD Module,” [Online Document], December, 2003, [Accessed 14 February 2008], http://www.sparkfun.com/datasheets/LCD/GDM2004D.pdf [35] Spark Fun Electronics, “SerLCD v2.5 Serial Enabled LCD,” [Online Document], May, 2006, [Accessed 14 February 2008], http://www.sparkfun.com/datasheets/LCD/SerLCD_V2_5.PDF [36] Motorola, “System Design and Layout Techniques for Noise Reduction in MCU-Based Systems,” [Online Document], 1995, [cited 21 February 2008], http://cobweb.ecn.purdue.edu/~dsml/ece477/Homework/CommonRefs/AN1259.pdf. [37] National Semiconductor, “Simple Switcher PCB Layout Guidelines,” [Online Document], July 2002, [cited 21 February 2008], http://www.national.com/an/AN/AN-1229.pdf. [38] SuperDroid Robotics, Inc. “RC (Remote Control) Support Page,” 2006. [Online]. Available: http://www.superdroidrobots.com/product_info/RC.htm [Accessed: Mar. 18, 2008]. -51- ECE 477 Final Report Spring 2008 [39] SanDisk Corporation, “SanDisk SD Card Product Manual V2.2,” Document No. 80-1300169, Nov. 2004. [Online]. Available: http://www.flashgenie.net/productmanualsdcardv2.2final.pdf [Accessed: Mar. 18, 2008]. [40] Issole Informatiue, “FlashGenie DSP and MMC / SD-Card Module,” 2008. [Online]. Available: http://www.flashgenie.net/index.html#code [Accessed: Mar. 18, 2008]. -52- ECE 477 Final Report Spring 2008 Appendix A: Individual Contributions A.1 Contributions of David Collins: To facilitate collaborative working, I set up several Google documents and AIM chat sessions to allow for virtual meetings. This made it possible for us to talk about a task at hand while simultaneously editing a document together. Virtual meetings also enabled each member to multitask and work on other activities which would not have been possible in a typical meeting environment. I was responsible for all of the software design and development. This was a natural choice as I was able to reuse a lot of the source code I had written for my Mini-project in ECE 362. Software development began on a Freescale 9S12C32 development board because we were unable to locate a development board for the 9S12A64. The use of the smaller microcontroller only really limited the number of peripherals which could be worked on simultaneously. I developed code on the 9S12C32 for the first half of the semester. In order to design drivers for each of the devices in our project, I built prototype circuits on a breadboard. The first device I worked with was the HP Photosmart R707 digital camera. I took it apart and removed as many components as possible to reduce its overall weight. I found that activating the buttons on it simply required pulling one side of switch to ground. This was achieved in the test setup using a Darlington array. I next researched how to interface to SD cards. The only major consideration is that SD cards operate at 3.3V instead of 5V. I made a converter using an open-drain inverter, normal inverter, and several resistors. I found source code online to model and wrote a driver to handle SD card interaction. After receiving a radio system donated by Ron Needham, I wrote drivers for servo control and radio signal measurement. I found that it was possible for servos to be driven significantly beyond the normal operating range. This meant that it was possible for the auto-pilot mode to have more aggressive control over the control surfaces of the plane than was possible in manual mode. In order to ensure that the operator always has the ability to switch back to manual control, I designed a circuit to monitor the auxiliary radio channel and switch the servo multiplexer accordingly. I produced an OrCAD drawing of the circuit and also explained the function and part choices for the other areas of my prototype to Matt so that he could create the schematic for the PCB. A-1 ECE 477 Final Report Spring 2008 Around the middle of the semester, I put together a 9S12A64 prototype board using a breakout board, some precise dremel cutting, and a lot of jumper wires. I ported the existing code base over to the new microcontroller and continued further development using it. When the EB-85A GPS module arrived, I began writing a driver to receive data from it. This functioned basically like an interrupt driven scanf with buffering. The system proved to be robust and was used to log several car rides in conjunction with the MicroSD card. One of the last major coding achievements involved functions to calculate the distance and direction between GPS waypoints. The method I chose to use involved a cosine lookup table to avoid the overhead of floating point emulation. Later I wrote code to perform a PID control loop and set it up to measure the thermopile sensor readings. Once the voltage regulation circuits had been attached to the PCB and tested, I soldered on the microcontroller, clock circuit elements, bypass capacitors, and LEDs to ensure that I could write a program onto the microcontroller and make it run. Programming it over the BDM cable worked on the first try. Other team members continued the population of the rest of the components. However, as I tested out various code modules, I found that several functions did not work. After many hours of debugging, I figured out that some of the ICs had not been soldered properly. I then had to go through and resolder, then examine all of the ICs on the PCB. As the project neared completion, I took over responsibility for the soldering of external connectors going to each of the off board devices. This also included building a box to house an LCD and several selector buttons. I additionally handled the final assembly of the project. I figured out a way to securely attach the PCB onto the cockpit of the plane using a pair of aluminum skis. The camera mount ended up being the most cumbersome attachment to the plane. I cut a slot into a large piece of foam to ensure that the camera would not be damaged even if its lens was extended while landing. I used small pieces of foam to attach the thermopiles and GPS receiver. As far as documentation goes, I was responsible for submitting the Software Design Considerations homework and the Reliability and Safety Analysis homework. I updated the layout of the website in the last week of the semester to ensure that everything looked good for the archive CD. During the initial phase of the project, I played a large role in determining which plane to buy as well as other major components selections. A-2 ECE 477 Final Report Spring 2008 A.2 Contributions of Matt Ligocki: My primary contributions to the project were the hardware design and PCB layout. My initial work involved component selection, specifically choosing the microcontroller and GPS modules. I also was responsible for maintaining the team’s tablet PC and installed any additional software we would require during the semester. Once the major components were selected I began schematic work and was responsible for maintaining the master schematic. My contributions to the schematic included the microcontroller circuitry, GPS interface, SD interface, external interfacing circuits (BDM, LCD, radio etc.) power supply, and parts of the plane control system circuitry. I also created most of the custom symbols used in the schematic. When the schematic was mostly completed I was responsible for the PCB layout. I performed the place and route of the entire board and created all of custom footprints required including the MicroSD connector. Since our board design utilized 0805 size discrete components which are not supplied in lab, I researched and bought all of the necessary discrete components required for board assembly. I was also responsible for tracking the master bill of materials for the board and ensured that all parts were either being ordered or sampled and would arrive in time for the PCB check off date and board assembly. With all of the hardware design work completed my responsibilities shifted into helping where needed. When the PCB arrived I inspected the board to ensure that there were no manufacturing defects. During the assembly phase I performed minor soldering work but left the majority of the soldering to my teammates since I lacked previous soldering experience. My primary contribution during this phase of the project was checking the board during the assembly phase to ensure that components were properly soldered and that the various components were working correctly. I was also responsible for researching and ordering any final miscellaneous components that were required during final assembly. During the final weeks of the project I began to take more of an organizational role making sure that the final required documentation was completed and breaking up the remaining work amongst the team. My final contribution to the project is organizing this final report. A-3 ECE 477 Final Report Spring 2008 A.3 Contributions of Daniel Bixby: At the start of the project I helped the team brainstorm ideas. I spent time researching different methods for mounting a digital camera on an RC plane. I investigated the dimensions of our original plane selection along with those of the major components and researched how best to fit them in the plane. I was in charge of the research, selection, and purchasing of several of the major design components. During this time, I consulted several sources including local hobbyists and, more often, online forums. Besides researching pure numbers, it was helpful to have the input of folks who had “been there and done that,” as I had virtually no experience with RC planes. This included the battery which had to sufficiently power the plane and the PCB while allowing for up to 30 minutes of flying time. I also had to find an upgrade to the existing motor and electronic speed controller. We needed a brushless motor that would provide enough power to keep the plane aloft. I spent time studying the electrical characteristics of several different motors. Upon selecting the motor, I studied different gear ratios to keep the motor spinning at a reasonable speed. I also had to research and select a new folding propeller as the old one was not compatible with the upgraded motor/gearbox, ensuring that its maximum speed would not be exceeded. I was also responsible for selecting a lithium-polymer balance charger for the project. I looked at many different possibilities. Originally we wanted one that would plug into the wall without requiring a DC power supply. It was difficult to locate one that met these requirements without featuring a painfully slow charging time. In the end I ordered a balance charger with a maximum 5-amp draw while constructing my own power source from an old ATX supply. I made slight modifications to the plane such as hollowing out the cockpit plug to make room for the PCB. I devised and implemented an initial method for mounting the camera and larger battery, though this was revised as the semester went on. I spent time in physical construction of the plane, getting it ready to fly with the existing components. This involved soldering down the components and researching/buying the necessary accessories (glue, connectors, etc.) online or from the local hobby store. As the semester progressed, I assisted David with several test flights of the plane. It has been quite the learning experience for me, as I knew next to nothing of RC planes prior to this project. I’ve been able to interact with a lot of different people who were more experienced, and A-4 ECE 477 Final Report Spring 2008 I learned more with each step of the way. Documentation I was solely responsible for included the packaging specifications, patent liability analysis, and team poster. A-5 ECE 477 Final Report Spring 2008 A.4 Contributions of Paul Ng: I successfully designed the electrical parts of the circuitry and schematics. I designed the circuitry for the switching regulators using the LM 2679-3.3 and 5.0 regulators. The circuitry involves a current limiting resistor which I selected so that the maximum current draw from the regulator is 5A. Initially I had increased the size of the decoupling capacitor in case of necessary need for instantaneous power. However Matt changed the profile of the device to a smaller capacitor for sizing reasons. I put together the schematic for the entire project for the fifth homework. I also designed the thermopile setup using the AD8626 op-amp circuitry. The setup uses a Melexis Thermopile and a JFET OPAMP to amplify the output. The setup would receive the voltage from the thermopile and amplify it 1000 times to a suitable voltage that could be read by the microcontroller. This setup allows the plane to detect tilt using thermal signature of the ground versus the sky. I also successfully tested the thermopile setup. It was able to detect the heat signatures from the ground successfully. This would allow the plane to navigate by adjusting the turn ratio of the ailerons depending on how much heat each thermopiles see. Using the four thermopiles, the plane would be able to control its yaw, row and pitch axes. With David’s navigation software, the plane will be able to fly successfully. I spent several hours soldering together most of the PCB. I also fixed some errors on the PCB that needed to be fixed. For example, the Schottky Diodes were soldered on forward biased instead of reverse. Overall the process was relatively successful and I managed to get the LM2679 regulators working with the desired output. The regulators output were able to output about 3.3V and 5V however they had more ripple voltage than initially expected. I helped assemble the new plane when the parts were fully available to us. I also participated in the required testing phase of the project by participating in the testing of the plane. We managed to get some decent flight out of the plane however towards the later part of the testing; we encountered some unexpected form of RF interference with the Electronic Speed Controller. Towards the end of the project, I also spent several hours attempting to fix the broken GPS module that had fallen apart during the course of testing. I met with Prof William Chappell to discuss the options available to me. I attempted to fix the product several times with the assistance of Dave Azpell and Charles Barnett but the device was non functional. The only option left was to purchase a brand new GPS module. A-6 ECE 477 Final Report Spring 2008 Appendix B: Packaging Figure B-1: Easy Glider Plane ( 71” wingspan, 43” length) shown in scale comparison with (A) digital camera (2.5” by 3.5”), (B) PCB of estimated size (2.5” by 3.5”), (C) thermopiles and D) GPS module in their foam boxes, (E) upgraded motor driven by ESC with gearbox connected to prop, and F) LiPo battery in its slot between the wings. These are shown with their respective locations in the plane. The GPS module box is mounted atop the tail. The thermopiles box is mounted on top of the plane between the wings. The camera and its box go directly underneath the fuselage, while the PCB rests on the edges of the cockpit area. B-1 Figure C.1: Microcontroller C-1 R53 1k D4 LED0 R54 1k D5 LED1 R55 1k D6 LED2 3 2 1 J23 BOOT 5V 5V 5V C3 0.1uF C6 0.22uF C4 0.22uF C2 0.22uF C1 0.22uF CAM_PW CAM5_IN CAM4_IN CAM3 CAM2 CAM1 CAM0 RADIO_AUX RADIO_AUTO RADIO_ELEVATOR RADIO_RUDDER RADIO_AILERON RADIO_THROTTLE AUTOPILOT THROTTLE AILERON RUDDER ELEVATOR 59 62 77 76 29 28 49 50 9 10 16 17 18 19 20 21 22 23 41 42 43 44 45 46 47 48 5 6 7 8 11 12 13 14 78 79 80 1 2 3 4 MC9S12A64CFUE VDDA VSSA VDDX VSSX VDDR VSSR VDD2 VSS2 VDD1 VSS1 ADDR0/DATA0/PB0 ADDR1/DATA1/PB1 ADDR2/DATA2/PB2 ADDR3/DATA3/PB3 ADDR4/DATA4/PB4 ADDR5/DATA5/PB5 ADDR6/DATA6/PB6 ADDR7/DATA7/PB7 ADDR8/DATA8/PA0 ADDR9/DATA9/PA1 ADDR10/DATA10/PA2 ADDR11/DATA11/PA3 ADDR12/DATA12/PA4 ADDR13/DATA13/PA5 ADDR14/DATA14/PA6 ADDR15/DATA15/PA7 IOC0/PT0 IOC1/PT1 IOC2/PT2 IOC3/PT3 IOC4/PT4 IOC5/PT5 IOC6/PT6 IOC7/PT7 PWM7/KWP7/PP7 PWM5/KWP5/PP5 PWM4/KWP4/PP4 PWM3/KWP3/PP3 PWM2/KWP2/PP2 PWM1/KWP1/PP1 PWM0/KWP0/PP0 U1 VREGEN VRH VRL VDDPLL VSSPLL XFC EXTAL XTAL MODC/TAGHI/BKGD RESET TEST XCLKS/NOACC/PE7 MODB/IPIPE1/PE6 MODA/IPIPE0/PE5 ECLK/PE4 LSTRB/TAGLO/PE3 R/W/PE2 IRQ/PE1 XIRQ/PE0 PM5/SCK0 PM4/MOSI0 PM3/SS0 PM2/MISO0 PM1 PM0 PJ7/KWJ7/SCL PJ6/KWJ6/SDA PS0/RXD0 PS1/TXD0 PS2/RXD1 PS3/TXD1 PAD00/AN00 PAD01/AN01 PAD02/AN02 PAD03/AN03 PAD04/AN04 PAD05/AN05 PAD06/AN06 PAD07/AN07/ETRIG0 67 60 61 31 33 32 34 35 15 30 36 24 25 26 27 37 38 39 40 70 71 72 73 74 75 68 69 63 64 65 66 51 52 53 54 55 56 57 58 5V Date: Size A Title 5V C5 0.1uF R1 10M Y1 8MHz 3300pF C9 22pF 22pF C8 C7 Tuesday , April 01, 2008 Sheet 1 Clock Circuit [M68MOD912C32] 3K9 R2 330pF C10 PLL Filter [M68MOD912C32] Document Number Microcontroller BKGD RESET SCLK DI !CS DO SD_IN LCD_DETECT LCD_PB1 LCD_PB0 GPS_TX1 GPS_RX1 LCD_TX LCD_RX THERM0 THERM1 THERM2 THERM3 VSENSE of 1 Rev 3 ECE 477 Final Report Spring 2008 Appendix C: Schematic Figure C.2: Control system C-2 AILERON_L AILERON_R J13 J14 THROTTLE J12 1 2 3 1 2 3 1 2 3 RADIO_AUX 5V 5V 5V 40.2k R48 C48 1uF RADIO_AILERON AILERON RADIO_THROTTLE THROTTLE 40.2k C47 1uF R49 5V 1 2 3 4 5 6 7 8 R51 1k R50 6.98k Vcc OE 4B1 4B2 4A 3B1 3B2 3A U18 -In V+ R52 100k 16 15 14 13 12 11 10 9 5V TLV3491 OUT V+In SN74CBT3257 S 1B1 1B2 1A 2B1 2B2 2A GND U13 1 2 3 5V R40 1k 5 4 Date: Size A Title C50 10uF Tuesday , April 01, 2008 Document Number Plane Control Sy stem RADIO_ELEVATOR ELEVATOR RADIO_RUDDER RUDDER C49 10000pF 5V 5V 1 2 3 Sheet 1 2 3 1 2 3 1 ELEVATOR J16 RUDDER J15 AUTOPILOT SELECT_JUMPER J21 of 1 Rev 1 ECE 477 Final Report Spring 2008 GPS_RX1 GPS_TX1 5V 5V 1 2 3 4 1 2 3 4 Figure C.3: GPS C-3 SN74LVC2T45 VCCA VCCB A1 B1 A2 B2 GND DIR U16 SN74LVC2T45 VCCA VCCB A1 B1 A2 B2 GND DIR U15 8 7 6 5 8 7 6 5 5V R46 1k R45 1k R47 1k ON/OFF R44 1k 5V 3 U17 1 Vin GND 2 R43 1k 5V 5 LP2981-2.8 Vout Date: Size A Title 1 2 3 4 GPS 1 2 3 4 CON4 5 6 7 8 - J22 Pinout Vin GND TX1 RX1 TX2 RX2 1PPS BAT Thursday , February 28, 2008 Document Number GPS 5V Sheet 1 of 1 Rev 1 ECE 477 Final Report Spring 2008 CAM0 CAM1 CAM2 CAM3 BKGD 5V R3 4K7 BDM 2 4 6 1 2 3 4 5 6 7 8 Figure C.4: External Interfaces C-4 1C 2C 3C 4C 5C 6C 7C COM ULN2003A 1B 2B 3B 4B 5B 6B 7B E U11 CHECK PIN ARRANGEMENT AGAINST REAL BDM 1 3 5 BDM Connector [AN2727] J1 16 15 14 13 12 11 10 9 5V R4 10k CAM4_IN CAM5_IN CAM_PW RESET 3.3V 1 2 1 2 3 4 5 6 7 CAMERAPOW J20 CAMERA J19 C35 0.33uF C33 0.047uF C34 0.33uF Date: Size A Title C36 0.33uF 5V MAX3227 READY FORCEOFF C1+ Vcc V+ GND C1DOUT C2+ FORCEON C2DIN VINVALID RIN ROUT U12 Saturday , March 01, 2008 Document Number Interf acing 1 2 3 4 5 6 7 8 5V R38 1K Sheet 1 1 2 3 4 5 6 7 LCD_TX LCD_RX LCD_DETECT LCD_PB0 LCD_PB1 R39 1K 16 15 14 13 12 11 10 9 5V RADIO_AUX RADIO_AUTO RADIO_RUDDER RADIO_ELEVATOR RADIO_AILERON RADIO_THROTTLE 5V of LCD J18 1 2 3 4 5 6 7 8 1 5V RADIO J9 Rev 1 C32 0.1uF ECE 477 Final Report Spring 2008 C25 10uF C27 10uF C52 0.1uF C51 0.1uF C26 3300pF 7 2 C28 3300pF 7 2 SS IN U6 SS IN U7 3.9k 6 1 3 D3 10V R16 8.25k 1 R15 8.25k 10000pF C15 LM2679SD-3.3 SW C BOOST 3 10000pF C22 LM2679SD-5.0 SW C BOOST FB 1 2 J17 POWER 5 I ADJ 6 FB C-5 I ADJ Figure C.5: Power Supply 5 R19 D1 SK32-7 15uH L1 D2 SK32-7 15uH L2 C29 0.047uF Date: Size A Title C45 150uF C43 150uF VSENSE 3.3V 5V Saturday , March 01, 2008 Document Number Power Supply C44 150uF C42 150uF R21 8.25k R20 10k Sheet 1 of 1 Rev 1 ECE 477 Final Report Spring 2008 DO SCLK !CS DI R8 1K 5V 5V 5V 1 2 3 4 1 2 3 4 1 2 3 4 Figure C.6: microSD C-6 SN74LVC2T45 VCCA VCCB A1 B1 A2 B2 GND DIR U4 SN74LVC2T45 VCCA VCCB A1 B1 A2 B2 GND DIR U3 SN74LVC2T45 VCCA VCCB A1 B1 A2 B2 GND DIR U2 8 7 6 5 8 7 6 5 8 7 6 5 3.3V 3.3V 3.3V R11 1K 5V R9 1K 5V R7 1K R12 1K 3.3V 3.3V SD_IN R14 R6 49.9k 49.9k 3.3V 3.3V J2 Date: Size A Title SD CONN 1 2 3 4 5 6 7 8 9 10 R5 49.9k Saturday , March 01, 2008 Document Number <Doc> SD Card SD Card Circuit Pinout 1 - RSV 2 - CS 3 - DI 4 - VDD 5 - SCLK 6 - VSS 7 - DO 8 - RSV 9 - Insert Detect (Back) 10 - Insert Detect (Side) Sheet 1 of 1 Rev 1 ECE 477 Final Report Spring 2008 C-7 5V ON/OFF LP2981-2.5 3 R42 1k U14 5V 1 Vin GND 2 Vout 5 2.5V Reference THERM2 R23 100 R22 100k AD8626 OUT A V+ -IN A OUT B +IN A -IN B V+IN B 8 7 6 5 AD8626 OUT A V+ -IN A OUT B +IN A -IN B V+IN B 8 7 6 5 Date: Size A Title C31 0.047uF J4 THERM1 Saturday , March 01, 2008 Document Number <Doc> Thermopile C30 0.047uF J5 THERM3 Thermopile Circuit Pinout 1 - IR+ 2 - IR- 1 2 3 4 U10 5V Thermopile Circuit Pinout 1 - IR+ 2 - IR- 1 2 3 4 U9 J6 THERM2 R29 100 R28 100k J3 THERM0 2 1 5V 1 2 2 1 Figure C.7: Thermopile 1 2 THERM0 R27 100 THERM3 THERM1 Sheet R26 100k R25 100 R24 100k 1 of 1 Rev 3 ECE 477 Final Report Spring 2008 ECE 477 Final Report Spring 2008 Appendix D: PCB Layout Top and Bottom Copper Figure D.1: PCB top copper and silk screen D-1 ECE 477 Final Report Spring 2008 Figure D.2: PCB bottom copper and silk screen D-2 ECE 477 Final Report Spring 2008 Appendix E: Parts List Spreadsheet Vendor Freescale Etek Tower Hobbies RC World of Planes Draganfly Innovations David Collins Newegg Mouser Digikey Atlanta Hobby Tower Hobbies Hobby Lobby Hobby Lobby Hobby Lobby Newegg EBay Manufacturer Freescale Etek Multiplex Megamotor Part No. MC9S12A64CFUE EB-85A 214207 16/15/4 Description Microcontroller (sampled) GPS Module Multiplex Easy Glider Brushless Motor Castle Creations CC-PH25 25 Amp Brushless Esc HP Kingston JAE Electronics Many Megamotor FlightPower Graupner IMAX None PQI RC Smart None SDC/1GBKR ST2S008V1AR1500 Many Unknown LXRVS0 GPC10060 SKM601B None None None Photosmart R707 Digital Camera Kingston 1GB MicroSD Flash Card microSD push-push connector PCB Components 2.5:1 Gearbox w/5mm output shaft 2100-mAh 3-cell LiPo battery 10x6 CAM Folding Prop Balance Charger for 1-5 LiPo cells Velcro, glue, misc. parts 2GB SD Card 3900mAh Lipo battery Unit Cost Qty $6.60 1 $55.50 1 $168.98 1 $85.00 1 $67.95 1 $67.95 $0.00 $5.99 $1.67 $103.09 $49.95 $62.99 $39.90 $89.90 $15.19 $7.99 $39.98 1 1 3 1 1 1 1 1 1 1 1 $0.00 $5.99 $5.01 $103.09 $49.95 $62.99 $39.90 $89.90 $15.19 $7.99 $39.98 TOTAL E-1 Total Cost $6.60 $55.50 $168.98 $85.00 $804.02 ECE 477 Final Report Spring 2008 Appendix F: Software Listing Figure F.1: Flowchart for Main Program F-1 ECE 477 Final Report Spring 2008 Figure F.2: Hierarchical Block Diagram of Code Organization F-2 ECE 477 Final Report Spring 2008 Source Code Listing /******************************* main.c **************************************** * * * Author: David Collins * * Project: Global Pigeon - ECE 477 Team 10, Spring 2008 * * * * This file contains the main function for Project Global Pigeon as well as * * many test functions which test various peripherials. The code is designed * * to work with a Freescale 9S12A64 microcontroller as it to be compiled using * * CodeWarrior. * * * * The current state of the main function consists of an infinite loop which * * waits for data and stores it periodically to the MicroSD card. An RTI * * interrupt in nav.c maintains a consistent period and performs the actual * * storage. GPS coordinates, thermopile readings, and radio inputs are all * * logged. This data was then going to be used to determine an appropriate * * control algorithm for the autopilot mode. Unfortunately, poor weather, * * radio interference, and time constraints kept the autopilot mode from being * * realized. * * * *******************************************************************************/ #include <hidef.h> #include <mc9s12a64.h> #include #include #include #include #include #include #include #include #include #include #include #include #include // common defines and macros // derivative information "pll.h" "timer.h" "sci.h" "gps.h" "sd.h" "pigeon.h" "radio.h" "servo.h" "camera.h" "adc.h" "debug.h" "nav.h" "lcd.h" #pragma LINK_INFO DERIVATIVE "mc9s12a64" // debug testing for the GPS module void TestGPS(void); // output the binary offsets of the GPS data type void PrintGPSOffset(void); // simple debug testing of the MicroSD card void TestSD(void); // Store GPS track to the SD card void TestTracking(void); F-3 ECE 477 Final Report Spring 2008 // display the radio values out of each channel void TestRadio(void); // interactive camera test function void TestCamera(void); // blink the LEDs void TestHeartbeat(void); // ensure that the thermopiles are outputting something reasonable void TestThermopiles(void); // test that distance and bearing calculation work properly void Test_Bearings(void); // display a menu for PSSC checkoff void Test_PSSC(void); // play with the servos void PSSC3(void); // play with MicroSD void PSSC5(void); // Store GPS track to the SD card while displaying distance and direction to engineering fountain void TestTarget(void); // Keep updating the GPS values void TestGPSmonitor(void); // display a menu to test the functionality of various peripherals void TestMenu(void); unsigned char SD_Buffer[SD_BLOCK_SIZE]; void PrintTime(unsigned long t_s, unsigned long t_e) { t_e -= t_s; SCI_OutString(1, "Time: "); SCI_OutULInt(1, t_e); SCI_OutString(1, "\r\n"); } void main(void) { Pigeon_Init(); PLL_Init(); Timer_Init(0,1); //SCI_Init(1, 115200); // PC connection LCD_Init(0); // LCD F-4 ECE 477 Final Report Spring 2008 GPS_Init(); SD_Init(); Radio_Init(); Servo_Init(); Camera_Init(); ADC_Init(); EnableInterrupts; SCI_OutString(1, "Hello\r\n"); LEDS = LED_RED | LED_GREEN | LED_YELLOW; //Test_Bearings(); // spin forever, RTI in control //for(;;); TestHeartbeat(); // turn off all LEDs PORTA = 0; // start stabilization RTI, Nav_Init(); needs to be after a heartbeat pause // display GPS data along with distance and direction to a target //TestTarget(); // PSSC checkoff menu //Test_PSSC(); // begins logging GPS waypoints immediately to the MicroSD card //TestTracking(); // Keep updating the GPS values while RTI is storing to the SD card TestGPSmonitor(); // display a menu to test the functionality of various peripherals //TestMenu(); // spin forever for (;;); } // ensure that the thermopiles are outputting something reasonable void TestThermopiles(void) { for(;;) { SCI_OutChar(1, '\f'); SCI_OutString(1, "Vsense: "); SCI_OutUInt(1, ADC_In(ADC_CH_VSENSE)); SCI_OutString(1, "\r\n"); F-5 ECE 477 Final Report Spring 2008 SCI_OutString(1, "Therm0: "); SCI_OutString(1, "\r\n"); SCI_OutString(1, "Therm1: "); SCI_OutString(1, "\r\n"); SCI_OutString(1, "Therm2: "); SCI_OutString(1, "\r\n"); SCI_OutString(1, "Therm3: "); SCI_OutString(1, "\r\n"); SCI_OutUInt(1, ADC_In(ADC_CH_THERM0)); SCI_OutUInt(1, ADC_In(ADC_CH_THERM1)); SCI_OutUInt(1, ADC_In(ADC_CH_THERM2)); SCI_OutUInt(1, ADC_In(ADC_CH_THERM3)); Timer_Wait1ms(50); } } // blink the LEDs void TestHeartbeat(void) { unsigned char i=0; int j; for (j=0; j<20; j++) //while (!SCI1_DATA_READY) { PORTA = i; PORTA |= 0b00000100; i++; Timer_Wait1ms(50); } } // interactive camera test function void TestCamera(void) { unsigned char keyPress=0; SCI_OutString(1, SCI_OutString(1, SCI_OutString(1, SCI_OutString(1, SCI_OutString(1, SCI_OutString(1, "On -> "Off -> "Auto focus -> "Shutter -> "Video start -> "Video stop -> O\r\n"); P\r\n"); A\r\n"); S\r\n"); V\r\n"); B\r\n"); for(;;) { // Test R707 Camera interface if (SCI1_DATA_READY) { keyPress = SCI_InChar(1); keyPress &= ~0x20; // convert to uppercase if (keyPress == 'O') else if (keyPress == else if (keyPress == else if (keyPress == Camera_Send(CAMERA_COMMAND_ON); 'P') Camera_Send(CAMERA_COMMAND_OFF); 'A') Camera_Send(CAMERA_COMMAND_AF); 'S') Camera_Send(CAMERA_COMMAND_SHUTTER); F-6 ECE 477 Final Report else else else else if if if if (keyPress (keyPress (keyPress (keyPress Spring 2008 == == == == 'V') 'B') 'Z') 'X') Camera_Send(CAMERA_COMMAND_VIDEO_START); Camera_Send(CAMERA_COMMAND_VIDEO_STOP); Camera_Send(CAMERA_COMMAND_AF_STROBE); Camera_Send(CAMERA_COMMAND_NULL_STROBE); } Camera_HandleEvents(); } } // display the radio values out of each channel void TestRadio(void) { int i=0; for (;;) { if ((i & 7) == 0) { // output reading SCI_OutChar(1, '\f'); SCI_OutString(1, "Aux: "); SCI_OutUInt(1, SCI_OutString(1, "\r\n"); SCI_OutString(1, "Auto: "); SCI_OutUInt(1, SCI_OutString(1, "\r\n"); SCI_OutString(1, "Elevator: "); SCI_OutUInt(1, SCI_OutString(1, "\r\n"); SCI_OutString(1, "Rudder: "); SCI_OutUInt(1, SCI_OutString(1, "\r\n"); SCI_OutString(1, "Ailerons: "); SCI_OutUInt(1, SCI_OutString(1, "\r\n"); SCI_OutString(1, "Throttle: "); SCI_OutUInt(1, SCI_OutString(1, "\r\n"); } i++; if (Radio_PulseWidth(RADIO_CH_AUTO) < 36000) { // auto mode // turn off pass through Radio_PassthruUnset(RADIO_MASK_ALL); Servo_Duty(SERVO_CH_THROTTLE, SERVO_IN_MIN); Servo_Duty(SERVO_CH_AILERON, 0); Servo_Duty(SERVO_CH_ELEVATOR, 0); Servo_Duty(SERVO_CH_RUDDER, 0); } else { // manual mode Radio_PassthruSet(RADIO_MASK_ALL); } Timer_Wait1ms(10); F-7 Radio_PulseWidth(0)); Radio_PulseWidth(1)); Radio_PulseWidth(2)); Radio_PulseWidth(3)); Radio_PulseWidth(4)); Radio_PulseWidth(5)); ECE 477 Final Report Spring 2008 } } // Store GPS track to the SD card void TestTracking(void) { unsigned short i; unsigned long count = 0; int max, bufcount=0; LEDS |= LED_RED; i = SD_Card_Init(); if (i==0) LEDS &= ~LED_RED; // determine how many points will fit in a block // max = the max index max = (SD_BLOCK_SIZE / sizeof(GPS_DATA)) - 1; for (i=0; i<SD_BLOCK_SIZE; i++) SD_Buffer[i] = 0; // clear the header // i = SD_Write_Block(SD_Buffer, BLOCK_GPS_TRACK_OUT); // read the header LEDS |= LED_RED; i = SD_Read_Block(SD_Buffer, BLOCK_GPS_TRACK_OUT); if (i==0) LEDS &= ~LED_RED; // copy out the first 4 bytes as an integer count = *(unsigned long *)SD_Buffer; for (;;) { // new gps data ready if (GPS_ReadyFlag()) { // translate the NMEA sentences to binary LEDS |= LED_YELLOW; if (GPS_Translate()) { // only record it if all of the position and bearing fields refreshed // copy the waypoint data into the SD buffer GPS_Value(&((GPS_DATA *)SD_Buffer)[bufcount]); //if (((GPS_DATA *)SD_Buffer)[bufcount].fix == 3) // always plot if (1) { // 3D fix LEDS |= LED_GREEN; bufcount++; F-8 ECE 477 Final Report Spring 2008 if (bufcount >= max) { #ifndef GPSPASSTHRU //SCI_OutString(1, "Write "); //SCI_OutULInt(1, count); //SCI_OutString(1, "\r\n"); #endif bufcount = 0; // write the data to the SD card count++; LEDS |= LED_RED; i = SD_Write_Block(SD_Buffer, BLOCK_GPS_TRACK_OUT + count); if (i==0) LEDS &= ~LED_RED; // write the count back to the header *(unsigned long *)SD_Buffer = count; LEDS |= LED_RED; i = SD_Write_Block(SD_Buffer, BLOCK_GPS_TRACK_OUT); if (i==0) LEDS &= ~LED_RED; } } else { // Not a 3D fix LEDS &= ~LED_GREEN; } } LEDS &= ~LED_YELLOW; } } } // Store GPS track to the SD card while displaying distance and direction to engineering fountain void TestTarget(void) { unsigned short i; unsigned long count = 0; int max, bufcount=0; GPS_DATA gpsCurrent, gpsTarget; // set the engineering fountain as the target gpsTarget.latitude = 24257186L; gpsTarget.longitude = -52148269L; gpsTarget.altitude = 188; LEDS |= LED_RED; i = SD_Card_Init(); if (i==0) LEDS &= ~LED_RED; // determine how many points will fit in a block F-9 ECE 477 Final Report Spring 2008 // max = the max index max = (SD_BLOCK_SIZE / sizeof(GPS_DATA)) - 1; for (i=0; i<SD_BLOCK_SIZE; i++) SD_Buffer[i] = 0; // clear the header // i = SD_Write_Block(SD_Buffer, BLOCK_GPS_TRACK_OUT); // read the header LEDS |= LED_RED; i = SD_Read_Block(SD_Buffer, BLOCK_GPS_TRACK_OUT); if (i==0) LEDS &= ~LED_RED; // copy out the first 4 bytes as an integer count = *(unsigned long *)SD_Buffer; for (;;) { // new gps data ready if (GPS_ReadyFlag()) { // translate the NMEA sentences to binary LEDS |= LED_YELLOW; if (GPS_Translate()) { // only record it if all of the position and bearing fields refreshed // copy the waypoint data into the SD buffer GPS_Value(&((GPS_DATA *)SD_Buffer)[bufcount]); GPS_Value(&gpsCurrent); //if (((GPS_DATA *)SD_Buffer)[bufcount].fix == 3) // always plot if (1) { // 3D fix LEDS |= LED_GREEN; GPS_PrintTarget(&gpsCurrent, &gpsTarget); bufcount++; if (bufcount >= max) { #ifndef GPSPASSTHRU SCI_OutString(1, "Write "); SCI_OutULInt(1, count); SCI_OutString(1, "\r\n"); #endif bufcount = 0; // write the data to the SD card count++; LEDS |= LED_RED; i = SD_Write_Block(SD_Buffer, BLOCK_GPS_TRACK_OUT + count); F-10 ECE 477 Final Report Spring 2008 if (i==0) LEDS &= ~LED_RED; // write the count back to the header *(unsigned long *)SD_Buffer = count; LEDS |= LED_RED; i = SD_Write_Block(SD_Buffer, BLOCK_GPS_TRACK_OUT); if (i==0) LEDS &= ~LED_RED; } } else { // Not a 3D fix LEDS &= ~LED_GREEN; } } LEDS &= ~LED_YELLOW; } } } // debug testing for the GPS module void TestGPS(void) { int i; unsigned char c; for(;;) { // wait for a byte from the GPS module /* while (!SCI0_DATA_READY); c = SCI_InChar(0); SCI_OutChar(1, c); */ // call handler as if triggered by an interrupt // GPS_Receive_Handler(); if (GPS_ReadyFlag()) { i = GPS_Translate(); } } } // output the binary offsets of the GPS data type // used to help translate from the codewarrior compiler to gcc storage mechanism void PrintGPSOffset(void) { F-11 ECE 477 Final Report Spring 2008 GPS_DATA g; SCI_OutString(1, "sizeof(GPS_DATA) = "); SCI_OutUInt(1, sizeof(GPS_DATA)); SCI_OutString(1, "\r\nOffsets:\r\n"); SCI_OutString(1, "latitude: "); SCI_OutULInt(1, (unsigned long)&(g.latitude) (unsigned long)&g); SCI_OutString(1, "\r\n"); SCI_OutString(1, "longitude: "); SCI_OutULInt(1, (unsigned long)&(g.longitude) (unsigned long)&g); SCI_OutString(1, "\r\n"); SCI_OutString(1, "altitude: "); SCI_OutULInt(1, (unsigned long)&(g.altitude) (unsigned long)&g); SCI_OutString(1, "\r\n"); SCI_OutString(1, "speed: "); SCI_OutULInt(1, (unsigned long)&(g.speed) - (unsigned long)&g); SCI_OutString(1, "\r\n"); SCI_OutString(1, "bearing: "); SCI_OutULInt(1, (unsigned long)&(g.bearing) (unsigned long)&g); SCI_OutString(1, "\r\n"); SCI_OutString(1, "numSV: "); SCI_OutULInt(1, (unsigned long)&(g.numSV) - (unsigned long)&g); SCI_OutString(1, "\r\n"); SCI_OutString(1, "year: "); SCI_OutULInt(1, (unsigned long)&(g.year) - (unsigned long)&g); SCI_OutString(1, "\r\n"); SCI_OutString(1, "month: "); SCI_OutULInt(1, (unsigned long)&(g.day) - (unsigned long)&g); SCI_OutString(1, "\r\n"); SCI_OutString(1, "day: "); SCI_OutULInt(1, (unsigned long)&(g.day) - (unsigned long)&g); SCI_OutString(1, "\r\n"); SCI_OutString(1, "hr: "); SCI_OutULInt(1, (unsigned long)&(g.hr) - (unsigned long)&g); SCI_OutString(1, "\r\n"); SCI_OutString(1, "min: "); SCI_OutULInt(1, (unsigned long)&(g.min) - (unsigned long)&g); SCI_OutString(1, "\r\n"); SCI_OutString(1, "sec: "); SCI_OutULInt(1, (unsigned long)&(g.sec) - (unsigned long)&g); SCI_OutString(1, "\r\n"); SCI_OutString(1, "geoidSep: "); SCI_OutULInt(1, (unsigned long)&(g.geoidSep) (unsigned long)&g); SCI_OutString(1, "\r\n"); SCI_OutString(1, "PDOP: "); SCI_OutULInt(1, (unsigned long)&(g.PDOP) - (unsigned long)&g); SCI_OutString(1, "\r\n"); SCI_OutString(1, "HDOP: "); SCI_OutULInt(1, (unsigned long)&(g.HDOP) - (unsigned long)&g); SCI_OutString(1, "\r\n"); SCI_OutString(1, "VDOP: "); SCI_OutULInt(1, (unsigned long)&(g.VDOP) - (unsigned long)&g); SCI_OutString(1, "\r\n"); SCI_OutString(1, "fix: "); SCI_OutULInt(1, (unsigned long)&(g.fix) - (unsigned long)&g); SCI_OutString(1, "\r\n"); SCI_OutString(1, "navMode: "); SCI_OutULInt(1, (unsigned long)&(g.navMode) (unsigned long)&g); SCI_OutString(1, "\r\n"); } // simple debug testing of the MicroSD card void TestSD(void) { unsigned short i,j; char *replace = "OMG, h4x0red!!!"; char *pos; // for timing purposes unsigned long t[4]; SCI_OutString(1, "Initializing SD card...\r\n"); t[0] = TimeStamp(); i = SD_Card_Init(); F-12 ECE 477 Final Report Spring 2008 t[1] = TimeStamp(); PrintTime(t[0], t[1]); SCI_OutString(1, "Reading block 645\r\n"); t[0] = TimeStamp(); i = SD_Read_Block(SD_Buffer, 645); t[1] = TimeStamp(); PrintTime(t[0], t[1]); SCI_OutString(1, "Before: "); for (i=0; i<30; i++) { SCI_OutChar(1, SD_Buffer[i]); } SCI_OutString(1, "\r\n"); // modify the buffer pos = replace; i = 6; while (*replace) { SD_Buffer[i] = *replace; replace++; i++; } SCI_OutString(1, "After: "); for (i=0; i<30; i++) { SCI_OutChar(1, SD_Buffer[i]); } SCI_OutString(1, "\r\n"); //for (;;); SCI_OutString(1, "Writing edited block 645\r\n"); t[0] = TimeStamp(); i = SD_Write_Block(SD_Buffer, 645); t[1] = TimeStamp(); PrintTime(t[0], t[1]); for (j=645; j<1000; j++) { t[0] = TimeStamp(); i = SD_Read_Block(SD_Buffer, j); t[1] = TimeStamp(); PrintTime(t[0], t[1]); SCI_OutString(1, "Contents of memory block "); SCI_OutUInt(1, j); SCI_OutString(1, "\r\n"); // print out a hex dump for (i=1; i<=SD_BLOCK_SIZE; i++) F-13 ECE 477 Final Report Spring 2008 { SCI_OutHex(1, SD_Buffer[i-1]); if ( (i%16) == 0 ) SCI_OutString(1, "\r\n"); else if ( (i%8) == 0 ) SCI_OutString(1, " "); else SCI_OutChar(1, ' '); } SCI_OutString(1, "\r\n"); SCI_OutString(1, "\r\n"); // wait for key press i = SCI_InChar(1); } } // test that distance and bearing calculation work properly void Test_Bearings(void) { unsigned long dist, bearing, truedist, truebearing; GPS_DATA p1, p2; SCI_OutString(1, "Distance and Bearing Test Cases:\r\n\r\n"); p1.latitude = 24279031L; p1.longitude = -52154981L; p2.latitude = 24280528L; p2.longitude = -52155932L; truedist = 1010; truebearing = 334; Nav_CalcDifference(&dist, &bearing, &p1, &p2); SCI_OutString(1, "True dist: "); SCI_OutULInt(1, truedist); SCI_OutString(1, ", Calc dist: "); SCI_OutULInt(1, dist); SCI_OutString(1, "\r\n"); SCI_OutString(1, "True bearing: "); SCI_OutULInt(1, truebearing); SCI_OutString(1, ", Calc bearing: "); SCI_OutULInt(1, bearing); SCI_OutString(1, "\r\n\r\n"); truebearing = 154; Nav_CalcDifference(&dist, &bearing, &p2, &p1); SCI_OutString(1, "True dist: "); SCI_OutULInt(1, truedist); SCI_OutString(1, ", Calc dist: "); SCI_OutULInt(1, dist); SCI_OutString(1, "\r\n"); SCI_OutString(1, "True bearing: "); SCI_OutULInt(1, truebearing); SCI_OutString(1, ", Calc bearing: "); SCI_OutULInt(1, bearing); SCI_OutString(1, "\r\n\r\n"); p1.latitude = 24280008L; p1.longitude = -52155748L; p2.latitude = 24280029L; p2.longitude = -52155247L; truedist = 233; truebearing = 86; Nav_CalcDifference(&dist, &bearing, &p1, &p2); F-14 ECE 477 Final Report Spring 2008 SCI_OutString(1, "True dist: "); SCI_OutULInt(1, truedist); SCI_OutString(1, ", Calc dist: "); SCI_OutULInt(1, dist); SCI_OutString(1, "\r\n"); SCI_OutString(1, "True bearing: "); SCI_OutULInt(1, truebearing); SCI_OutString(1, ", Calc bearing: "); SCI_OutULInt(1, bearing); SCI_OutString(1, "\r\n\r\n"); truebearing = 266; Nav_CalcDifference(&dist, &bearing, &p2, &p1); SCI_OutString(1, "True dist: "); SCI_OutULInt(1, truedist); SCI_OutString(1, ", Calc dist: "); SCI_OutULInt(1, dist); SCI_OutString(1, "\r\n"); SCI_OutString(1, "True bearing: "); SCI_OutULInt(1, truebearing); SCI_OutString(1, ", Calc bearing: "); SCI_OutULInt(1, bearing); SCI_OutString(1, "\r\n\r\n"); p1.latitude = 24256028L; p1.longitude = -52141495L; p2.latitude = 24255385L; p2.longitude = -52154478L; truedist = 6036; truebearing = 267; Nav_CalcDifference(&dist, &bearing, &p1, &p2); SCI_OutString(1, "True dist: "); SCI_OutULInt(1, truedist); SCI_OutString(1, ", Calc dist: "); SCI_OutULInt(1, dist); SCI_OutString(1, "\r\n"); SCI_OutString(1, "True bearing: "); SCI_OutULInt(1, truebearing); SCI_OutString(1, ", Calc bearing: "); SCI_OutULInt(1, bearing); SCI_OutString(1, "\r\n\r\n"); for(;;); } // display a menu for PSSC checkoff void Test_PSSC(void) { unsigned char c; // choose a test program to run for (;;) { SCI_OutString(1, "\r\nChoose PSSC to test:\r\n"); SCI_OutString(1, "2. An ability to decode and display GPS coordinates.\r\n"); SCI_OutString(1, "3. An ability to control motor speed and control surface position.\r\n"); SCI_OutString(1, "4. An ability to capture still images.\r\n"); SCI_OutString(1, "5. An ability to read waypoints from a MicroSD removable storage device.\r\n"); c = SCI_InChar(1); switch (c) { case '2': SCI_OutString(1, "\r\nPSSC 2\r\n"); Timer_Wait1ms(200); F-15 ECE 477 Final Report Spring 2008 SCI_Init(1, 19200); TestTracking(); SCI_Init(1, 115200); break; case '3': SCI_OutString(1, "\r\nPSSC 3\r\n"); PSSC3(); break; case '4': SCI_OutString(1, "\r\nPSSC 4\r\n"); TestCamera(); break; case '5': SCI_OutString(1, "\r\nPSSC 5\r\n"); PSSC5(); break; default: break; } } } // play with the servos void PSSC3(void) { unsigned char c; // turn off radio pass thru Radio_PassthruUnset(RADIO_MASK_ALL); SET_AUTOMATIC_FLIGHT(); // set everything to 0 Servo_Duty(SERVO_CH_THROTTLE, SERVO_IN_MIN); Servo_Duty(SERVO_CH_AILERON, 0); Servo_Duty(SERVO_CH_ELEVATOR, 0); Servo_Duty(SERVO_CH_RUDDER, 0); SCI_OutString(1, SCI_OutString(1, SCI_OutString(1, SCI_OutString(1, "Throttle: "Aileron: "Elevator: "Rudder: 1->0 2->-1 3->-1 4->-1 Q->1/2 W->0 E->0 R->0 A->1\r\n"); S->1\r\n"); D->1\r\n"); F->1\r\n"); for (;;) { c = SCI_InChar(1); switch (c) { case '1': Servo_Duty(SERVO_CH_THROTTLE, SERVO_IN_MIN); break; case 'q': Servo_Duty(SERVO_CH_THROTTLE, 0); F-16 ECE 477 Final Report Spring 2008 break; case 'a': Servo_Duty(SERVO_CH_THROTTLE, SERVO_IN_MAX); break; case '2': Servo_Duty(SERVO_CH_AILERON, SERVO_IN_MIN); break; case 'w': Servo_Duty(SERVO_CH_AILERON, 0); break; case 's': Servo_Duty(SERVO_CH_AILERON, SERVO_IN_MAX); break; case '3': Servo_Duty(SERVO_CH_ELEVATOR, SERVO_IN_MIN); break; case 'e': Servo_Duty(SERVO_CH_ELEVATOR, 0); break; case 'd': Servo_Duty(SERVO_CH_ELEVATOR, SERVO_IN_MAX); break; case '4': Servo_Duty(SERVO_CH_RUDDER, SERVO_IN_MIN); break; case 'r': Servo_Duty(SERVO_CH_RUDDER, 0); break; case 'f': Servo_Duty(SERVO_CH_RUDDER, SERVO_IN_MAX); break; default: break; } } } // play with MicroSD void PSSC5(void) { unsigned short i; long latitude, longitude, count; LEDS |= LED_RED; i = SD_Card_Init(); if (i==0) LEDS &= ~LED_RED; // read the header LEDS |= LED_RED; i = SD_Read_Block(SD_Buffer, BLOCK_GPS_TRACK_IN); if (i==0) LEDS &= ~LED_RED; count = *(unsigned long *)SD_Buffer; F-17 ECE 477 Final Report Spring 2008 for (i=0; i<count; i++) { latitude = ((unsigned long *)SD_Buffer)[i * 2 + 1]; longitude = ((unsigned long *)SD_Buffer)[i * 2 + 2]; SCI_OutChar(1, '('); SCI_OutLInt(1, latitude / 6L); SCI_OutString(1, ", "); SCI_OutLInt(1, longitude / 6L); SCI_OutString(1, ")\r\n"); } } // Keep updating the GPS values, fire camera based on radio transmitter switches void TestGPSmonitor(void) { unsigned char prev_on = 1, cur_on = 0; unsigned char prev_shutter = 1, cur_shutter = 0; for (;;) { // new gps data ready if (GPS_ReadyFlag()) { // translate the NMEA sentences to binary LEDS |= LED_YELLOW; GPS_Translate(); LEDS &= ~LED_YELLOW; } // get current switch state if (Radio_PulseWidth(0) < 35940) { cur_on = 1; } else { cur_on = 0; } if (Radio_PulseWidth(1) < 35940) { cur_shutter = 1; } else { cur_shutter = 0; } // act on switch changes if (cur_on == 1 && prev_on == 0) { SCI_OutString(1, "Camera On\r\n"); Camera_Send(CAMERA_COMMAND_ON); } else if (cur_on == 0 && prev_on == 1) { SCI_OutString(1, "Camera Off\r\n"); F-18 ECE 477 Final Report Spring 2008 Camera_Send(CAMERA_COMMAND_OFF); } else if (cur_shutter == 1 && prev_shutter == 0) { SCI_OutString(1, "Shutter\r\n"); Camera_Send(CAMERA_COMMAND_SHUTTER); } prev_on = cur_on; prev_shutter = cur_shutter; Camera_HandleEvents(); } } // display a menu to test the functionality of various peripherals void TestMenu(void) { unsigned char c; // choose a test program to run for (;;) { SCI_OutString(1, "Choose a test:\r\n1. GPS\r\n2. SD\r\n3. Tracking\r\n4. Radio\r\n5. Camera\r\n6. Thermopiles\r\n"); c = SCI_InChar(1); switch (c) { case '1': SCI_OutString(1, "\r\nGPS\r\n"); TestGPS(); break; case '2': SCI_OutString(1, "\r\nSD\r\n"); TestSD(); break; case '3': SCI_OutString(1, "\r\nTracking\r\n"); TestTracking(); break; case '4': SCI_OutString(1, "\r\nRadio\r\n"); TestRadio(); break; case '5': SCI_OutString(1, "\r\nCamera\r\n"); TestCamera(); break; case '6': SCI_OutString(1, "\r\nThermopiles\r\n"); TestThermopiles(); break; default: break; } F-19 ECE 477 Final Report Spring 2008 } } /******************************* End of main.c ********************************/ /******************************* pigeon.c ************************************** * * * Author: David Collins * * Project: Global Pigeon - ECE 477 Team 10, Spring 2008 * * * * This file contains Team Global Pigeon specific initializations based on the * * port connections. * * * *******************************************************************************/ #include <hidef.h> #include <mc9s12a64.h> #include "pigeon.h" // initialize various ports void Pigeon_Init(void) { // set pull resistors on inputs that aren't padded out on the 80pin package PERH = 0xFF; PERP = 0b01000000; PERS = 0xF0; // set up port A to output on bits 0-2 DDRA |= 0x07; // set PTT6 as output for autopilot selector DDRT |= 0b01000000; } /******************************* End of pigeon.c ******************************/ /******************************* pigeon.h ************************************** * * * Author: David Collins * * Project: Global Pigeon - ECE 477 Team 10, Spring 2008 * * * * This file contains Team Global Pigeon specific port masks and structures. * * * *******************************************************************************/ #ifndef HEADER_PIGEON_H #define HEADER_PIGEON_H F-20 ECE 477 Final Report Spring 2008 // port that the indicator LEDs are connected to #define LEDS PORTA // bit corresponding to each LED #define LED_RED 0x01 #define LED_YELLOW 0x02 #define LED_GREEN 0x04 #define SET_MANUAL_FLIGHT() PTT &= ~0x40; #define SET_AUTOMATIC_FLIGHT() PTT |= 0x40; // SD card block offsets // offset to start of global settings #define BLOCK_SETTINGS 1024 // offset to start GPS waypoints to navigate to #define BLOCK_GPS_TRACK_IN 1040 // offset to start GPS track outputting #define BLOCK_GPS_TRACK_OUT 1200 // clock frequency in Hz #define CLOCK_SPEED 24000000 // for use in writing the low and high 16bits of a 32bit int // used in determining time intervals from fire and line breaking typedef union { unsigned long int Full; struct { unsigned short int High; unsigned short int Low; } Half; } PARTLONG; // initialize various ports void Pigeon_Init(void); #endif /******************************* End of pigeon.h ******************************/ /********************************* gps.c *************************************** * * * Author: David Collins * * Project: Global Pigeon - ECE 477 Team 10, Spring 2008 * F-21 ECE 477 Final Report Spring 2008 * * * Allows for communication with an ETek EB-85A GPS module. However, the * * usage of of standard NMEA sentences should allow this source code to work * * with other GPS modules. * * * * Several buffers are maintained into which raw NMEA sentences are written. * * Writing to a buffer begins when an '$' is received and stops when a '*' is * * received. Only chosen NMEA sentences are stored. These consist of RMC, * * GGA, and GSA. A translation function is called to fill integer values in a * * structure based on the contents of each NMEA sentence. * * * *******************************************************************************/ #include <hidef.h> #include <mc9s12a64.h> #include "gps.h" #include "sci.h" #include "debug.h" #include "nav.h" // #include "constants.h" const char NMEA_SET_MIN[] = "$PMTK314,0,1,0,1,5,0,0,0,0,0,0,0,0,0,0,0,0*2D\r\n"; //const char NMEA_SET_MIN[] = "$PMTK314,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0*28\r\n"; //const char NMEA_SET_MIN[] = "$PMTK314,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0*28\r\n"; const char NMEA_SET_WAAS[] = "$PMTK313,1*2E\r\n$PMTK301,2*2E\r\n"; #define GPS_NUM_ACCEPTED 3 const char gpsNmeaAccepted[GPS_NUM_ACCEPTED][6] = {"GPRMC", "GPGGA", "GPGSA"}; //const char gpsNmeaAccepted[GPS_NUM_ACCEPTED][6] = {"GPVTG", "GPGGA"}; //const char gpsNmeaAccepted[GPS_NUM_ACCEPTED][6] = {"GPRMC", "GPGGA"}; #define GPS_NUM_BUFFERS 5 #define GPS_BUFFER_SIZE 255 // head and tail points for buffer selection int gpsHead, gpsTail; // GPS input buffer char gpsBuffer[GPS_NUM_BUFFERS][GPS_BUFFER_SIZE]; // current writing position in each GPS buffer int gpsBufferPos[GPS_NUM_BUFFERS]; // flag is true while currently receiving a NMEA sentence char gpsInSentence; // flag true if NMEA sentence char gpsInAccepted; // bits for accepted sentences set high when received int gpsFlag; F-22 ECE 477 Final Report Spring 2008 GPS_DATA gpsData, gpsDataStored; // initial the GPS module and the UART port connecting to it void GPS_Init(void) { int i; unsigned char *p; // initialize gps buffers to 0 gpsHead = gpsTail = 0; for (i=0; i<GPS_NUM_BUFFERS; i++) { gpsBufferPos[i] = 0; } gpsInSentence = 0; gpsInAccepted = 0; gpsFlag = 0; // zero out the gps data structure p = (unsigned char *)&gpsData; for (i=0; i<sizeof(GPS_DATA); i++) { p[i] = 0; } // initialize the SCI0 registers SCI_Init(0, 38400); // set for receiving interrupt SCI0CR2 = 0x2C; // clear the flags //SCI0SR1 = 0xC0; // send NMEA command to set for minimal sentence output SCI_OutString(0, NMEA_SET_MIN); // send NMEA command to enable WAAS operation SCI_OutString(0, NMEA_SET_WAAS); SCI_OutString(1, "\r\nSent commands \r\n\r\n"); } // returns true when strings match int IsMatch(const char *a, const char *b, int len) { int i; for (i=0; i<len; i++) { if (a[i] != b[i]) return 0; } return 1; } F-23 ECE 477 Final Report Spring 2008 // returns true if new NMEA sentence is ready for translation unsigned char GPS_ReadyFlag(void) { return (gpsTail != gpsHead); } // handle incoming data using receiver interrupt interrupt 20 void GPS_Receive_Handler(void) { int i; char c; // clear the flag i = SCI0SR1; // get the new character c = SCI0DRL; // check that it is a receive interrupt if (!(i & RDRF)) { SCI_OutString(1, "SCI interrupted but not on receive.\r\n"); // should only get hear through an interrupt, // so the flag ought always be set // return in its not return; } // pass through the character #ifdef GPSPASSTHRU SCI_OutChar(1, c); #endif if (!gpsInSentence) { if (c == '$') { gpsInSentence = 1; } } else if (!gpsInAccepted) { if (c == ',') { // TalkerID finished, check if it is accepted for (i=0; i<GPS_NUM_ACCEPTED; i++) { if (IsMatch(gpsBuffer[gpsTail], gpsNmeaAccepted[i], gpsBufferPos[gpsTail])) { // it is an accepted sentence break; } } if (i<GPS_NUM_ACCEPTED) { // replace first character in buffer with accepted NMEA index gpsBuffer[gpsTail][0] = '0' + i; gpsBuffer[gpsTail][1] = ','; gpsBufferPos[gpsTail] = 2; gpsInAccepted = 1; } else { F-24 ECE 477 Final Report Spring 2008 // this is not an accepted sentence, so set for not in sentence gpsInSentence = 0; // move position back to start of buffer gpsBufferPos[gpsTail] = 0; } } else { // add character to buffer gpsBuffer[gpsTail][gpsBufferPos[gpsTail]] = c; gpsBufferPos[gpsTail]++; } } else { // is in an accepted NMEA sentence, copy into buffer if not end if (c == '*') { // end of the sentence gpsBuffer[gpsTail][gpsBufferPos[gpsTail]] = '\0'; gpsBufferPos[gpsTail]++; // set for not in sentence and not accepted gpsInSentence = 0; gpsInAccepted = 0; // move to next buffer with circular add gpsTail++; if (gpsTail == GPS_NUM_BUFFERS) gpsTail=0; // move to the start of the buffer gpsBufferPos[gpsTail] = 0; } else { // just copy the char gpsBuffer[gpsTail][gpsBufferPos[gpsTail]] = c; gpsBufferPos[gpsTail]++; } } } // non-interrupt function for translating NMEA sentences into useful data // returns true if a fully refreshed reading is available int GPS_Translate(void) { int i, j, neg, max; char *buf; if (gpsTail != gpsHead) { // new data is ready in the buffer //printf("%s\n", gpsBuffer[gpsHead]); buf = gpsBuffer[gpsHead]; max = gpsBufferPos[gpsHead]; i = buf[0] - '0'; if (i == 0) { // RMC F-25 ECE 477 Final Report Spring 2008 // get time gpsData.hr = (buf[2] - '0')*10 + (buf[3] - '0'); gpsData.min = (buf[4] - '0')*10 + (buf[5] - '0'); gpsData.sec = ((((buf[6]-'0')*10+(buf[7]-'0'))*10+(buf[9]-'0'))*10+(buf[10]'0'))*10+(buf[11]-'0'); gpsData.latitude = ((buf[15]-'0')*10+(buf[16]-'0'))*6; // read in latitude for (i=17; i<24; i++) { if (buf[i] >= '0' && buf[i] <= '9') { if (i>17) gpsData.latitude *= 10; gpsData.latitude += buf[i] - '0'; } } if (buf[25] == 'S') { // make negative for southern hemisphere gpsData.latitude = 0 - gpsData.latitude; } gpsData.longitude = (((buf[27]-'0')*10+(buf[28]-'0'))*10+(buf[29]-'0'))*6; // read in latitude for (i=30; i<37; i++) { if (buf[i] >= '0' && buf[i] <= '9') { if (i>30) gpsData.longitude *= 10; gpsData.longitude += buf[i] - '0'; } } if (buf[38] == 'W') { // make negative for west gpsData.longitude = 0 - gpsData.longitude; } // get speed gpsData.speed = 0; i=40; while (buf[i] != ',' && i < max) { if (buf[i] >= '0' && buf[i] <= '9') { gpsData.speed *= 10; gpsData.speed += buf[i] - '0'; } i++; } // get bearing gpsData.bearing = 0; i++; while (buf[i] != ',' && i < max) { if (buf[i] >= '0' && buf[i] <= '9') { gpsData.bearing *= 10; gpsData.bearing += buf[i] - '0'; } i++; } // get date i++; gpsData.day = (buf[i]-'0')*10+(buf[i+1]-'0'); F-26 ECE 477 Final Report Spring 2008 i+=2; gpsData.month = (buf[i]-'0')*10+(buf[i+1]-'0'); i+=2; gpsData.year = (buf[i]-'0')*10+(buf[i+1]-'0'); // i+=5; switch (buf[i]) { case 'N': gpsData.navMode break; case 'A': gpsData.navMode break; case 'D': gpsData.navMode break; case 'E': gpsData.navMode break; } = 0; = 1; = 2; = 3; // ensure that the visible GPS value is always valid gpsDataStored = gpsData; // raise the ready flag gpsFlag |= GPS_NMEA_GPRMC; } else if (i == 1) { // GGA // get number of satellites gpsData.numSV = 0; i=40; while (buf[i] != ',' && i < max) { if (buf[i] >= '0' && buf[i] <= '9') { gpsData.numSV *= 10; gpsData.numSV += buf[i] - '0'; } i++; } // altitude gpsData.altitude = 0; i++; j=0; while (j<1) { if (buf[i] == ',') j++; i++; } neg = 0; while (buf[i] != ',' && i < max) { if (buf[i] >= '0' && buf[i] <= '9') { gpsData.altitude *= 10; gpsData.altitude += buf[i] - '0'; F-27 ECE 477 Final Report Spring 2008 } else if (buf[i] == '-') { neg = 1; } i++; } // negate if needed if (neg) gpsData.altitude = - gpsData.altitude; // get geoidal separation gpsData.geoidSep = 0; i+=3; neg = 0; while (buf[i] != ',' && i < max) { if (buf[i] >= '0' && buf[i] <= '9') { gpsData.geoidSep *= 10; gpsData.geoidSep += buf[i] - '0'; } else if (buf[i] == '-') { neg = 1; } i++; } // negate if needed if (neg) gpsData.geoidSep = 0 - gpsData.geoidSep; // ensure that the visible GPS value is always valid gpsDataStored = gpsData; // raise the ready flag gpsFlag |= GPS_NMEA_GPGGA; } else if (i == 2) { // GSA // get fix mode gpsData.fix = buf[4] - '0'; if (gpsData.fix == 1) gpsData.fix=0; // move to the DOPs i=6; j=0; while (j<12) { if (buf[i] == ',' && i < max) j++; i++; } // get PDOP gpsData.PDOP = 0; while (buf[i] != ',' && i < max) { if (buf[i] >= '0' && buf[i] <= '9') { gpsData.PDOP *= 10; gpsData.PDOP += buf[i] - '0'; } i++; F-28 ECE 477 Final Report Spring 2008 } // get PDOP gpsData.HDOP = 0; i++; while (buf[i] != ',' && i < max) { if (buf[i] >= '0' && buf[i] <= '9') { gpsData.HDOP *= 10; gpsData.HDOP += buf[i] - '0'; } i++; } // get PDOP gpsData.VDOP = 0; i++; while (buf[i] != ',' && i < max) { if (buf[i] >= '0' && buf[i] <= '9') { gpsData.VDOP *= 10; gpsData.VDOP += buf[i] - '0'; } i++; } // ensure that the visible GPS value is always valid gpsDataStored = gpsData; // raise the ready flag gpsFlag |= GPS_NMEA_GPGSA; } // move to next buffer with circular add gpsHead++; if (gpsHead == GPS_NUM_BUFFERS) gpsHead=0; } // print everything when both are new if ((gpsFlag & (GPS_NMEA_GPRMC | GPS_NMEA_GPGGA)) == (GPS_NMEA_GPRMC | GPS_NMEA_GPGGA)) { gpsFlag &= ~(GPS_NMEA_GPRMC | GPS_NMEA_GPGGA); // print all data GPS_Print(&gpsData); return 1; } return 0; } // copy the value of the internal gps structure into provided pointer void GPS_Value(GPS_DATA *gps) { *gps = gpsDataStored; F-29 ECE 477 Final Report Spring 2008 } // print out GPS data void GPS_Print(const GPS_DATA *gps) { #ifndef GPSPASSTHRU SCI_OutChar(1, '\f'); SCI_OutLInt(1, gps->latitude / 6L); SCI_OutString(1, ", "); SCI_OutLInt(1, gps>longitude / 6L); SCI_OutString(1, "\r\n"); SCI_OutULInt(1, gps->altitude); SCI_OutString(1, "m "); SCI_OutString(1, "SV:"); SCI_OutUInt(1, gps->numSV); SCI_OutString(1, " "); SCI_OutUInt(1, gps->fix); SCI_OutString(1, "D\r\n"); SCI_OutUInt(1, gps->speed); SCI_OutString(1, "k "); SCI_OutUInt(1, gps->bearing); SCI_OutString(1, "d\r\n"); SCI_OutUInt(1, gps->hr); SCI_OutChar(1, ':'); SCI_OutUInt(1, gps->min); SCI_OutChar(1, ':'); SCI_OutULInt(1, gps->sec); SCI_OutString(1, " "); SCI_OutUInt(1, gps->month); SCI_OutChar(1, '/'); SCI_OutUInt(1, gps->day); SCI_OutChar(1, '/'); SCI_OutUInt(1, gps->year); SCI_OutString(1, "\r\n"); #endif //SCI_OutString(1, "Nav mode - "); SCI_OutUInt(1, gps->navMode); SCI_OutString(1, "\r\n"); //SCI_OutString(1, "Geo Sep - "); SCI_OutUInt(1, gps->geoidSep); SCI_OutString(1, "\r\n"); //SCI_OutUInt(1, gps->PDOP); SCI_OutString(1, ", "); //SCI_OutUInt(1, gps->HDOP); SCI_OutString(1, ", "); //SCI_OutUInt(1, gps->VDOP); SCI_OutString(1, "\r\n"); } // print out GPS data relative to a target void GPS_PrintTarget(const GPS_DATA *gpsCurrent, const GPS_DATA *gpsTarget) { unsigned long dist, bearing; long error; Nav_CalcDifference(&dist, &bearing, gpsCurrent, gpsTarget); error = (long)gpsCurrent->bearing / 100 - (long)bearing; if (error < -180) error += 360; else if (error > 180) error -=360; SCI_OutChar(1, '\f'); SCI_OutLInt(1, gpsCurrent->latitude / 6L); SCI_OutString(1, ", "); SCI_OutLInt(1, gpsCurrent->longitude / 6L); SCI_OutString(1, "\r\n"); SCI_OutULInt(1, gpsCurrent->altitude); SCI_OutString(1, "m "); SCI_OutString(1, "SV:"); SCI_OutUInt(1, gpsCurrent->numSV); SCI_OutString(1, " "); SCI_OutUInt(1, gpsCurrent->fix); SCI_OutString(1, "D\r\n"); SCI_OutUInt(1, gpsCurrent->speed); SCI_OutString(1, "k "); SCI_OutUInt(1, gpsCurrent->bearing); SCI_OutString(1, "d\r\n"); SCI_OutULInt(1, dist); SCI_OutString(1, "ft "); SCI_OutULInt(1, bearing); SCI_OutString(1, "d "); SCI_OutLInt(1, error); SCI_OutString(1, "d"); F-30 ECE 477 Final Report Spring 2008 } /******************************** End of gps.c ********************************/ /********************************* gps.h *************************************** * * * Author: David Collins * * Project: Global Pigeon - ECE 477 Team 10, Spring 2008 * * * * Allows for communication with an ETek EB-85A GPS module. However, the * * usage of of standard NMEA sentences should allow this source code to work * * with other GPS modules. * * * * Defines a structure to store GPS data in as well as flag masks for NMEA * * sentence reception signalling. * * * *******************************************************************************/ #ifndef HEADER_GPS_H #define HEADER_GPS_H #define GPS_NMEA_GPRMC 1 #define GPS_NMEA_GPGGA 2 #define GPS_NMEA_GPGSA 4 typedef struct { long latitude; long longitude; long altitude; unsigned short speed; unsigned short bearing; unsigned char numSV; unsigned char year; unsigned char month; unsigned char day; unsigned char hr; unsigned char min; unsigned short sec; short geoidSep; short PDOP, HDOP, VDOP; unsigned char fix; unsigned char navMode; 3 = DR } GPS_DATA; // // // // // // // // // // // // // // // // min * 10000, N = +, S = min * 10000, E = +, W = m * 10 knot * 100 deg * 100 (0-360.00) number of SV's used in solution 00-99 00-12 00-31 00-23 00-59 s * 1000, 0-59000 m * 10, geoidal separation DOP * 10 values 0 = no fix, 2 = 2D, 3 = 3D 0 = no fix, 1 = Autonomous mode, 2 = Differential mode, // initial the GPS module and the UART port connecting to it void GPS_Init(void); // non-interrupt function for translating NMEA sentences into useful data int GPS_Translate(void); F-31 ECE 477 Final Report Spring 2008 // returns true if new NMEA sentence is ready for translation unsigned char GPS_ReadyFlag(void); // copy the value of the internal gps structure into provided pointer void GPS_Value(GPS_DATA *gps); // print out GPS data void GPS_Print(const GPS_DATA *gps); // print out GPS data relative to a target void GPS_PrintTarget(const GPS_DATA *gpsCurrent, const GPS_DATA *gpsTarget); #endif /******************************** End of gps.h ********************************/ /********************************* nav.c *************************************** * * * Author: David Collins * * Project: Global Pigeon - ECE 477 Team 10, Spring 2008 * * * * This file contains functions to control navigation and stabilization. * * Navigation requires the ability to determine the angle and distance between * * two GPS waypoints. Everything needed to be done using integers so a cosine * * lookup table was included to simplify operation. A generic PID update * * function is included which would be used for both navigation and * * stabilization. The RTI ISR is used to periodically measure the thermopile * * values and then store various inputs onto the SD card. Autopilot has not * * been implemented yet due to the problems with radio interference. * * * *******************************************************************************/ #include #include #include #include #include #include #include <mc9s12a64.h> "nav.h" "pigeon.h" "adc.h" "sci.h" "sd.h" "radio.h" // internal functions // sends commands to servos at regular intervals void Nav_Handler(void); // print out the averaged thermopile values void PrintThermopiles(void); // scale a thermopile value so that they all have the same base value unsigned short Therm_Scaled(unsigned char channel); // calculate the square root of a long input value F-32 ECE 477 Final Report Spring 2008 // source: http://www.codecodex.com/wiki/index.php?title=Calculate_an_integer_square_root unsigned long lsqrt(unsigned long y); // performs thermopile scaling and display void Test_ThermScale(void); // Store GPS data as well as thermopile readings and radio signals to the SD card void TestLogging(void); // set up initial used in the data logging void RTI_Init(void); // cos(ang) * 256 with ang in degree // used for scaling down longitude values based on latitude // cosAdjust[0] corresponds to 4 deg as 0-3deg == 256 const unsigned char cosAdjust[87] = { 255, 255, 255, 254, 254, 253, 252, 251, 250, 249, 248, 247, 246, 242, 241, 239, 237, 236, 234, 232, 230, 228, 226, 224, 222, 219, 212, 210, 207, 204, 202, 199, 196, 193, 190, 187, 184, 181, 178, 168, 165, 161, 158, 154, 150, 147, 143, 139, 136, 132, 128, 124, 112, 108, 104, 100, 96, 92, 88, 83, 79, 75, 71, 66, 62, 49, 44, 40, 36, 31, 27, 22, 18, 13, 9, 4, 0}; // determine how many points will fit in a block; is the max index #define STATE_BLOCK_MAX ((SD_BLOCK_SIZE / sizeof(STATE_DATA))) // amount to downshift #define THERM_SCALE_SHIFT 10 long therm_scale_mul[THERM_COUNT] = {1024, 1029, 992, 1054}; long therm_scale_add[THERM_COUNT] = {0, -3, -6, -21}; // counter for rti interrupt unsigned int rti_count = 0; // holds the thermopile sums unsigned int therm_sum[THERM_COUNT] = {0, 0, 0, 0}; unsigned int therm_value[THERM_COUNT] = {0, 0, 0, 0}; unsigned int vsense_sum = 0, vsense_value = 0; PID therm3pid; long int therm3set; extern unsigned char SD_Buffer[SD_BLOCK_SIZE]; unsigned char RTI_DataReady; F-33 245, 217, 175, 120, 58, 243, 215, 171, 116, 53, ECE 477 Final Report Spring 2008 // number of blocks used on the SD card unsigned long LogCount; // number of entries logged in current block int LogBufCount; // set up registers needed for navigation void Nav_Init(void) { // set up initial used in the data logging RTI_Init(); // set up RTI to poll thermopile values and round them // set RTI to interrupt at 325.52 Hz = 8 MHz OSCCLK / 3*2^13 // this was chosen so that 10 samples averaged before a 10 Hz servo adjustment // would correspond to the last 1/3 of the time between actions RTICTL = 0x42; // enable RTI CRGINT = 0x80; therm3set = 440L; therm3pid.Kp = 10; therm3pid.Kd = 10; therm3pid.Ki = 1; therm3pid.sumError = 0; therm3pid.prevError = 0; therm3pid.outputMin = therm3pid.outputMax = therm3pid.sumErrorMin therm3pid.sumErrorMax -1500; 1500; = -100; = 100; RTI_DataReady = 0; } interrupt 7 void RTI_ISR(void) { int i; // clear the RTIF flag CRGFLG = 0x80; if (rti_count < NAV_AVERAGE_COUNT) { // add values to running sum therm_sum[0] += ADC_In(ADC_CH_THERM0); therm_sum[1] += ADC_In(ADC_CH_THERM1); therm_sum[2] += ADC_In(ADC_CH_THERM2); therm_sum[3] += ADC_In(ADC_CH_THERM3); F-34 ECE 477 Final Report Spring 2008 vsense_sum += ADC_In(ADC_CH_VSENSE); } else if (rti_count == NAV_AVERAGE_COUNT) { // calculate averaged values for (i=0; i<THERM_COUNT; i++) { therm_value[i] = therm_sum[i] >> NAV_SHIFT; therm_sum[i] = 0; } vsense_value = vsense_sum >> NAV_SHIFT; vsense_sum = 0; // perform all timely events Nav_Handler(); } else if (rti_count >= NAV_STABILIZE_COUNT) { // wrap back around rti_count = 0; } rti_count++; } // sends commands to servos at regular intervals void Nav_Handler(void) { // Store GPS data as well as thermopile readings and radio signals to the SD card TestLogging(); RTI_DataReady = 1; // performs thermopile scaling and display // Test_ThermScale(); } // print out the averaged thermopile values void PrintThermopiles(void) { SCI_OutChar(1, '\f'); SCI_OutString(1, "Vsense: "); SCI_OutUInt(1, vsense_value); SCI_OutString(1, "\r\n"); // Raw SCI_OutString(1, SCI_OutString(1, "\r\n"); SCI_OutString(1, "\r\n"); SCI_OutString(1, "\r\n"); "Raw\r\n"); "Therm0: "); SCI_OutUInt(1, therm_value[0]); SCI_OutString(1, "Therm1: "); SCI_OutUInt(1, therm_value[1]); SCI_OutString(1, "Therm2: "); SCI_OutUInt(1, therm_value[2]); SCI_OutString(1, F-35 ECE 477 Final Report Spring 2008 SCI_OutString(1, "Therm3: "); SCI_OutUInt(1, therm_value[3]); SCI_OutString(1, "\r\n"); // Scaled SCI_OutString(1, SCI_OutString(1, "\r\n"); SCI_OutString(1, "\r\n"); SCI_OutString(1, "\r\n"); SCI_OutString(1, "\r\n"); "Scaled\r\n"); "Therm0: "); SCI_OutULInt(1, Therm_Scaled(0)); SCI_OutString(1, "Therm1: "); SCI_OutULInt(1, Therm_Scaled(1)); SCI_OutString(1, "Therm2: "); SCI_OutULInt(1, Therm_Scaled(2)); SCI_OutString(1, "Therm3: "); SCI_OutULInt(1, Therm_Scaled(3)); SCI_OutString(1, } // outputs the new control output value long int Nav_PID(long int error, PID *pid) { long int P, I, D, out; // Proportional P = pid->Kp * error; // Integral pid->sumError += error; if (pid->sumError > pid->sumErrorMax) { pid->sumError = pid->sumErrorMax; } else if(pid->sumError < pid->sumErrorMin) { pid->sumError = pid->sumErrorMin; } I = pid->Ki * pid->sumError; // Derivative D = pid->Kd * (error - pid->prevError); pid->prevError = error; out = P + I + D; if (out > pid->outputMax) { out = pid->outputMax; } else if (out < pid->outputMin) { out = pid->outputMin; } return out; } // scale a thermopile value so that they all have the same base value F-36 ECE 477 Final Report Spring 2008 unsigned short Therm_Scaled(unsigned char channel) { long out; out = therm_value[channel]; out *= therm_scale_mul[channel]; out >>= THERM_SCALE_SHIFT; out += therm_scale_add[channel]; return (unsigned short)out; } // calculates the distance (ft) and bearing (deg) between two waypoints // bearing vector goes from p1 to p2 void Nav_CalcDifference(unsigned long *pDist, unsigned long *pBearing, const GPS_DATA *p1, const GPS_DATA *p2) { long dlat, dlong, temp; int downshift=0; unsigned char target, type, low=0, mid=43, high=86; unsigned long udlat, udlong, utemp, utemp2, uval; //printf("p1: (%ld, %ld), p2: (%ld, %ld)\n", p1->latitude, p1->longitude, p2>latitude, p2->longitude); // calculate the differences between the waypoints // differences currently in units of minutes of angle dlat = p2->latitude - p1->latitude; dlong = p2->longitude - p1->longitude; // convert from minute to degree, rounding to the nearest degree if (p1->latitude > 0) temp = p1->latitude / 600000L; else temp = p1->latitude / -600000L; // scale dlong as longitude degrees get closer together at higher latitudes // no change for latitudes <4deg if (temp > 90) { dlong = 0; } else if (temp > 3) { dlong *= cosAdjust[temp - 4]; dlong >>= 8; } // absolute values udlat = (dlat > 0 ? dlat : -dlat); udlong = (dlong > 0 ? dlong : -dlong); //printf("dlat: %ld\ndlong: %ld\n", dlat, dlong); // downshift the inputs so that the square root doesn't fail while (udlat > 0x8000 || udlong > 0x8000) { udlat >>= 1; udlong >>= 1; downshift++; } F-37 ECE 477 Final Report Spring 2008 //printf("Downshift=%d, udlat=%ld, udlong=%ld\n", downshift, udlat, udlong); // calculate distance *pDist = udlat * udlat + udlong * udlong; *pDist = lsqrt(*pDist); // scale back up // pDist is units of minutes * 10000 *pDist <<= downshift; //printf("Distance: %ld (min)\n", *pDist); // absolute values udlat = (dlat > 0 ? dlat : -dlat); udlong = (dlong > 0 ? dlong : -dlong); utemp = *pDist; downshift = 0; // pick the triangle leg such that sine or cosine is small if (udlat < udlong) { uval = udlat; type = 0; } else { uval = udlong; type = 1; } //printf("uval: %ld\n", uval);; // ensure it doesn't go out of range while (uval > 0x00FFFFFFuL) { uval >>= 1; utemp >>= 1; downshift++; } // calulate the target sine or cosine utemp2 = uval << 8; //printf("uval: %ld utemp2: %ld\n", uval, utemp2); utemp2 /= utemp; //printf("utemp: %ld utemp2: %ld\n", utemp, utemp2); target = (unsigned char)utemp2; //printf("Target: %d\n", target); // convert from minute * 10000 to feet *pDist = (utemp * 155) >> (8 - downshift); //printf("Distance: %ld (ft)\n", *pDist); //printf("Type: %d\n", type); if (uval == 0) { // corner case of vertical or horizontal travel mid = 90; F-38 ECE 477 Final Report Spring 2008 } else { // find the angle using bisection while (low < mid && mid < high) { //printf("L: %2d, M: %2d, H: %2d\n", low, mid, high); if (target == cosAdjust[mid]) { break; } else if (target < cosAdjust[mid]) { low = mid; } else { high = mid; } mid = (high + low) >> 1; } // make mid an angle away from north mid += 4; } if (type) mid = 90 - mid; //printf("Angle: %d\n", mid); if (dlat >= 0 && dlong >= 0) { // quandrant I *pBearing = mid; } else if (dlat >= 0 && dlong <= 0) { // quandrant II *pBearing = 360 - mid; } else if (dlat <= 0 && dlong <= 0) { // quandrant III *pBearing = mid + 180; } else { // quandrant IV *pBearing = 180 - mid; } } // calculate the square root of a long input value // source: http://www.codecodex.com/wiki/index.php?title=Calculate_an_integer_square_root unsigned long lsqrt(unsigned long y) { unsigned long x_old, x_new; unsigned long testy; int nbits; int i; if (y == 0) { F-39 ECE 477 Final Report Spring 2008 return 0L; } // select a good starting value using binary logarithms: nbits = (sizeof(y) * 8); for (i = 4, testy = 16L;; i += 2, testy <<= 2L) { if (i >= nbits || y <= testy) { x_old = (1L << (i >> 1)); // x_old = closest power of 2 to sqrt(testy) break; } } // x_old >= sqrt(y) // use the Babylonian method to arrive at the integer square root: // i should never be very big, but set a cap just in case for (i=0;i<50;i++) { x_new = (y / x_old + x_old) >> 1; if (x_old <= x_new) break; x_old = x_new; } // make sure that the answer is right: /* if (x_old * x_old > y || (x_old + 1) * (x_old + 1) <= y) { //printf("Error in lsqrt(), bad output\n"); return 0L; } */ return x_old; } // performs thermopile scaling and display void Test_ThermScale(void) { long int output; // alternate green LED LEDS ^= LED_GREEN; // output the thermopile values for debugging PrintThermopiles(); output = Nav_PID(therm_value[3] - therm3set, &therm3pid); SCI_OutString(1, "Output: "); SCI_OutLInt(1, output); SCI_OutString(1, "\r\n"); } // set up initial used in the data logging void RTI_Init(void) { F-40 ECE 477 Final Report Spring 2008 unsigned short i; LogCount = 0; LogBufCount = 0; LEDS |= LED_RED; i = SD_Card_Init(); if (i==0) LEDS &= ~LED_RED; for (i=0; i<SD_BLOCK_SIZE; i++) SD_Buffer[i] = 0; // clear the header // i = SD_Write_Block(SD_Buffer, BLOCK_GPS_TRACK_OUT); // read the header LEDS |= LED_RED; i = SD_Read_Block(SD_Buffer, BLOCK_GPS_TRACK_OUT); if (i==0) LEDS &= ~LED_RED; // copy out the first 4 bytes as an integer LogCount = *(unsigned long *)SD_Buffer; } // Store GPS data as well as thermopile readings and radio signals to the SD card void TestLogging(void) { unsigned short i; STATE_DATA *state; // alternate green LED LEDS ^= LED_GREEN; // get the storage location state = &((STATE_DATA *)SD_Buffer)[LogBufCount]; // copy the waypoint data into the SD buffer GPS_Value(&(state->gps)); // copy in radio values for (i=0; i<6; i++) { state->radio[i] = Radio_PulseWidth(i); } // copy in thermopile values for (i=0; i<4; i++) { state->therm[i] = therm_value[i]; } LogBufCount++; if (LogBufCount >= STATE_BLOCK_MAX) F-41 ECE 477 Final Report Spring 2008 { LogBufCount = 0; // write the data to the SD card LogCount++; LEDS |= LED_RED; i = SD_Write_Block(SD_Buffer, BLOCK_GPS_TRACK_OUT + LogCount); if (i==0) LEDS &= ~LED_RED; // write the count back to the header *(unsigned long *)SD_Buffer = LogCount; LEDS |= LED_RED; i = SD_Write_Block(SD_Buffer, BLOCK_GPS_TRACK_OUT); if (i==0) LEDS &= ~LED_RED; } } /******************************** End of nav.c ********************************/ /********************************* nav.h *************************************** * * * Author: David Collins * * Project: Global Pigeon - ECE 477 Team 10, Spring 2008 * * * * This file contains functions to control navigation and stabilization. * * Navigation is based on GPS readings. Stabilization is achieved using the * * thermopile values. Structures are defined to hold PID state information as * * well as logging information. * * * *******************************************************************************/ #ifndef HEADER_NAV #define HEADER_NAV #include "gps.h" // number of RTI counts that get averaged together #define NAV_AVERAGE_COUNT 8 #define NAV_SHIFT 3 // number of RTI counts between stabilization events #define NAV_STABILIZE_COUNT 32 // number of thermopiles #define THERM_COUNT 4 // state values needed for PID calculations typedef struct { long int Kp, Kd, Ki; long int prevError, sumError; long int sumErrorMin, sumErrorMax; F-42 ECE 477 Final Report Spring 2008 long int outputMin, outputMax; } PID; typedef struct { unsigned short radio[6]; unsigned int therm[4]; GPS_DATA gps; } STATE_DATA; // set up registers needed for navigation void Nav_Init(void); // outputs the new control output value long int Nav_PID(long int error, PID *pid); // calculates the distance (ft) and bearing (deg) between two waypoints // bearing vector goes from p1 to p2 void Nav_CalcDifference(unsigned long *pDist, unsigned long *pBearing, const GPS_DATA *p1, const GPS_DATA *p2); #endif /******************************** End of nav.h ********************************/ /********************************** sd.c *************************************** * * * Author: David Collins * * Project: Global Pigeon - ECE 477 Team 10, Spring 2008 * * Reference: Robert Imhoff, info@flashgenie.net, http://www.flashgenie.net * * * * Provides a read/write interface to an SD card over an SPI port. The card * * initialization function sends commands to the card to get it into SPI mode. * * The read and write functions operate in 512 byte blocks. This is the * * minimum number of bytes that the SD standard allows to be accessed at a * * time. * * * *******************************************************************************/ #include <hidef.h> #include <mc9s12a64.h> #include "sd.h" #include "debug.h" // global variable for return values unsigned char ret; // set by write command which didn't complete unsigned char SDbusy = 0; F-43 ECE 477 Final Report Spring 2008 // internal function called to wait for write or erase operations to end // returns 0 on success unsigned char SD_BusyWait(unsigned long waitCycles); // send out 2 empty characters to disengage SD card #define SD_Off() ret = SPI_ShiftByte(SD_EMPTY_CHAR); ret = SPI_ShiftByte(SD_EMPTY_CHAR); SD_DESELECT(); // number of bytes to send while SD card is busy before giving up #define SD_WRITE_WAIT_TIMEOUT 50000 #define SD_CMD_TIMEOUT 520 #define SD_CMD_RESP_TIMEOUT 10 #define SD_INIT_TIMEOUT 2000 #define SD_INIT_INSERT_TIMEOUT 10 #define #define #define #define SD_READ_BUSY_WAIT 32000 SD_READ_RETRIES 5 SD_WRITE_RETRIES 5 SD_WRITE_ACK_BUSY_WAIT 100 // Initialize microcontroller registers for use with SD card void SD_Init(void) { // PTM5 - SPI Clock // PTM4 - SPI master output // PTM3 - Chip select bar - controlled separately in code // PTM2 - SPI slave input ** Device Specific ** // PTM1 - Card inserted when low // I don't think these are required, enabling SPI should force them to be as needed DDRM = 0b00111000; // PTM5-3 = output PTM = 0; // zero out PTM registers SD_DESELECT(); // set PTM1 to have a pull up PERM = 0b11000010; PPSM = 0b00000000; // route the SPI module to Port M MODRR = 0b00010000; // enable SPI, set to master, use clock normally low, input on rising edge of clock // MSB first send // do not use chip select in the normal way because it needs to stay low throughout the entire operation // enabling it here would make it go high after every byte // CPOL=0, CPHA=0 SPI0CR1 = 0b01010000; F-44 ECE 477 Final Report Spring 2008 // PTM3 is chip select, but not with CPU control, no bidirectional stuff or wait mode SPI0CR2 = 0b00000000; // set the clock rate /* SPIBR is 0 M2 M1 M0 0 E2 E1 E0 divisor = (M2M1M0 + 1) * 2 ^ (E2E1E0 + 1) SD has to run at <=400kHz at the beginning of initialization, then up to 25MHz afterward with a bus clock of 24MHz, that cooresponds to SPIBR = 0b00000101 */ SD_SET_SPEED_LOW(); SDbusy = 0; // clear SPIF ret = SPI0SR; ret = SPI0DR; } // proceeds though an entire SPI shift operation and returns the value // sent from the slave unsigned char SPI_ShiftByte(unsigned char input) { SPI_WAIT_FOR_SPACE(); SPI0DR = input; // put input byte in the SPI output buffer SPI_WAIT_FOR_DATA(); return SPI0DR; // return the value received } // get two-byte R2 response from SD card if write command fails unsigned short SD_GetStatus(void) { unsigned char r; unsigned short status; // CMD13 - status command r = SD_SendCommand(13, 0); status = ((unsigned short)r) << 8; // receive second byte of response r = SPI_ShiftByte(SD_EMPTY_CHAR); status |= (unsigned short)r; return status; } // internal function called to wait for write or erase operations to end // returns 0 on success F-45 ECE 477 Final Report Spring 2008 unsigned char SD_BusyWait(unsigned long waitCycles) { unsigned long i; unsigned char b; DEBUG("Waiting for write sequence to finish...\r\n"); // send waitCycles * 8 clock pulse at max for (i = 0; i < waitCycles; i++) { b = SPI_ShiftByte(SD_EMPTY_CHAR); if (b) // non-zero value: card came out of busy state { SDbusy = 0; return 0; } } //only get here with failure, still busy SD_Off(); return 1; } // send an SD command code to the SD card unsigned char SD_SendCommand(unsigned char command, unsigned long blocknum) { unsigned char crc, b; unsigned long i, address; // set the framing bits properly command |= 0x40; command &= ~0x80; // this crc code corresponds to CMD0, but SPI mode in the SD card // ignores the CRC after CMD0 completes, therefore, 0x95 will always be used crc = 0x95; SD_SELECT(); // assert chip select // Wake up the SD card by sending it 0xFF repeatedly if (SDbusy) //busy flag was set by previous write or erase command, need longer wait { // wait for any pending write/erase operation to terminate b = SD_BusyWait(SD_WRITE_WAIT_TIMEOUT); // error -- card did not come out of busy state if (b) return b; } else //busy flag was not set, but still have to wake up card { for (i = 0; i < SD_CMD_TIMEOUT; i++) // send 0xff till non-0 answer (0 = busy) { b = SPI_ShiftByte(SD_EMPTY_CHAR); // clock cycles to wake up if needed if (b == 0xff) break; // no longer busy F-46 ECE 477 Final Report Spring 2008 } } // convert the block number into a 32bit address address = blocknum * SD_BLOCK_SIZE; // send the actual command b = SPI_ShiftByte(command); // address sent MSB first b = SPI_ShiftByte((unsigned b = SPI_ShiftByte((unsigned b = SPI_ShiftByte((unsigned b = SPI_ShiftByte((unsigned b = SPI_ShiftByte(crc); char)(address >> 24)); char)(address >> 16)); char)(address >> 8)); char)address); // send 0xFF until non-FF answer for (i = 0; i < SD_CMD_RESP_TIMEOUT; i++) { if (b != SD_EMPTY_CHAR) // have response: return return b; // return command response byte b = SPI_ShiftByte(SD_EMPTY_CHAR); } // CMD timeout, only arrive here if failure return (SD_EMPTY_CHAR); } // Send the initialization sequence to the SD card // returns 0 if successful unsigned char SD_Card_Init(void) { int i, j, k; unsigned char r; SD_DESELECT(); // initialization must be done with SCLK <= 400kHz SD_SET_SPEED_LOW(); DEBUG("SD init...\r\n"); // attempt to initialize the card several times for (k=0; k<SD_INIT_INSERT_TIMEOUT; k++) { if (SD_IS_CARD_INSERTED()) // only proceed if the card is inserted { for (j=0; j<SD_INIT_TIMEOUT; j++) { //DEBUG(" Sending dummy pulses\r\n"); // send dummy pulses to get SD card into native mode // must receive at least 74 clock ticks to initialize internal registers for (i = 0; i < 12; i++) { r = SPI_ShiftByte(SD_EMPTY_CHAR); } SD_SELECT(); // activate chip F-47 ECE 477 Final Report Spring 2008 // send CMD0 to switch to SPI mode r = SD_SendCommand(0, 0); if (r <= 1) //have answer break; // else wait some more SD_DESELECT(); } if (j==SD_INIT_TIMEOUT) DEBUG("SD failed to respond to CMD0\r\n"); // try ACMD55 -- MMC will respond with error r = SD_SendCommand(55, 0); /* SCI_OutString(1, "Reply from CMD55: "); SCI_OutUInt(1, r); SCI_OutString(1, "\r\n"); */ if (r == 5) { // *** MMC *** // CardType = MMCType; // loop until card finishes initializing for (i=0; i<SD_INIT_TIMEOUT; i++) { // CMD1 : returns 0x01 while the card is initializing, 0 when finished r = SD_SendCommand(1, 0); if (r==0) break; } } else { // *** SD *** // CardType = SDType; // ACMD41 complete the ACMD r = SD_SendCommand(41, 0); DEBUG(" Sending CMD55, ACMD41 until initialized\r\n"); // loop until card finishes initializing for (i=0; i<SD_INIT_TIMEOUT; i++) { // CMD55 r = SD_SendCommand(55, 0); // ACMD41 : returns 0x01 while the card is initializing, 0 when finished r = SD_SendCommand(41, 0); if (r==0) break; } } if (r == 0) // success F-48 ECE 477 Final Report Spring 2008 { // high speed only works for SD, remove this if MMC DEBUG(" SD card clock speed set high\r\n"); SD_SET_SPEED_HIGH(); DEBUG(" SD card successfully initialized\r\n"); SD_Off(); return 0; } else // stay in loop to try again { // did not finish initializing DEBUG("Retrying SD init.\r\n"); // Display_CRLF(); Display_Str("retry init "); } } } // only get here if everything timed out return r; } // Read in a block from the SD card // Returns 0 on success unsigned char SD_Read_Block(unsigned char *buffer, unsigned long blocknum) { int i; unsigned char r; unsigned long n; if (!SD_IS_CARD_INSERTED()) { DEBUG("Could not read, no card inserted.\r\n"); SD_DESELECT(); return 1; } // send out read command until it is accepted for (i=0; i<SD_READ_RETRIES; i++) { // CMD17 - read block r = SD_SendCommand(17, blocknum); if (r == 0) { // succeeded break; } else { // try to resynch clock r = SPI_ShiftByte(SD_EMPTY_CHAR); // these two lines might not be needed SD_DESELECT(); SD_SELECT(); F-49 ECE 477 Final Report Spring 2008 r = SPI_ShiftByte(SD_EMPTY_CHAR); } } if (r) // error... { // SD card did not accept read command DEBUG("Failed to read from SD card.\r\n"); SD_Off(); // fail return r; } // read block -- response ok */ // send 0xff till non-empty answer with data start token */ for (n=0; n<SD_READ_BUSY_WAIT; n++) { r = SPI_ShiftByte(SD_EMPTY_CHAR); if (r != SD_EMPTY_CHAR) break; } // 0xFE is the start data token // read failed if it is not received if (r != SD_DATA_START_TOKEN) { DEBUG("SD read data token not received.\r\n"); // CMD12 - Stop read r = SD_SendCommand(12, 0); SD_Off(); return 1; } // read ok: data start token received // start reading data block for (i=0; i<SD_BLOCK_SIZE; i++) { *buffer = SPI_ShiftByte(SD_EMPTY_CHAR); buffer++; } // the SD card sends 2 CRC bytes after the data block // receive them, but ignore them r = SPI_ShiftByte(SD_EMPTY_CHAR); r = SPI_ShiftByte(SD_EMPTY_CHAR); DEBUG("SD read succeeded.\r\n"); SD_Off(); return 0; } // Write a block to the SD card // Returns 0 on success F-50 ECE 477 Final Report Spring 2008 unsigned char SD_Write_Block(unsigned char *buffer, unsigned long blocknum) { int i; unsigned char r; unsigned short r2; if (!SD_IS_CARD_INSERTED()) { DEBUG("Could not write, no card inserted.\r\n"); SD_DESELECT(); return 1; } // send out read command until it is accepted for (i=0; i<SD_WRITE_RETRIES; i++) { // CMD24 - write block r = SD_SendCommand(24, blocknum); if (r == 0) { // succeeded break; } else { // try to resynch clock r = SPI_ShiftByte(SD_EMPTY_CHAR); // these two lines might not be needed SD_DESELECT(); SD_SELECT(); r = SPI_ShiftByte(SD_EMPTY_CHAR); } } if (r) // error... { // SD card did not accept write command DEBUG("Failed to write to SD card.\r\n"); SD_Off(); // fail return r; } // response ok -- write the block // send the data start token r = SPI_ShiftByte(SD_EMPTY_CHAR); r = SPI_ShiftByte(SD_DATA_START_TOKEN); // finally, send the actual data for (i=0; i<SD_BLOCK_SIZE; i++) { F-51 ECE 477 Final Report Spring 2008 r = SPI_ShiftByte(*buffer); buffer++; } // the SD card expects 2 CRC bytes after the data block // send 2 filler bytes r = SPI_ShiftByte(SD_EMPTY_CHAR); r = SPI_ShiftByte(SD_EMPTY_CHAR); for (i=0; i<SD_WRITE_ACK_BUSY_WAIT; i++) { // Send dummy bytes until response byte received r = SPI_ShiftByte(SD_EMPTY_CHAR); if ((r != SD_EMPTY_CHAR) && (r != SD_BUSY_CHAR)) break; } // time out because no response if (r == SD_EMPTY_CHAR || r == SD_BUSY_CHAR) { SD_Off(); DEBUG("SD card write timed out.\r\n"); return 1; } // else interpret data response r &= 0x1F; if (r != 0x05) { // rejection, get next two bytes to return error code r2 = SD_GetStatus(); SD_Off(); DEBUG("Write error occured.\r\n"); // change to be unsigned short return return (unsigned char)r2; } // else data accepted // device stays busy to write block SDbusy = 1; DEBUG("SD write succeeded.\r\n"); return 0; } /******************************** End of sd.c ********************************/ /********************************** sd.h *************************************** * * * Author: David Collins * * Project: Global Pigeon - ECE 477 Team 10, Spring 2008 * * Reference: Robert Imhoff, info@flashgenie.net, http://www.flashgenie.net * * * F-52 ECE 477 Final Report Spring 2008 * Provides a read/write interface to an SD card over an SPI port. * * * *******************************************************************************/ #ifndef HEADER_SD #define HEADER_SD // this is the default read block size in bytes // the block write size must be 512 #define SD_BLOCK_SIZE 512 #define SD_EMPTY_CHAR 0xFF #define SD_BUSY_CHAR 0x01 #define SD_DATA_START_TOKEN 0xFE // bit set in SPISR when transfer is complete #define SPIF 0x80 // bit set in SPISR when SPI register is ready for new data #define SPTEF 0x20 // loops until data shifting is complete #define SPI_WAIT_FOR_DATA() while ( !(SPI0SR & SPIF) ); #define SPI_WAIT_FOR_SPACE() while ( !(SPI0SR & SPTEF) ); // chip #define #define #define select lines for SD card SPI_CHIP_SELECT 0x08 SD_SELECT() PTM &= ~SPI_CHIP_SELECT; SD_DESELECT() PTM |= SPI_CHIP_SELECT; // detect if an SD card is inserted // #define SD_IS_CARD_INSERTED() (!(PTM & 0x02)) // currently not operational #define SD_IS_CARD_INSERTED() (1) // set the SPI clock to ~400kHz per spec (375kHz) and 12MHz respectively // #define SD_SET_SPEED_HIGH() SPI0BR = 0b00000000; // prototype setup requires much slower clock 6MHz #define SD_SET_SPEED_HIGH() SPI0BR = 0b00000001; #define SD_SET_SPEED_LOW() SPI0BR = 0b00000101; // Initialize microcontroller registers for use with SD card void SD_Init(void); // proceeds though an entire SPI shift operation and returns the value // sent from the slave unsigned char SPI_ShiftByte(unsigned char input); // get two-byte R2 response from SD card if write command fails unsigned short SD_GetStatus(void); // send an SD command code to the SD card unsigned char SD_SendCommand(unsigned char command, unsigned long blocknum); // Send the initialization sequence to the SD card F-53 ECE 477 Final Report Spring 2008 // returns 0 if successful unsigned char SD_Card_Init(void); // Read in a block from the SD card // Returns 0 on success unsigned char SD_Read_Block(unsigned char *buffer, unsigned long blocknum); // Write a block to the SD card // Returns 0 on success unsigned char SD_Write_Block(unsigned char *buffer, unsigned long blocknum); #endif /******************************** End of sd.h ********************************/ /******************************* camera.c ************************************** * * * Author: David Collins * * Project: Global Pigeon - ECE 477 Team 10, Spring 2008 * * * * Provides an interface to an HP Photosmart R707 digital camera. The camera * * has the following functions exposed to the microcontroller thanks to wires * * which have been soldered across the buttons on the camera: * * Input: PB0 Power on sensing * * PB1 AF Lock * * PB2 Video Lock * * Output: PB6 On/Off * * PB5 Auto focus * * PB4 Shutter * * PB3 Video record * * * * High level commands are passed to the Camera_Send function which are stored * * in a circular buffer. Calls to Camera_HandleEvent check if the current * * running command has finished and starts the next one when appropriate. This * * setup ensures that slow camera commands do not hold up processor execution. * * * *******************************************************************************/ #include <hidef.h> #include <mc9s12a64.h> #include "camera.h" #include "debug.h" #include "timer.h" // issues commands to the camera after each has had enough time to // finish unsigned char commandBuffer[MAX_COMMANDS]; unsigned char commandCurrent = 0; int commandHead=0, commandLen=0, commandTail=0; // waiting times for each action in units of clock ticks F-54 ECE 477 Final Report Spring 2008 // current values reflect a 24MHz clock unsigned long cameraWaitTime[CAMERA_TOTAL_COMMANDS] = { 0UL, // null 96000000UL, // on 2400000UL, // off 7200000UL, // autofocus time, if it wasn't asserted before shutter 2400000UL, // shutter 24000000UL, // video start 12000000UL, // video stop 24000000UL, // AF strobe to get initial focus lock 4800000UL // null strobe, turn everything off and wait }; // time stamps for timing the events unsigned long cameraStartTime=0, cameraStopTime=0; void Camera_Init(void) { // set PB0-PB2 as input, PB3-PB6 as output, PB7 left as input DDRB = 0b01111000; // enable pullups for Port B PUCR |= 0x02; // Initialize event commandHead = 0; commandTail = 0; commandLen = 0; commandCurrent = 0; handler // head of circular buffer, read from // tail of circular buffer, written to // number of items in circular buffer // current running command } // this function transitions the camera control pins void Camera_HandleEvents(void) { // handle current command if (commandCurrent != CAMERA_COMMAND_NONE) { cameraStopTime = TimeStamp(); if (cameraStopTime-cameraStartTime >= cameraWaitTime[commandCurrent]) { // set up to wait for another period if current action incomplete // check on every HandleEvents call instead // cameraStartTime = cameraStopTime; // current command complete if commandCurrent set to CAMERA_COMMAND_NONE // wait period is over, disassert signal F-55 ECE 477 Final Report Spring 2008 switch(commandCurrent) { case CAMERA_COMMAND_ON: if (CAMERA_IS_POWERED()) { CAMERA_UNSET_ON(); commandCurrent = CAMERA_COMMAND_NONE; } break; case CAMERA_COMMAND_OFF: if (!CAMERA_IS_POWERED()) { CAMERA_UNSET_ON(); commandCurrent = CAMERA_COMMAND_NONE; } break; case CAMERA_COMMAND_AF: // do nothing, AF signal should remain on until shutter commandCurrent = CAMERA_COMMAND_NONE; break; case CAMERA_COMMAND_SHUTTER: CAMERA_UNSET_SHUTTER(); CAMERA_UNSET_AF(); commandCurrent = CAMERA_COMMAND_NONE; break; case CAMERA_COMMAND_VIDEO_START: if (CAMERA_VIDEO_LOCKED()) { CAMERA_UNSET_VIDEO(); commandCurrent = CAMERA_COMMAND_NONE; } break; case CAMERA_COMMAND_VIDEO_STOP: if (!CAMERA_VIDEO_LOCKED()) { CAMERA_UNSET_VIDEO(); commandCurrent = CAMERA_COMMAND_NONE; } break; case CAMERA_COMMAND_AF_STROBE: CAMERA_UNSET_AF(); commandCurrent = CAMERA_COMMAND_NONE; break; case CAMERA_COMMAND_NULL_STROBE: // do nothing commandCurrent = CAMERA_COMMAND_NONE; break; } } } // start next command if there is one if (commandLen > 0 && commandCurrent == CAMERA_COMMAND_NONE) { // previously not running a command, now one is available if (!CAMERA_IS_POWERED() && commandBuffer[commandHead] != CAMERA_COMMAND_ON) { F-56 ECE 477 Final Report Spring 2008 // do not execute any commands until the camera has turned on commandCurrent = CAMERA_COMMAND_ON; } else if (commandBuffer[commandHead] == CAMERA_COMMAND_SHUTTER && (!(CAMERA_OUTPUT_PORT & CAMERA_MASK_AF) || !CAMERA_AF_LOCKED())) { // a shutter command was issued without an auto focus command before it // this also checks the AF lock coming out of the camera before starting // a shutter event // issue an AF command, and don't deque the shutter command commandCurrent = CAMERA_COMMAND_AF; } else { // deque the next command commandCurrent = commandBuffer[commandHead]; commandLen--; // circular increment commandHead++; if (commandHead == MAX_COMMANDS) commandHead=0; } cameraStartTime = TimeStamp(); // raise the appropriate output switch(commandCurrent) { case CAMERA_COMMAND_ON: if (!CAMERA_IS_POWERED()) { CAMERA_SET_ON(); DEBUG("Camera On\r\n"); } else { // kill the command if camera already on commandCurrent=CAMERA_COMMAND_NONE; } break; case CAMERA_COMMAND_OFF: if (CAMERA_IS_POWERED()) { CAMERA_SET_ON(); DEBUG("Camera Off\r\n"); } else { // kill the command if camera already off commandCurrent=CAMERA_COMMAND_NONE; } break; case CAMERA_COMMAND_AF: if (!(CAMERA_OUTPUT_PORT & CAMERA_MASK_AF)) { CAMERA_SET_AF(); DEBUG("Camera Auto focus\r\n"); } break; F-57 ECE 477 Final Report Spring 2008 case CAMERA_COMMAND_SHUTTER: CAMERA_SET_SHUTTER(); DEBUG("Camera Shutter\r\n"); break; case CAMERA_COMMAND_VIDEO_START: CAMERA_SET_VIDEO(); DEBUG("Camera Video start\r\n"); break; case CAMERA_COMMAND_VIDEO_STOP: CAMERA_SET_VIDEO(); DEBUG("Camera Video stop\r\n"); break; case CAMERA_COMMAND_AF_STROBE: CAMERA_SET_AF(); DEBUG("Camera Auto focus strobe\r\n"); break; case CAMERA_COMMAND_NULL_STROBE: // do nothing CAMERA_UNSET_ON(); CAMERA_UNSET_AF(); CAMERA_UNSET_SHUTTER(); CAMERA_UNSET_VIDEO(); DEBUG("Camera null strobe\r\n"); break; } } } // a command to the camera queue void Camera_Send(unsigned char command) { if (command < CAMERA_TOTAL_COMMANDS) { if (commandLen < MAX_COMMANDS) { // there is space in the buffer // enque the command commandBuffer[commandTail] = command; commandLen++; // circular increment commandTail++; if (commandTail == MAX_COMMANDS) commandTail=0; } else { DEBUG("Not enough camera command buffer space\r\n"); } } else { DEBUG("Invalid camera command\r\n"); } } F-58 ECE 477 Final Report Spring 2008 /****************************** End of camera.c *******************************/ /******************************* camera.h ************************************** * * * Author: David Collins * * Project: Global Pigeon - ECE 477 Team 10, Spring 2008 * * * * Provides an interface to an HP Photosmart R707 digital camera. Specifies * * commands for the camera to perform. * * * *******************************************************************************/ #ifndef HEADER_CAMERA #define HEADER_CAMERA // I/O ports used for the camera #define CAMERA_INPUT_PORT PORTB #define CAMERA_OUTPUT_PORT PORTB // inputs #define CAMERA_MASK_POWERED (0x01) #define CAMERA_MASK_AF_LOCK (0x04) #define CAMERA_MASK_VIDEO_LOCK (0x02) // outputs #define CAMERA_MASK_ON (0x40) #define CAMERA_MASK_AF (0x20) #define CAMERA_MASK_SHUTTER (0x10) #define CAMERA_MASK_VIDEO (0x08) // maximum number of outstanding commands // others issued beyond this are dropped #define MAX_COMMANDS 20 // command characters #define CAMERA_TOTAL_COMMANDS 9 #define #define #define #define #define #define #define #define #define CAMERA_COMMAND_NONE CAMERA_COMMAND_ON CAMERA_COMMAND_OFF CAMERA_COMMAND_AF CAMERA_COMMAND_SHUTTER CAMERA_COMMAND_VIDEO_START CAMERA_COMMAND_VIDEO_STOP CAMERA_COMMAND_AF_STROBE CAMERA_COMMAND_NULL_STROBE (0x00) (0x01) (0x02) (0x03) (0x04) (0x05) (0x06) (0x07) (0x08) // Input: // true when the camera is powered on, i.e. when its SD card is powered F-59 ECE 477 Final Report Spring 2008 #define CAMERA_IS_POWERED() (!(CAMERA_INPUT_PORT & CAMERA_MASK_POWERED)) // true when the camera AF has locked and it is ready for shutter release #define CAMERA_AF_LOCKED() (!(CAMERA_INPUT_PORT & CAMERA_MASK_AF_LOCK)) // true once the video has started running #define CAMERA_VIDEO_LOCKED() (!(CAMERA_INPUT_PORT & CAMERA_MASK_VIDEO_LOCK)) // Output: // CAMERA_OUTPUT_PORT0 toggles the On/Off button #define CAMERA_SET_ON() {CAMERA_OUTPUT_PORT |= CAMERA_MASK_ON;} #define CAMERA_UNSET_ON() {CAMERA_OUTPUT_PORT &= ~CAMERA_MASK_ON;} // CAMERA_OUTPUT_PORT1 toggles auto focus #define CAMERA_SET_AF() {CAMERA_OUTPUT_PORT |= CAMERA_MASK_AF;} #define CAMERA_UNSET_AF() {CAMERA_OUTPUT_PORT &= ~CAMERA_MASK_AF;} // CAMERA_OUTPUT_PORT2 toggles shutter #define CAMERA_SET_SHUTTER() {CAMERA_OUTPUT_PORT |= CAMERA_MASK_SHUTTER;} #define CAMERA_UNSET_SHUTTER() {CAMERA_OUTPUT_PORT &= ~CAMERA_MASK_SHUTTER;} // CAMERA_OUTPUT_PORT3 toggles video #define CAMERA_SET_VIDEO() {CAMERA_OUTPUT_PORT |= CAMERA_MASK_VIDEO;} #define CAMERA_UNSET_VIDEO() {CAMERA_OUTPUT_PORT &= ~CAMERA_MASK_VIDEO;} void Camera_Init(void); // this function transitions the camera control pins void Camera_HandleEvents(void); // a command to the camera queue void Camera_Send(unsigned char command); #endif /****************************** End of camera.h *******************************/ /******************************* radio.c *************************************** * * * Author: David Collins * * Project: Global Pigeon - ECE 477 Team 10, Spring 2008 * * * * Uses the Timer module to receive servo pulses using 6 input capture pins. * * The pules are 1ms to 2ms in duration every 20ms. * * * * This driver is based upon measuring the number of clock cycles between a * * rising and falling edge. However, the input capture registers are only * * 16bit and the free running clock needs to increment at every clock cycles. * * This means that with a 24MHz clock, the maximum pulse width that can be * * measured is 2.73ms. Exceeding this value will cause the pulse width * * variables to wrap back around to 0. * * * *******************************************************************************/ F-60 ECE 477 Final Report Spring 2008 #include <hidef.h> #include <mc9s12a64.h> #include "radio.h" #include "timer.h" #include "servo.h" /* 9S12A64 Pins PTT0 - PTT5 */ // used for timing the incoming servo control pulses unsigned short radio_start[RADIO_MAX_CHANNELS]; unsigned short radio_stop[RADIO_MAX_CHANNELS]; unsigned short radio_pulse[RADIO_MAX_CHANNELS]; // high for each channel to indicate new data unsigned char radio_flag; // determines which radio channels pass directly to PWM on interrupt unsigned char radio_passthru; // configures the timer input capture to allow for receiving servo signals void Radio_Init(void) { int i; // zero the counters for (i=0; i<RADIO_MAX_CHANNELS; i++) { radio_start[i]=0; radio_stop[i]=0; radio_pulse[i]=0; } radio_passthru = 0xFF; // set PTT0-PTT5 for input capture TIOS &= ~0b00111111; // input capture on rising edge TCTL3 = 0b00000101; TCTL4 = 0b01010101; // set PTT0-PTT5 as input DDRT &= ~0b00111111; // enable a pull up //PERT |= 0b00111111; //PPST = 0; // enable interrupts on IOC0-IOC5 TIE |= 0b00111111; F-61 ECE 477 Final Report Spring 2008 } // Chose to duplicate ISR code so that ISRs run as fast as possible // interrupt handler for IOC0 channel // Radio channel Aux interrupt 8 void IOC0_Handler(void) { // acknowledge the interrupt TFLG1 = 0x01; if (TCTL4 & 0b00000001) // rising edge { // switch to falling edge TCTL4 &= 0b11111100; TCTL4 |= 0b00000010; radio_start[0] = TC0; } else // falling edge { // switch to rising edge TCTL4 &= 0b11111100; TCTL4 |= 0b00000001; radio_stop[0] = TC0; radio_pulse[0] = radio_stop[0] - radio_start[0]; radio_flag |= 0x01; } } // interrupt handler for IOC1 channel // Radio channel Auto interrupt 9 void IOC1_Handler(void) { // acknowledge the interrupt TFLG1 = 0x02; if (TCTL4 & 0b00000100) // rising edge { // switch to falling edge TCTL4 &= 0b11110011; TCTL4 |= 0b00001000; radio_start[1] = TC1; } else // falling edge { // switch to rising edge TCTL4 &= 0b11110011; TCTL4 |= 0b00000100; radio_stop[1] = TC1; radio_pulse[1] = radio_stop[1] - radio_start[1]; F-62 ECE 477 Final Report Spring 2008 radio_flag |= 0x02; } } // interrupt handler for IOC2 channel // Radio channel Elevator interrupt 10 void IOC2Handler(void) { // acknowledge the interrupt TFLG1 = 0x04; if (TCTL4 & 0b00010000) // rising edge { // switch to falling edge TCTL4 &= 0b11001111; TCTL4 |= 0b00100000; radio_start[2] = TC2; } else // falling edge { // switch to rising edge TCTL4 &= 0b11001111; TCTL4 |= 0b00010000; radio_stop[2] = TC2; radio_pulse[2] = radio_stop[2] - radio_start[2]; radio_flag |= 0x04; if (radio_passthru & RADIO_MASK_ELEVATOR) { PWM_Duty16(SERVO_CH_ELEVATOR, radio_pulse[RADIO_CH_ELEVATOR] >> 3); } } } // interrupt handler for IOC3 channel // Radio channel Rudder interrupt 11 void IOC3_Handler(void) { // acknowledge the interrupt TFLG1 = 0x08; if (TCTL4 & 0b01000000) // rising edge { // switch to falling edge TCTL4 &= 0b00111111; TCTL4 |= 0b10000000; radio_start[3] = TC3; } else // falling edge { // switch to rising edge TCTL4 &= 0b00111111; TCTL4 |= 0b01000000; F-63 ECE 477 Final Report Spring 2008 radio_stop[3] = TC3; radio_pulse[3] = radio_stop[3] - radio_start[3]; radio_flag |= 0x08; if (radio_passthru & RADIO_MASK_RUDDER) { PWM_Duty16(SERVO_CH_RUDDER, radio_pulse[RADIO_CH_RUDDER] >> 3); } } } // interrupt handler for IOC4 channel // Radio channel Aileron interrupt 12 void IOC4_Handler(void) { // acknowledge the interrupt TFLG1 = 0x10; if (TCTL3 & 0b00000001) // rising edge { // switch to falling edge TCTL3 &= 0b11111100; TCTL3 |= 0b00000010; radio_start[4] = TC4; } else // falling edge { // switch to rising edge TCTL3 &= 0b11111100; TCTL3 |= 0b00000001; radio_stop[4] = TC4; radio_pulse[4] = radio_stop[4] - radio_start[4]; radio_flag |= 0x10; if (radio_passthru & RADIO_MASK_AILERON) { PWM_Duty16(SERVO_CH_AILERON, radio_pulse[RADIO_CH_AILERON] >> 3); } } } // interrupt handler for IOC5 channel // Radio channel Throttle interrupt 13 void IOC5_Handler(void) { // acknowledge the interrupt TFLG1 = 0x20; if (TCTL3 & 0b00000100) // rising edge { // switch to falling edge TCTL3 &= 0b11110011; TCTL3 |= 0b00001000; F-64 ECE 477 Final Report Spring 2008 radio_start[5] = TC5; } else // falling edge { // switch to rising edge TCTL3 &= 0b11110011; TCTL3 |= 0b00000100; radio_stop[5] = TC5; radio_pulse[5] = radio_stop[5] - radio_start[5]; radio_flag |= 0x20; if (radio_passthru & RADIO_MASK_THROTTLE) { PWM_Duty16(SERVO_CH_THROTTLE, radio_pulse[RADIO_CH_THROTTLE] >> 3); } } } // returns the current pulse width measured on a radio channel unsigned short Radio_PulseWidth(unsigned char channel) { if (channel < RADIO_MAX_CHANNELS) { return radio_pulse[channel]; } else { return -1; } } // returns true if the flag has be asserted, indicating a new recieved pulse unsigned char Radio_ReadyFlag(unsigned char channel) { if (channel < RADIO_MAX_CHANNELS) { return (radio_flag & (1<<channel)); } else { return 0; } } // acknowledges a flag by setting it low void Radio_DisassertFlag(unsigned char channel) { if (channel < RADIO_MAX_CHANNELS) { radio_flag &= ~(1<<channel); } F-65 ECE 477 Final Report Spring 2008 } // turns on radio pass through for channels specified in mask void Radio_PassthruSet(unsigned char mask) { radio_passthru |= mask; } // turns off radio pass through for channels specified in mask void Radio_PassthruUnset(unsigned char mask) { radio_passthru &= ~mask; } /******************************* End of radio.c *******************************/ /******************************* radio.h *************************************** * * * Author: David Collins * * Project: Global Pigeon - ECE 477 Team 10, Spring 2008 * * * * Provides access to radio input counts and allows for the setting of radio * * pass through on each channel individually. When pass through is enabled, * * radio values are immediately sent to the servos. * * * *******************************************************************************/ #ifndef HEADER_RADIO_H #define HEADER_RADIO_H #define RADIO_MAX_CHANNELS 6 #define #define #define #define #define #define RADIO_CH_AUTO 0 RADIO_CH_GEAR 1 RADIO_CH_ELEVATOR 2 RADIO_CH_RUDDER 3 RADIO_CH_AILERON 4 RADIO_CH_THROTTLE 5 #define #define #define #define #define RADIO_MASK_ELEVATOR (1 << RADIO_CH_ELEVATOR) RADIO_MASK_RUDDER (1 << RADIO_CH_RUDDER) RADIO_MASK_AILERON (1 << RADIO_CH_AILERON) RADIO_MASK_THROTTLE (1 << RADIO_CH_THROTTLE) RADIO_MASK_ALL (0xFF) // configures the timer input capture to allow for receiving servo signals void Radio_Init(void); // output a radio channel value unsigned short Radio_PulseWidth(unsigned char channel); F-66 ECE 477 Final Report Spring 2008 // returns true if the flag has be asserted, indicating a new recieved pulse unsigned char Radio_ReadyFlag(unsigned char channel); // acknowledges a flag by setting it low void Radio_DisassertFlag(unsigned char channel); // outputs currect radio values out to the servos connected to the PWM module void Radio_Passthru(void); // turns on radio pass through for channels specified in mask void Radio_PassthruSet(unsigned char mask); // turns off radio pass through for channels specified in mask void Radio_PassthruUnset(unsigned char mask); #endif /******************************* End of radio.h *******************************/ /******************************* servo.c *************************************** * * * Author: David Collins * * Project: Global Pigeon - ECE 477 Team 10, Spring 2008 * * * * Uses the PWM module to send servo pulses using all port P pins. However, * * only pins 1,3,5, and 7 of port P have an output signal. The pulse are 1ms * * to 2ms in duration every 20ms to indicate full left to full right. The PWM * * channels operate in 16bit concatenated mode. * * * *******************************************************************************/ #include <hidef.h> #include <mc9s12a64.h> #include "servo.h" #include "pigeon.h" /* 9S12A64 Pins PTP0-PTP7 Outputs on PTP1, PTP3, PTP5, PTP7 */ // used to interact with duty and period registers unsigned short *PWM_Duty16_Offset = (unsigned short *)&PWMDTY0; unsigned short *PWM_Period16_Offset = (unsigned short *)&PWMPER0; // sets up the PWM registers for 20ms period and servo centered initial duty void Servo_Init(void) { // Disable PWM module for PTT0,1; setting to 16bit mode works only when disabled PWME = 0; F-67 ECE 477 Final Report Spring 2008 // Duty On time is logic high PWMPOL = 0xFF; // use clock A and B respectively PWMCLK = 0; // left aligned PWM PWMCAE = 0; // clock A prescaler of 8 // for a 16bit PWM and 24MHz clock, this leads to 60000 period = 20ms // thus duty values of 3000 to 6000 are approprate servo values PWMPRCLK = 0b00110011; // 100Hz //PWMPRCLK = 0b00100010; // enable PWM channel concatenation to get 16bit PWM PWMCTL |= 0xF0; PWM_Period16(0, SERVO_PWM_PERIOD); Servo_Duty(SERVO_CH_THROTTLE, SERVO_IN_MIN); Servo_Duty(SERVO_CH_AILERON, 0); Servo_Duty(SERVO_CH_ELEVATOR, 0); Servo_Duty(SERVO_CH_RUDDER, 0); // Enable PWM module PWME = 0xFF; } // Tested with a Hitec HS-322HD // It was able to operate at 50Hz and 100Hz, but seized at 150Hz and 200Hz. // The total range of inputs with period=255, is duty=15 to 62, this corresponds to about 200deg of rotation // sets the duty cycle of selected 16bit PWM channel // only two 16bit channels are available void PWM_Duty16(unsigned char channel, unsigned short value) { if (channel < SERVO_COUNT) // ensure only valid channels can be set { PWM_Duty16_Offset[channel] = value; } } // sets the period of selected 16bit PWM channel void PWM_Period16(unsigned char channel, unsigned short value) { if (channel < SERVO_COUNT) // ensure only valid channels can be set { PWM_Period16_Offset[channel] = value; } F-68 ECE 477 Final Report Spring 2008 } // sets the pulse width of a servo channel // this corresponds to a 16bit PWM channel // input values are SERVO_IN_MIN to SERVO_IN_MAX void Servo_Duty(unsigned char channel, short value) { if (channel < SERVO_COUNT) // ensure only valid channels can be set { // saturate inputs to handle out of range values if (value > SERVO_IN_MAX) value = SERVO_IN_MAX; if (value < SERVO_IN_MIN) value = SERVO_IN_MIN; // scale to get correct servo pwm duty cycle // this simple technique ensures that the zero point // is handle correctly, but could lead to high or low clipping // a multiplicative scaling method would be more appropriate // but more difficult to do with integers value += SERVO_OUT_PWM_ZERO; if (value > SERVO_OUT_PWM_MAX) value = SERVO_OUT_PWM_MAX; if (value < SERVO_OUT_PWM_MIN) value = SERVO_OUT_PWM_MIN; PWM_Duty16_Offset[channel] = value; } } /******************************* End of servo.c *******************************/ /******************************* servo.h *************************************** * * * Author: David Collins * * Project: Global Pigeon - ECE 477 Team 10, Spring 2008 * * * * Provides access to the 4, 16bit PWM channels. Specifies maximum input and * * output values for servos as well as mappings to channel names. * * * *******************************************************************************/ #ifndef HEADER_SERVO_H #define HEADER_SERVO_H // range of values accepted as input to servo control functions #define SERVO_IN_MAX (1500) #define SERVO_IN_MIN (-1500) // number of prescaled clock cycles in one period // used to achieve a 50Hz PWM for the servos // value is dependent upon the system bus clock frequency #define SERVO_PWM_PERIOD 60000 // allowable range of servo duty cycles // correspond to approximately 1ms to 2ms, with tweaking // for individual servo differences F-69 ECE 477 Final Report Spring 2008 #define SERVO_OUT_PWM_MAX 6000 #define SERVO_OUT_PWM_ZERO 4500 #define SERVO_OUT_PWM_MIN 3000 #define #define #define #define SERVO_CH_THROTTLE 0 SERVO_CH_AILERON 1 SERVO_CH_ELEVATOR 2 SERVO_CH_RUDDER 3 // number of 16bit servo channels #define SERVO_COUNT 4 // sets up the PWM registers for 20ms period and servo centered initial duty void Servo_Init(void); // sets the duty cycle of selected 16bit PWM channel // only two 16bit channels are available void PWM_Duty16(unsigned char channel, unsigned short value); // sets the period of selected 16bit PWM channel void PWM_Period16(unsigned char channel, unsigned short value); // sets the pulse width of a servo channel // this corresponds to a 16bit PWM channel // input values are SERVO_IN_MIN to SERVO_IN_MAX void Servo_Duty(unsigned char channel, short value); #endif /******************************* End of servo.h *******************************/ /********************************* sci.c *************************************** * * * Author: David Collins * * Project: Global Pigeon - ECE 477 Team 10, Spring 2008 * * * * Sets up the SCI ports to run at a specified baud rate. Provides various * * functions to print out integers in different ways. * * * *******************************************************************************/ #include <mc9s12a64.h> #include "SCI.h" #include "pigeon.h" char PrintBuffer[PRINT_BUFFER_SIZE]; // port can be either 0 or 1 // sets the serial port baud rate to anything you like F-70 ECE 477 Final Report Spring 2008 // taking into account the system clock frequency void SCI_Init(char port, unsigned long int BaudRate) { BaudRate = (CLOCK_SPEED / 16) / BaudRate; // determine the frequency divisor if (port == 0) { SCI0BDH = (unsigned char)(BaudRate >> 8); SCI0BDL = BaudRate & 0xFF; SCI0CR1 = 0; SCI0CR2 = 0x0C; } else if (port == 1) { SCI1BDH = (unsigned char)(BaudRate >> 8); SCI1BDL = BaudRate & 0xFF; SCI1CR1 = 0; SCI1CR2 = 0x0C; } // // // // set high portion of divisor set low portion of divisor various transmission settings enable transmit and receive // // // // set high portion of divisor set low portion of divisor various transmission settings enable transmit and receive } // wait for data to fill SCI data register then return it char SCI_InChar(char port) { if (port == 0) { while (!(SCI0SR1 & RDRF)); return SCI0DRL; } else if (port == 1) { while (!(SCI1SR1 & RDRF)); return SCI1DRL; } } // wait for SCI data register to be empty, then fill it with the input value to send it over SCI void SCI_OutChar(char port, char data) { if (port == 0) { while (!(SCI0SR1 & TDRE)); SCI0DRL = data; } else if (port == 1) { while (!(SCI1SR1 & TDRE)); SCI1DRL = data; } } // Outputs a null terminated string over SCI F-71 ECE 477 Final Report Spring 2008 void SCI_OutString(char port, const char *pVal) { while(*pVal) { SCI_OutChar(port, *pVal); pVal++; } } // Outputs a 16bit unsigned integer (0-65536) void SCI_OutUInt(char port, unsigned short n) { unsigned char i=0; do { PrintBuffer[i++] = n % 10; n /= 10; } while (n); do { SCI_OutChar(port, PrintBuffer[--i] + '0'); } while (i); } // Outputs a 16bit signed integer void SCI_OutInt(char port, signed short n) { if (n < 0) { n = -n; SCI_OutChar(port, '-'); } SCI_OutUInt(port, (unsigned short)n); } // Outputs a 32bit unsigned integer void SCI_OutULInt(char port, unsigned long n) { unsigned char i=0; do { PrintBuffer[i++] = n % 10; n /= 10; } while (n); do { SCI_OutChar(port, PrintBuffer[--i] + '0'); } while (i); } // Outputs a 32bit unsigned integer void SCI_OutLInt(char port, signed long n) F-72 ECE 477 Final Report Spring 2008 { if (n < 0L) { n = -n; SCI_OutChar(port, '-'); } SCI_OutULInt(port, (unsigned long)n); } // Outputs a 16bit unsigned integer // fit to a certain minimum width void SCI_OutUIntF(char port, unsigned short n, unsigned char width) { unsigned char i=0; // determine digits do { PrintBuffer[i++] = n % 10; n /= 10; } while (n); // pad with spaces while (width > i) { SCI_OutChar(port, ' '); width--; } // output digits do { SCI_OutChar(port, PrintBuffer[--i] + '0'); } while (i); } // prints a character as hex void SCI_OutHex(char port, unsigned char data) { unsigned H, L; L = data & 0xF; H = data >> 4; if (H > 9) SCI_OutChar(port, H - 10 + 'A'); else SCI_OutChar(port, H + '0'); if (L > 9) SCI_OutChar(port, L - 10 + 'A'); else SCI_OutChar(port, L + '0'); } /******************************** End of sci.c ********************************/ F-73 ECE 477 Final Report Spring 2008 /********************************* sci.h *************************************** * * * Author: David Collins * * Project: Global Pigeon - ECE 477 Team 10, Spring 2008 * * * * Sets up the SCI ports to run at a specified baud rate. Provides various * * functions to print out integers in different ways. Contains definitions * * for useful characters and flag states. * * * *******************************************************************************/ #ifndef HEADER_SCI_H #define HEADER_SCI_H // port can be either 0 or 1 // ascii chars #define CR 0x0D #define LF 0x0A #define BS 0x08 #define ESC 0x1B #define SP 0x20 #define DEL 0x7F #define RDRF 0x20 #define TDRE 0x80 // Receive Data Register Full Bit // Transmit Data Register Empty Bit // true when an SCI byte has been received #define SCI0_DATA_READY (SCI0SR1 & RDRF) #define SCI1_DATA_READY (SCI1SR1 & RDRF) // size of buffer for integer printing #define PRINT_BUFFER_SIZE 13 // sets the serial port baud rate to anything you like // taking into account the system clock frequency void SCI_Init(char port, unsigned long int BaudRate); // wait for data to fill SCI data register then return it char SCI_InChar(char port); // wait for SCI data register to be empty, then fill it with the input value to send it over SCI void SCI_OutChar(char port, char data); // Outputs a null terminated string over SCI void SCI_OutString(char port, const char *pVal); // Outputs a 16bit unsigned integer 0-65536 F-74 ECE 477 Final Report Spring 2008 void SCI_OutUInt(char port, unsigned short n); // Outputs a 16bit signed integer void SCI_OutInt(char port, signed short n); // Outputs a 32bit unsigned integer void SCI_OutULInt(char port, unsigned long n); // Outputs a 32bit signed integer void SCI_OutLInt(char port, signed long n); // Outputs a 16bit unsigned integer // fit to a certain minimum width void SCI_OutUIntF(char port, unsigned short n, unsigned char width); // prints a character as hex void SCI_OutHex(char port, unsigned char data); #endif /******************************** End of sci.h ********************************/ /******************************* timer.c *************************************** * * * Author: David Collins * * Project: Global Pigeon - ECE 477 Team 10, Spring 2008 * * * * This file contains contains functions to set up the timer subsystem using * * the timer overflow and TCNT register. It also provides functions for time * * stamping and timed waits. * * * *******************************************************************************/ #include #include #include #include <hidef.h> <mc9s12a64.h> "pigeon.h" "timer.h" // used as a high clock counter, number of overflows unsigned short TOFCount; PARTLONG temptime; // Initializes timer subsystem // to be used for standard timer, or TOF functionality void Timer_Init(unsigned char PrescalerDivisor, int UseTOF) { TSCR1 = 0x80; // enable timer TSCR2 = PrescalerDivisor; // timer prescaler frequency set to system clock freq / 2^n PACTL = 0; // turn off pulse accumulation mode if (UseTOF) { F-75 ECE 477 Final Report Spring 2008 TFLG2 = 0x80; // clear timer overflow flag TSCR2 |= 0x80; // enable timer overflow interrupt //TOFCount = 0; EnableInterrupts } } // interrupt for Timer Overflow interrupt 16 void TOF_Handler(void) { TFLG2 = 0x80; // clear timer overflow flag TOFCount++; // increment TOF count } // Blocking wait for a given number of clock cycles // not completely accurate due to function call overhead void Timer_Wait(unsigned short delay) { unsigned short startTime; startTime = TCNT; while((TCNT-startTime) < delay); } // Wait for given number of milliseconds void Timer_Wait1ms(unsigned short delay) { for(;delay>0;delay--) { Timer_Wait(CLOCK_SPEED/1000); } } // returns the current number of clock ticks in a 32bit int unsigned long int TimeStamp(void) { temptime.Half.Low = TCNT; temptime.Half.High = TOFCount; return temptime.Full; } // return TOFCount unsigned short TOFNow(void) { return TOFCount; } /******************************* End of timer.c *******************************/ F-76 ECE 477 Final Report Spring 2008 /******************************* timer.h *************************************** * * * Author: David Collins * * Project: Global Pigeon - ECE 477 Team 10, Spring 2008 * * * * Provides other code modules with access to time stamping and timed wait * * functions. * * * *******************************************************************************/ #ifndef HEADER_TIMER_H #define HEADER_TIMER_H // Initializes timer subsystem // to be used for standard timer, or TOF functionality void Timer_Init(unsigned char PrescalerDivisor, int UseTOF); // Blocking wait for a given number of clock cycles // not completely accurate due to function call overhead void Timer_Wait(unsigned short delay); // Wait for given number of milliseconds void Timer_Wait1ms(unsigned short delay); // returns the current number of clock ticks in a 32bit int unsigned long int TimeStamp(void); // return TOFCount unsigned short TOFNow(void); #endif /******************************* End of timer.h *******************************/ /********************************* lcd.c *************************************** * * * Author: David Collins * * Project: Global Pigeon - ECE 477 Team 10, Spring 2008 * * * * Provides functions to send commands to the LCD screen. The format of the * * commands is specific to the Matrix Orbital LCD2041. * * * *******************************************************************************/ #include <mc9s12a64.h> #include "sci.h" F-77 ECE 477 Final Report Spring 2008 #include "lcd.h" // initializes the LCD and sets a screen brightness void LCD_Init(unsigned char backlight) { SCI_Init(1, 19200); // LCD connection // clear the screen SCI_OutChar(1, LCD_NEW_PAGE); LCD_SetBrightness(backlight); } // sends a simple command to the LCD screen void LCD_SendCommand(unsigned char command) { SCI_OutChar(1, LCD_START_COMMAND); SCI_OutChar(1, command); } // sets the LCD backlight brightness void LCD_SetBrightness(unsigned char value) { SCI_OutChar(1, LCD_START_COMMAND); SCI_OutChar(1, LCD_SET_BRIGHTNESS); SCI_OutChar(1, value); } /******************************** End of lcd.c ********************************/ /********************************* lcd.h *************************************** * * * Author: David Collins * * Project: Global Pigeon - ECE 477 Team 10, Spring 2008 * * * * Provides functions to send commands to the LCD screen. The format of the * * commands is specific to the Matrix Orbital LCD2041. Defines all of the * * specific commands available. * * * *******************************************************************************/ #ifndef HEADER_LCD #define HEADER_LCD // uses commands specific to LCD2041 // control characters #define LCD_BACKSPACE 0x08 #define LCD_NEW_PAGE 0x0C #define LCD_CR 0x0D #define LCD_LF 0x0A #define LCD_START_COMMAND 0xFE F-78 ECE 477 Final Report Spring 2008 // pure commands, no arguments #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define LCD_AUTO_LINE_WRAP_ON 0x43 LCD_AUTO_LINE_WRAP_OFF 0x44 LCD_DISPLAY_OFF 0x46 LCD_GO_HOME 0x48 LCD_UNDERLINE_CURSOR_ON 0x4A LCD_UNDERLINE_CURSOR_OFF 0x4B LCD_CURSOR_BACK 0x4C LCD_CURSOR_FORWARD 0x4D LCD_AUTO_SCROLL_ON 0x51 LCD_AUTO_SCROLL_OFF 0x52 LCD_CURSOR_BLOCK_BLINKING_ON 0x53 LCD_CURSOR_BLOCK_BLINKING_OFF 0x54 LCD_CLEAR_SCREEN 0x58 LCD_INIT_HORIZONTAL_BAR 0x68 LCD_INIT_MEDIUM_NUM 0x6D LCD_INIT_LARGE_NUM 0x6E LCD_INIT_NARROW_VERTICAL_BAR 0x73 LCD_INIT_WIDE_VERTICAL_BAR 0x76 // commands with arguments #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define LCD_PLACE_LARGE_NUM 0x23 LCD_SET_I2C_SLAVE_ADDR 0x33 LCD_SET_BAUD 0x39 LCD_PLACE_VERTICAL_BAR 0x3D LCD_SET_STARTUP_SCREEN 0x40 LCD_DISPLAY_ON 0x42 LCD_SET_CURSOR_POSITION 0x47 LCD_CREATE_CUSTOM_CHAR 0x4E LCD_SET_CONTRAST 0x50 LCD_GPO_OFF 0x56 LCD_GPO_ON 0x57 LCD_PLACE_MEDIUM_NUM 0x6F LCD_PLACE_HORIZONTAL_BAR 0x7C LCD_SET_SAVE_CONSTRAST 0x91 LCD_SET_REMEMBER 0x93 LCD_SET_SAVE_BRIGHTNESS 0x98 LCD_SET_BRIGHTNESS 0x99 LCD_SET_BAUD_NONSTANDARD 0xA4 LCD_LOAD_CUSTOM_CHARS 0xC0 LCD_SAVE_CUSTOM_CHARS 0xC1 LCD_SAVE_STARTUP_CUSTOM_CHARS 0xC2 LCD_SET_STARTUP_GPO_STATE 0xC3 // FUNCTIONS // initializes the LCD and sets a screen brightness void LCD_Init(unsigned char backlight); // sends a simple command to the LCD screen void LCD_SendCommand(unsigned char command); F-79 ECE 477 Final Report Spring 2008 // sets the LCD backlight brightness void LCD_SetBrightness(unsigned char value); #endif /******************************** End of lcd.h ********************************/ /********************************* adc.c *************************************** * * * Author: David Collins * * Project: Global Pigeon - ECE 477 Team 10, Spring 2008 * * * * Contains functions to set up and read analog values. Should work on any * * 9S12 variant. * * * *******************************************************************************/ #include <hidef.h> #include <mc9s12a64.h> #include "adc.h" // Initialize ATD subsystem void ADC_Init(void) { ATD0CTL2 = 0x80; // enable ADC ATD0CTL3 = 0x08; // conversion length of 1 ATD0CTL4 = 0x05; // set sample clock to 2MHz which is max } // Returns a 10bit right justified value for the input channel specified // in a 16bit integer unsigned short ADC_In(unsigned char channel) { ATD0CTL5 = 0x80 | channel; // start the conversion sequence while(!(ATD0STAT0 & 0x80)); // wait for the conversion to complete return ATD0DR0; } /******************************** End of adc.c ********************************/ /********************************* adc.h *************************************** * * * Author: David Collins * * Project: Global Pigeon - ECE 477 Team 10, Spring 2008 * * * * Contains functions to set up and read analog values. Should work on any * * 9S12 variant. * * * *******************************************************************************/ #ifndef HEADER_ADC_H F-80 ECE 477 Final Report Spring 2008 #define HEADER_ADC_H #define #define #define #define #define ADC_CH_VSENSE ADC_CH_THERM0 ADC_CH_THERM1 ADC_CH_THERM2 ADC_CH_THERM3 0 3 4 5 6 // Initialize ATD subsystem void ADC_Init(void); // Returns a 10bit right justified value for the input channel specified // in a 16bit integer unsigned short ADC_In(unsigned char channel); #endif /******************************** End of adc.h ********************************/ /********************************* pll.c *************************************** * * * Author: David Collins * * Project: Global Pigeon - ECE 477 Team 10, Spring 2008 * * * * Sets up the PLL system so that the MCU can run at 24MHz. This function * * should work with any 9S12 variant. * * * *******************************************************************************/ #include <hidef.h> #include <mc9s12a64.h> // Set PLL clock to 24 MHz, and switch 9S12 to run at this rate void PLL_Init(void) { SYNR = 0x02; // set PLL multiplier REFDV = 0x00; // set PLL divider CLKSEL = 0x00; // keep using OSCCLK PLLCTL = 0xD1; // set various condition bits for the transition while(!(CRGFLG & 0x08));// Wait for PLLCLK to stabilize. CLKSEL_PLLSEL = 1; // Switch to PLL clock } /******************************** End of pll.c ********************************/ /********************************* pll.h *************************************** * * * Author: David Collins * * Project: Global Pigeon - ECE 477 Team 10, Spring 2008 * * * F-81 ECE 477 Final Report Spring 2008 * Sets up the PLL system so that the MCU can run at 24MHz. This function * * should work with any 9S12 variant. * * * *******************************************************************************/ #ifndef HEADER_PLL_H #define HEADER_PLL_H // Set PLL clock to 24 MHz, and switch 9S12 to run at this rate void PLL_Init(void); #endif /******************************** End of pll.h ********************************/ /******************************* debug.h *************************************** * * * Author: David Collins * * Project: Global Pigeon - ECE 477 Team 10, Spring 2008 * * * * Used to print debug messages out of the SCI port. Conditional compilation * * ensures that there is no overhead when not debugging. * * * *******************************************************************************/ #ifndef HEADER_DEBUG #define HEADER_DEBUG #include "sci.h" //#define DEBUGGING #ifdef DEBUGGING // in debug mode #define DEBUG(x) SCI_OutString(1, x); #else // not in debug mode #define DEBUG(x) #endif // define if you want to only output GPS chars directly //#define GPSPASSTHRU #endif /******************************* End of debug.h *******************************/ F-82 ECE 477 Final Report Spring 2008 Appendix G: FMECA Worksheet Table G.1 – Microcontroller (Block A) FEMCA Failure Failure Mode No. A1 Microcontroller outputs no data A2 Some pins are always 0 or 1 Possible Causes Failure Effects Out of spec supply voltage, U1 failure, clock failure, PLL failure, software bug, bypass caps shorted Over-voltage on pin could have burned up the driver, software bug No display on LCD, does not work in autonomous mode Erratic system behavior, excessive heating of the microcontroller G-1 Method of Detection Observation Observation Criticality MediumHigh MediumHigh Remarks This failure would be elevated to high criticality if a shorting component caused excess heat dissipation This failure would be elevated to high criticality if a shorting component caused excess heat dissipation ECE 477 Final Report Spring 2008 Table G.2 – Voltage Regulators and Battery Sensing (Block B) FEMCA Failure Failure Mode No. B1 Vout,5 = 0V or Vout,3.3 = 0V Possible Causes Failure Effects Method of Detection Observation Criticality High Remarks Failure of U6 or U7, Shorted capacitor in Block B, no feedback, external short System shows no operation Failure of U6 or U7 Could damage any of the ICs on the board, system probably nonfunctional Erratic microcontroller failure, perhaps repeated resetting Observation High Observation Medium Unlikely to cause harm, but results in nonflyable plane Microcontroller reports unreasonable battery voltage Observation Low Medium Probably just a nuisance which would fry a port pin, but could also cause the entire microcontroller to fail. B2 Vout,5 > 5V or Vout,3.3 > 3.3V B3 Vout,5 or Vout,3.3 not Failure of a capacitor regulated enough in Block B that becomes and open circuit B4 Vsense > 5V R20 fails and causes a short G-2 If a short is causing the lack of output, excessive heat is being generated on the PCB or lead to a battery explosion, which could injury the user Possibility of injurious heat dissipation ECE 477 Final Report Spring 2008 Table G.3 – Radio input and Servo output (Block C) FEMCA Failure Failure Mode No. C1 Autopilot / Manual multiplexer signal incorrect C2 C3 Possible Causes U18 failure, or failure of any of the resistors or capacitors directly before it Failure Effects Plane does not properly switch between manual and autopilot Method of Detection Observation Criticality High Inputs do not U13 or R40 failure propagate through multiplexer Servo motors do not respond to manual input or autopilot Observation High Multiplexer always output either manual or autopilot values Cannot switch operating modes Observation High S pin of U13 shorted to Vcc or ground G-3 Remarks If this failure arose during a flight, the plane could crash, possibly injuring a person This would cause the plane to crash, possibly injuring someone Could cause injury if the drive motor powered up unexpectedly on the ground ECE 477 Final Report Spring 2008 Table G.4 – Thermopile Amplifiers (Block D) FEMCA Failure Failure Mode No. D1 Vref = 0V Possible Causes Failure Effects U14 failure, could also have its input or output shorted to ground Thermopiles do not sense sky properly, unstable flight Method of Detection Observation Criticality Remarks High Could cause injury if crash induced D2 Vref > 2.5V U14 failure Thermopiles do not sense ground as well, jittery flight Observation High Medium Could lead to crashing D3 Amplifier output is very small Plane cannot stabilize Observation High Would lead to crashing in autopilot mode, and possibly injure the operator D4 Thermopile values read in are erratic Failure of U9 or U10, Failure of any of the resistors in Block D such that they become shorts Connection to thermopiles could be faulty Jittery flight Observation Medium Could lead to crashing G-4 ECE 477 Final Report Spring 2008 Table G.5 – GPS and MicroSD Interface Circuits (Block E) FEMCA Failure Failure Mode No. E1 Unable to communicate with MicroSD card E2 Possible Causes Failure of U2, U3, or U4; Any resistor in the SD circuit becomes open; SD card corrupt; software Unable to Failure of U15, U16, communicate or U17; resistor in with GPS receiver GPS circuit becoming open; faulty cable; software bug Failure Effects System unable to read MicroSD card, displays error message Method of Criticality Detection Observation and Medium BIST System unable to Observation and Medium get a GPS lock, BIST waits indefinitely and will not allow autonomous flight Remarks No risk of injury, but the plane cannot operate autonomously No risk of injury, but the plane cannot operate autonomously Table G.6 – Camera and LCD Interface Circuits (Block F) FEMCA Failure Failure Mode No. F1 LCD_TX signal always idle F2 Camera shutter trigger always open Possible Causes Failure of U12, short or open circuit of any of the capacitors or resistors connected to U12 Failure of U11, software malfunction Failure Effects LCD is always blank Camera never takes photos G-5 Method of Detection Observation Criticality Low Observation and Low BIST Remarks This is a nuisance, but the plane will operate properly The plane will fly, but no photos will be taken