doc

advertisement
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
Download