EE 477 Final Report



ECE 477 Final Report

Spring 2006

[pic]

Team Code Name: __________Brightriders_______________________ Team ID: ___13__

Team Members (#1 is Team Leader):

#1: ____Joe Waugh______________ Signature: ____________________ Date: _________

#2: ____Evan Zelkowitz__________ Signature: ____________________ Date: _________

#3: ____Matt Cozza _____________ Signature: ____________________ Date: _________

#4: ____Elmer Chao_____________ Signature: ____________________ Date: _________

REPORT EVALUATION

|Component/Criterion |Score |Multiplier |Points |

|Abstract |0 1 2 3 4 5 6 7 8 9 10 |X 1 | |

|Project Overview and Block Diagram |0 1 2 3 4 5 6 7 8 9 10 |X 2 | |

|Team Success Criteria/Fulfillment |0 1 2 3 4 5 6 7 8 9 10 |X 2 | |

|Constraint Analysis/Component Selection |0 1 2 3 4 5 6 7 8 9 10 |X 2 | |

|Patent Liability Analysis |0 1 2 3 4 5 6 7 8 9 10 |X 2 | |

|Reliability and Safety Analysis |0 1 2 3 4 5 6 7 8 9 10 |X 2 | |

|Ethical/Environmental Impact Analysis |0 1 2 3 4 5 6 7 8 9 10 |X 2 | |

|Packaging Design Considerations |0 1 2 3 4 5 6 7 8 9 10 |X 2 | |

|Schematic Design Considerations |0 1 2 3 4 5 6 7 8 9 10 |X 2 | |

|PCB Layout Design Considerations |0 1 2 3 4 5 6 7 8 9 10 |X 2 | |

|Software Design Considerations |0 1 2 3 4 5 6 7 8 9 10 |X 2 | |

|Version 2 Changes |0 1 2 3 4 5 6 7 8 9 10 |X 1 | |

|Summary and Conclusions |0 1 2 3 4 5 6 7 8 9 10 |X 1 | |

|References |0 1 2 3 4 5 6 7 8 9 10 |X 2 | |

|Appendix A: Individual Contributions |0 1 2 3 4 5 6 7 8 9 10 |X 4 | |

|Appendix B: Packaging |0 1 2 3 4 5 6 7 8 9 10 |X 2 | |

|Appendix C: Schematic |0 1 2 3 4 5 6 7 8 9 10 |X 2 | |

|Appendix D: Top & Bottom Copper |0 1 2 3 4 5 6 7 8 9 10 |X 2 | |

|Appendix E: Parts List Spreadsheet |0 1 2 3 4 5 6 7 8 9 10 |X 2 | |

|Appendix F: Software Listing |0 1 2 3 4 5 6 7 8 9 10 |X 2 | |

|Appendix G: FMECA Worksheet |0 1 2 3 4 5 6 7 8 9 10 |X 2 | |

|Technical Writing Style |0 1 2 3 4 5 6 7 8 9 10 |X 8 | |

|CD of Project Website |0 1 2 3 4 5 6 7 8 9 10 |X 1 | |

| |TOTAL | |

TABLE OF CONTENTS

|Abstract |1 |

| 1.0 Project Overview and Block Diagram |1 |

| 2.0 Team Success Criteria and Fulfillment |3 |

| 3.0 Constraint Analysis and Component Selection |4 |

| 4.0 Patent Liability Analysis |8 |

| 5.0 Reliability and Safety Analysis |13 |

| 6.0 Ethical and Environmental Impact Analysis |20 |

| 7.0 Packaging Design Considerations |24 |

| 8.0 Schematic Design Considerations |29 |

| 9.0 PCB Layout Design Considerations |32 |

|10.0 Software Design Considerations |36 |

|11.0 Version 2 Changes |42 |

|12.0 Summary and Conclusions |43 |

|13.0 References |44 |

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

Abstract

The Purdue Solar Racing Telemetry System is a module which communicates with other modules in the solar car, and relays these communications to a tracking car. The Telemetry System communicates with the Motor Controller, the Battery Protection System, the Wireless Packet Modem, the GPS Module, the Maximum Power Point Trackers, and the Driver Interface. The Telemetry System receives data from all of the connected modules, and transmits this data wirelessly to a laptop in the tracking car.

1.0 Project Overview and Block Diagram

1.1 Overview

The Purdue Solar Racing Telemetry System is a module which communicates with other modules in the solar car, and relays these communications to a tracking car. The Telemetry System communicates with the Motor Controller, the Battery Protection System, the Wireless Packet Modem, the GPS Module, the Maximum Power Point Trackers, and the Driver Interface. The Telemetry System receives data from all of the connected modules, and transmits this data wirelessly to a laptop in the tracking car. This laptop uses a LabView setup to receive and interpret the data, so that the tracking team can view and log the status of the solar car. This project is a replacement for the current Telemetry System, which does not have a GPS module, CAN bus interface, accelerometer, or temperature sensor.

The main features of the Telemetry System are the methods it uses to communicate with the different modules inside the solar car. The system will be interfacing to the Driver Interface and Maximum Power Point Trackers through the use of a CAN bus. The accelerometers and temperature sensor are populated on the telemetry board itself, and the GPS Module, Motor Controller, Battery Protection System, and Wireless Packet Modem are all interfaced via RS232. The Telemetry system can run under two modes: race and diagnostics. During race mode, the microprocessor of the Telemetry System is programmed to poll various parameters periodically from the devices it’s interfaced to and then transmits this information to the chase vehicle via the Wireless Packet Modem. In addition, the Telemetry system serves as a center of communication by allowing the chase vehicle to request to send text messages to the Driver Interface System. Also, the Telemetry system takes requests from the Driver Interface System to provide information about vehicle parameters back to the Driver Interface System. In the diagnostics mode, the Telemetry system is able to listen to requests from the chase car to change parameters within the individual modules connected to it.

[pic]

Figure 1.1.1 Telemetry System Block Diagram

[pic]

Figure 1.1.2 Telemetry System Completed Project

2.0 Team Success Criteria and Fulfillment

Project-Specific Success Criteria:

1) Ability to receive and store motor status data from the motor controller via RS232.

Assessment: This PSSC has been completed and demonstrated.

2) Ability to receive and store battery status data from the battery protection system via RS232.

Assessment: This PSSC has been completed and demonstrated.

3) Ability to receive, store, and transmit data to and from CAN nodes on the CANbus, acting as the CAN master.

Assessment: This PSSC has been completed and demonstrated.

4) Ability to read and store data retrieved from on-board sensors, including the 3D-accelerometer and temperature sensor.

Assessment: This PSSC has been completed and demonstrated.

5) Ability to send stored data through the packet modem linked with the chase vehicle, both automatically and upon request.

Assessment: This PSSC has been completed and demonstrated.

3.0 Constraint Analysis and Component Selection

3.1 Design Constraint Analysis

The major design constraints when choosing our parts were connectivity. We need to ensure that we can have at least four usable UART channels for communication as well as a way to communicate over a CANbus. It would also be positive if the devices can be used in a low power mode or be put to sleep when not in use so as to minimize the amount of power that they draw. A large limiting factor is the size of the microcontroller itself. We are limited to using the PIC 18F family in order to stay consistent with other components on the car. This fact proves to limit our memory size as well as pin count, which later affects our choice of output peripherals.

3.1.1 Computation Requirements

Our device has to be able to handle interrupts coming from the CANbus in order to determine if it needs to gather and then send out information. It may also have to handle interrupts over RS232 as well coming from the RF modem. It does not have any true real time constraints as it is just collecting data and not controlling any part of the vehicle itself. The only true possible real-time constraints would be our polling of data from the battery pack and motor controller as we plan to do this about every second. Although this would not be a hard set constraint, it would be heavily preferred to have it as consistent as possible.

3.1.2 Interface Requirements

The accelerometers require three ATD channels to acquire data and two general purpose I/O channels to use as select lines. The SPI to UART interface chip also requires four general purpose I/O pins to use as an interrupt line, a reset, and two chip select lines to go to both of our SPI to UART chips. Both of these peripherals also require a voltage input of 3.3V. As is evident, most of our interface requirements actually use the on board peripherals and not general purpose I/O.

3.1.3 On-Chip Peripheral Requirements

Depending on which chip solutions we decide to go with, we will be using SPI, UART, a few general I/O ports, and a few ATD ports. The SPI will be used to interface to two external UART chips to expand our serial capabilities. These expanded UART channels will be used to communicate to the battery pack and the motor controller. The remaining UART port will be used for communication with the RF modem. As stated above, three ATD channels will be needed for the accelerometer chips. Depending upon our temperature sensor of choice we will most likely also need one or two ATD channels for the temperature as well. Finally we will be using the CAN interface provided on the microcontroller. This will first interface to a CAN transceiver chip in order to give us the current voltage input to our controller since the CANbus runs at 12 volts. After interfacing with the transceiver it will then process CAN requests and output data on the bus as requested.

3.1.4 Off-Chip Peripheral Requirements

The main off-chip peripheral that we need is a way to expand our UART port selection. The initial choice for this issue was a chip from Phillips that would let us gain either four or eight UART channels by connecting to one of our 8-bit parallel ports. Later we discovered that it would also require more pins than we could provide to create an address bus and to use as select lines. It was determined that we could not give up this many pins on such a small microcontroller.

We have since decided to go with another chip from Phillips which provides SPI to UART interfacing. This chip connects to the SPI interface on the microcontroller and then provides two UART ports. It also provides an interrupt input so that we can be notified of changes on the RS232 lines and can read them accordingly. This chip also has built-in FIFO buffers so that we do not have to constantly monitor the input and can just check the interrupt line. Since we will be needing four UART ports, we will need two of these chips. Each chip has a built in chip select to turn them off and on. These will be signaled using general I/O ports. The other off-chip peripherals that we need are three accelerometer chips, one for each axis, and a temperature sensor. We originally had looked at using a three axis accelerometer from Freescale but discovered that the part was only offered in the QFN package which we have no way of mounting with the equipment provided. The three-axis Freescale model is also available pre-mounted on a PCB from . We would like to use this model but it is dependent on approval from the Purdue solar racing team. Due to these circumstances we have decided to go with separate chips for each axis.

3.1.5 Power Constraints

Our device has to interface to a provided 12 volt rail and use as little power as possible. We have found a 90-95% efficient 12 volt to 5 volt DC-DC converter that we plan on using, as most of the other groups working on the solar car have also decided to use this part. The device does not need to operate in a cool environment or be handled during use, so heat dissipation is not a constraint.

3.1.6 Packaging Constraints

There is a large amount of open space in the cavity of the solar car so there is not really a size constraint at all. The packaging itself needs to provide port access for three RS232 ports as well the as the proprietary CAN connector standard. For easy maintenance our packaging should not have an overly complicated or permanently sealed system. This would allow the solar team to replace parts or re-program the system without much hassle.

3.1.7 Cost Constraints

The cost constraint of this product is to make it as low cost as possible to fit within the Purdue solar car team’s budget. Since this is a custom built project for specific use in the Purdue solar car, there are no competing projects or products to have to match or beat price with. The parts chosen should be sampleable. This will allow most of the parts to be received free of cost to the solar team and allow the budget to be used for the more expensive parts such as the GPS unit.

3.2 Component Selection Rationale

Our two main chips for consideration were our microcontroller and our UART interface. When choosing the microcontroller we have been restricted to the PIC 18F family in order to maintain a standard controller across all of the Purdue Solar Car. From this point we wanted a controller that had built in CAN capabilities since it is the standard in this project with which we all have the least amount of experience. This led us to two choices for our microcontroller; the PIC 18f4680 and the 18f4585. The defining characteristic between the two was the amount of space provided on each. The 4680 [1] provides us with 64k of memory while the 4585 only provides 48k. Since at this point we are unsure of how much space the libraries and code will take up in our program we decided to go with the 4680 since it provides us with the most amount of space while still providing us with a sufficient amount of I/O ports and CAN functionality. A good example of a microcontroller not chosen from the PIC 18F would be the Atmega1280 from Atmel. This microcontroller contains all the needed peripherals that we use as well as incorporating quad-UART functionality. This would allow us to do our design without the need for the SPI-UART chips. The issue with this chip would be its lack of support for CAN so an external chip would be necessary. Atmel does make one chip, the AT90CAN128, that contains a CAN interface as well as two UART connections. This would have allowed us to use only one of the SPI-UART chips and would be a very good choice for this project.

For the UART interface we looked at two chips; the [3] Phillips SC28L198A1A Eight Channel UART and the [2] Phillips SC16IS752IPW I2C/SPI to dual UART. The first option connects through an eight bit parallel bus to provide communication between the host CPU and the UART chip. It also requires more pins to create an address bus, as well as select lines. The latter chip only requires the standard SPI interface along with four general I/O pins to be used as an interrupt, reset, and two chip selects. Due to the large amount of pins required by the first choice and the size of the microcontroller we are using, we decided to go with [2]. In order to expand our available UART ports we will be using two of these chips. Each one will have it’s chip select lines interfaced through general purpose I/O. From there we can select which chip we wish to activate.

3. Summary

This document has discussed the design constraints of the Purdue solar car telemetry system. We have listed the functional needs of this project which include ability to communicate over multiple RS232 connections and CANbus, as well as communicate to various off chip sensors. We have listed the various on chip and off chip peripherals that we have decided to use in this project including our choice of microcontroller and UART communication chips. This design is not particularly limited by space or cost but by power consumption and the pre-defined limit of controllers. This limited selection of controllers has greatly influenced the rest of our decisions as far as off-chip peripherals are concerned due to the limiting factor of I/O pins.

4.0 Patent Liability Analysis

4.1 Introduction

For the patent liability assessment, the collection of all of the functions employed by the Telemetry System is of concern. There are several patents in existence today that describe some of these functions and methods in its claims. What has to be determined is whether these claims are an exact description of the function/method that our Telemetry System utilizes.

4.2 Results of Patent and Product Search

US Patent #6,023,232 [5]

Vehicle Communications Systems and Method

Filed: June 23, 1997

Condensed Abstract: This patent describes a vehicle communications system in which a number of devices are connected to a central computer which processes data networking applications. The devices are capable of transmitting and receiving information through channels associated with the central computer. Within the central computer also lies an adaptive control that is capable of selecting each individual device to perform a certain function.

Key Claim #1:

Key claim #1 basically describes the system consisting of a number of devices connected to a central computer that runs networking applications. The key portion of the claim is the description about the adaptive application control, which is said to be separate from the data networking applications and communicates with the networking applications through a data format that is unique to the individual devices. This claim seems to emphasize the role of an independent adaptive control that communicates with the networking applications and then makes a decision as to which devices will perform which functions given the requirements set by the networking applications. The adaptive control in this case seems to act as a middle-manager which takes in the needs of the networking applications and then executes them by utilizing the connected devices.

Key Claim #2: This claim describes a system of claim 1, where the interfaces used between the device and the central computer must consist of at least a CAN interface, RS232 interface, PCMCIA interface, Domestic Digital Bus interface, or a IR interface.

Key Claim #3: This claim describes a system of claim 1 and adds that the devices which are connected to the central computer are at least one of a GPS, PDA, GSM, a CD-ROM unit, and an RDS-TMC unit.

Key Claim #4: This claim describes a system of claim 1 and describes the data networking applications in the central computer being at least one of a fleet management application, route planning applications, a remote diagnosis application, an antitheft protection application, and an electronic data communications application.

US Patent #6,941,194 [6]

Motor Vehicle Communication System and method for exchanging data in a motor vehicle.

Filed: November 19, 1999

Condensed Abstract: This patent describes a vehicle communications system that uses a processor connected to numerous data sources and numerous operator consoles.

Key Claim #1: This claim describes the vehicle communications system in which a number of data sources and operator consoles are connected to a processor. The operator consoles must have user interfaces which allow a person to access the applications on the processor and retrieve information. The emphasis of this claim is that the processor allocates access rights with different degrees of priorities to each of the operator consoles for access to the data applications.

US Patent #6,526,460 [7]

Vehicle communications system

Filed: August 30, 1999

Condensed Abstract: The patent describes a vehicle communications system that consists of numerous devices used for transmitting, receiving, acquiring, or processing data for the purpose of executing applications all while using a common data bus.

Key Claim #1: This claim describes a system in which a number of devices used for transmitting, receiving, and processing information are connected together by a common bus. The emphasis in this claim is that the devices are all connected through a common bus. In this system, the applications within the system are each assigned functions which are executed through one or more of the devices connected to the system.

4.3 Analysis of Patent Liability

US Patent #6,023,232 has four claims that have aspects in common with the Telemetry System. Claims 2, 3, and 4 are dependent upon claim #1, and will act as literal infringements for the Telemetry System if claim #1 is proven to be an infringement under the doctrine of equivalents [9]. Ignoring claim 1 for the time being, however, it can be seen that claims 2, 3, and 4 are otherwise directly infringed upon by the Telemetry System. Claim 2 is infringed upon because the Telemetry system does use both RS232 and CAN to interface to the other devices in the vehicle communications system. Claim 3 is infringed upon because the Telemetry system also interfaces to a GPS. Claim 4 is infringed upon because the Telemetry System supports a diagnostic mode in which the chase vehicle can access and change registers through the Telemetry System. However, taking Claim 1 into account shows that all four of these claims will not be infringed upon. Most of the aspects within Claim #1 are an accurate description of the Telemetry System. However, the key portion which states, “an adaptive application control separate from the data networking applications which communicates with the data networking applications through a uniform data format that is independent of the interfaces and the individual devices,” [5] seems to be the critical difference between the claim and the Telemetry System. The Telemetry System does have an adaptive control in the sense that for different applications different devices and functions are utilized, but this adaptive control is not separate from the data networking applications at all. According to Claim #1, “separate,” in this case refers to an adaptive control that communicates to the actual data applications through a uniform data format independent of the other interfaces. Instead, the control and networking applications within the Telemetry system are integrated within the embedded microcontroller software. The microcontroller is capable of receiving requests from the chase vehicle wirelessly through the wireless packet modem directly choosing the correct device to communicate to without the use of a discrete adaptive application control. Thus, claim #1 doesn’t hold, which relinquishes the Telemetry System from any possibility of infringement with patent #6,023,232.

US Patent #6,941,194 has many claims that seem to have aspects in common with the Telemetry System. However, similar to the previous patent in question, there is a critical difference in its description within its first claim, which will relinquish the Telemetry System from infringing upon the rest of the claims. From claim #1, statement “a plurality of operator consoles (9) which are connected to the processor unit (1) and have user interfaces for accessing the applications (9) and for data playback, and a central system controller (17) having a priority management system (19) which allocates to the individual operator consoles (9) access rights with different degrees of priority to the applications (15),” [6] is of concern. The first italicized portion states that there’s a plurality of operator consoles. There is exactly one driver interface, which can be interpreted as an operator console in that it can act to request parameters from the other devices in the system such as speed, battery life, etc. However, assuming that the word “plurality” does not exclude the use of a single operator console, the second italicized portion states that the central system controller can provide access rights with different degrees of priority to the applications. Since the Driver Interface is the only operator console connected to the Telemetry system, the Driver Interface should be the only operator console with access to the applications. Therefore, there is no priority structure associated with the access of applications by individual operator consoles. US Patent #6,941,194 is therefore a patent that cannot be infringed upon by the Telemetry System.

US Patent #6,526,460 is a good description of some of the methods of the Telemetry System. The italicized statement, “each of the plurality of equipment units being connected to the common vehicle data bus via said associated one of said hardware interfaces;……. wherein the functions are executed within any desired one of said equipment units” [7]. The fact that the Driver Interface System and Maximum Power Point Trackers are connected to a common CAN bus cannot be denied. However, the rest of the equipment including the GPS, Motor Controller, Battery Protection System, and Wireless Packet Modem are not connected to a common vehicle data bus. However, this can be argued in the other direction by claiming that since a common bus does exist for a plurality of equipment, then this statement holds true. The second portion of the italicized statement is also debatable. The Telemetry System does not utilize any of the devices to perform any major functions, but it does poll data from those devices. The act of polling requires the polled devices to perform the “function” of accepting the request and sending out the requested data back to the Telemetry System. Whether this is considered function is debatable. In reality, US Patent #6,941,194 does have the potential of being infringed upon under the doctrine of equivalents [9].

4.4 Action Recommended

The above analysis shows that the first two queried patents can be excluded, but the third patent has the potential of being infringed upon. There is a clear solution that can be implemented to prevent all possibility of infringement in this case. Since the “common bus” is a feature of US Patent #6,941,194 claim #1, it is possible just to move every module on the CAN bus to an independent RS232 line. The main drawback of this change is that future expandability on RS232 would be very expensive compared to expandability on the CANbus. If the Purdue Solar Racing team were to add additional modules, an RS232 implementation would require a redesign of the Telemetry Board to expand RS232 ports. Also, instead of the Driver interface being able to communicate directly with the Maximum Power Point Trackers, it would have to go through the Telemetry System to communicate with it. However, this solution does not take away from any of the features of the telemetry system, and could actually be implemented if need be.

4.5 Summary

The three patents that were found all have claims with aspects in common with the Telemetry System. However, it is the differences that are most important when analyzing with the purpose of detecting potential infringement. The patents [5] & [6] were determined to be free of infringement by the Telemetry System. The infringement liability in patent [7] is debatable and needs to be further analyzed by an intellectual property lawyer in order to determine if infringement is likely to exist. If the potential for infringement is real, then the Telemetry System, Driver Interface, and Maximum Power Point Trackers need to be redesigned to use RS232 transceivers. However, taking into account the non-profit nature of the uses of the Telemetry System, attention must be put into determining the likelihood of a lawsuit if an infringement actually did exist. It may not be logical to increase the cost of the system and decrease its later expandability if there is little possibility of being sued realistically.

5.0 Reliability and Safety Analysis

5.1 Introduction

Reliability analysis is a critical part of designing a robust, and safe electronic system. The analysis serves as an early warning for designers, alerting them about potential risks and opportunities for improvement before the design reaches the testing stage. This early warning is crucial, because design changes during later stages of the product life are much more costly than design changes early in the product life. Reliability analysis is especially important now, with lead-free parts adding additional failure modes to electronic devices. These failure modes include tin whiskers, which can form shorts between consecutive pins, weaker solder joints, and increased chip failures due to higher temperature solder profiles. These failure modes increase the necessity to design for reliability up front, since there are even more obstacles to overcome for a robust design.

5.2 Reliability Analysis

Ideally, a reliability analysis would be performed on every component in the schematic. However, the failure rate contributions from many of the components will be insignificant compared to the more complex devices that operate at higher temperatures. Therefore, our analysis will be limited to four key components:

1. PIC 18F4680 – the microcontroller.

2. SC16IS752 – the SPI to dual UART converter.

3. MAX1684 – the switching regulator, providing 5v

4. LT1121 – the linear regulator, providing 3.3v

The reliability for each of these four components was determined using the following three formulas:

λp = (C1πT + C2πE) πQπL (1)

TJ = TC + θJC*P (2)

MTTF = 1 / λp [10] (3)

Equation 1 determines the part failure rate, or the number of failures per 106 hours. To calculate Equation 1, the junction temperature is required, which can be calculated from Equation 2. Finally, Equation 3 is used to determine the Mean Time To Failure. A summary of the symbols used in these equations appears below.

λp = Part Failure Rate (failures per 106 Hours)

C1 = Die Complexity Failure Rate

πT = Temperature Factor

C2 = Package Failure Rate

πE = Environment Factor

πQ = Quality Factor

πL = Learning Factor

TJ = Junction Temperature (ºC)

TC = Case Temperature (ºC)

θJC = Junction-to-Case Thermal Resistance (ºC/W)

P = Maximum Power Dissipation (W)

MTTF = Mean Time To Failure

MTBF = Mean Time Between Failures [10]

5.2.1 PIC 18F4680 Microcontroller Reliability

|Parameter |Value |Rationale |

|TC |50 |Ground, Mobile classification [10] |

|θJC |28 |Used the largest “Dual-In-Line” thermal resistance estimate [10] |

|P |1.0 |Maximum power dissipation rating [1] |

|C1 |0.14 |8-bit MOS microcontroller [10] |

|πT |0.64 |Rounded up the calculated TJ to 80 ºC [10] |

|C2 |0.024 |DIP with glass seal with 40 pins [10] |

|πE |4 |Ground, Mobile classification [10] |

|πQ |10 |Commercial device [10] |

|πL |1 |2+ years in production [10] |

Table 5.2.1.1 – Parameter Selection and Rationale for PIC 18F4680

|Parameter |Equation |Result |

|TJ |TC + θJC*P |78 ºC |

|λp |(C1πT + C2πE) πQπL |1.86 failures per 106 hours |

|MTBF |1 / λp |538,793 hours, or |

| | |61.5 years |

Table 5.2.1.2 – Reliability Calculation Results for PIC 18F4680

The PIC 18F4680 was analyzed because it is the most critical component in the system. It is also the component which is the most complex, and dissipates the most power. The microcontroller drives all of the functionality of the telemetry system, so a single point failure here could render the entire system unusable. For this reason, the microcontroller was designed to fit into a DIP socket, so it could be easily replaced after a failure. Because the microcontroller is user replicable, the MTBF is calculated instead of the MTTF.

The PIC 18F4680 is a 40 pin, 8-bit MOS microcontroller in a DIP package. It is a commercial product, which has been in production for over two years. Since the telemetry system is designed to be used in a solar car application, the environment classification of “Ground, Mobile,” was chosen. The ambient temperature, TC, in this classification according to [10] is 50ºC, which matches the approximate ambient temperature of the Purdue solar car, 45ºC. The power parameter in the junction temperature calculation was set to be the maximum rated power dissipation of the device. Using the parameters from Table 5.2.1.1, the part reliability was determined to be 1.86 failures per 106 hours, giving a MTBF of over 61 years.

5.2.2 SC16IS752 SPI to Dual UART Reliability

|Parameter |Value |Rationale |

|TC |50 |Ground, Mobile classification [10] |

|θJC |22 |Used the largest “Flat Package” thermal resistance estimate [10] |

|P |0.3 |Maximum power dissipation rating [2] |

|C1 |0.14 |Modeled as an 8-bit MOS microcontroller [10] |

|πT |0.42 |Rounded up the calculated TJ to 60 ºC [10] |

|C2 |0.013 |Non-hermetic SMT with 28 pins [10] |

|πE |4 |Ground, Mobile classification [10] |

|πQ |10 |Commercial device [10] |

|πL |1.8 |Approximately 0.5 years in production [10] |

Table 5.2.2.1 – Parameter Selection and Rationale for SC16IS752

|Parameter |Equation |Result |

|TJ |TC + θJC*P |56.6 ºC |

|λp |(C1πT + C2πE) πQπL |1.99 failures per 106 hours |

|MTTF |1 / λp |501,403 hours, or |

| | |57.2 years |

Table 5.2.2.1 – Reliability Calculation Results for SC16IS752

The SC16IS752 was analyzed because it also is a relatively complex device, which drives a majority of the functionality of the telemetry system. A pair of these chips is utilized in the telemetry system design to add three additional UARTs to the system. These UARTs are used to communicate with the Battery Protection System, the Motor Controller, and the GPS Module. These devices constitute the majority of the devices from which the telemetry system collects data. These chips are 28-pin surface mount devices with a maximum power dissipation of 0.3 watts. They were modeled as 8-bit MOS microcontrollers, since they have a selectable I2C or SPI interface, two UART modules, internal registers, and GPIO pins. These devices have only been in production for a short time of around 0.5 years, based on the date of the initial revision of the datasheet. Therefore, the learning factor is 1.8. Using the parameters from Table 5.2.2.1, the part reliability was determined to be 1.99 failures per 106 hours, giving a MTTF of over 57 years. This failure rate will improve as the length of time it has been in production increases. Once it finally reaches two years of production, the MTTF will improve to almost 103 years.

5.2.3 MAX1684 Switching Regulator Reliability

|Parameter |Value |Rationale |

|TC |50 |Ground, Mobile classification [10] |

|θJC |22 |Used the largest “Flat Pack” thermal resistance estimate [10] |

|P |0.667 |Maximum power dissipation rating [11] |

|C1 |0.02 |Assumed 101 to 300 transistor linear MOS [10] |

|πT |2 |Rounded up the calculated TJ to 65 ºC [10] |

|C2 |0.0072 |Non-hermetic SMT with 16 pins [10] |

|πE |4 |Ground, Mobile classification [10] |

|πQ |10 |Commercial device [10] |

|πL |1 |2+ years in production [10] |

Table 5.2.3.1 – Parameter Selection and Rationale for MAX1684

|Parameter |Equation |Result |

|TJ |TC + θJC*P |64.7 ºC |

|λp |(C1πT + C2πE) πQπL |0.688 failures per 106 hours |

|MTTF |1 / λp |1,453,488 hours, or |

| | |165.8 years |

Table 5.2.3.2 – Reliability Calculation Results for MAX1684

The MAX1684 was analyzed because it is the main voltage regulator in the telemetry system. It converts the 12v input voltage supply to a 5v supply, which drives every component in the system except for the SC16IS752 SPI to dual UART chips. Since a single point failure of this component will render the entire system unusable, and since the device is not user serviceable, it is important for this component to have a high MTTF. The device itself is a 16-pin surface mount chip with a maximum power dissipation of 0.667 watts. It was assumed to be a 101 to 300 transistor linear MOS device. It is a commercial device that has been in production for over two years. Using the parameters from Table 5.2.3.1, the part reliability was determined to be 0.688 failures per 106 hours, giving a MTTF of over 165 years. The MTTF could further be increased by adding an inexpensive heat sink to the system to reduce the junction temperature.

5.2.4 LT1121 Linear Regulator Reliability

The LT1121 reliability analysis uses one additional equation, and a few additional parameters. The equation for power dissipated by the LT1121 from [12] was used to provide a more accurate reliability prediction. The equation and parameter descriptions appear below:

P = IOmax(VImax – Vout) + (Ignd * VImax) (4)

IOmax = Maximum Output Current (A)

VImax = Maximum Input Voltage (V)

Vout = Output Voltage (V)

Ignd = Ground Pin Current (A) [12]

|Parameter |Value |Rationale |

|IOmax |0.020 |Sum of the maximum currents of both SC16IS752 chips [2] |

|VImax |5.0 |5 volt input from the MAX1684 chip |

|Vout |3.3 |3.3 volt output from the LT1121 chip |

|Ignd |0.001 |Ground pin current with 20mA load [12] |

|TC |50 |Ground, Mobile classification [10] |

|θJC |28 |Used the largest “Dual-In-Line” thermal resistance estimate [10] |

|C1 |0.02 |Assumed 101 to 300 transistor linear MOS [10] |

|πT |1.0 |Rounded up the calculated TJ to 55 ºC [10] |

|C2 |0.021 |DIP with glass seal with 8 pins [10] |

|πE |4 |Ground, Mobile classification [10] |

|πQ |10 |Commercial device [10] |

|πL |1 |2+ years in production [10] |

Table 5.2.4.1 – Parameter Selection and Rationale for LT1121

|Parameter |Equation |Result |

|P |IOmax(VImax – Vout) + (Ignd * VImax) |0.039 W |

|TJ |TC + θJC*P |51.0 ºC |

|λp |(C1πT + C2πE) πQπL |0.284 failures per 106 hours |

|MTTF |1 / λp |3,521,126 hours |

| | |401.6 years |

Table 5.2.4.2 – Reliability Calculation Results for LT1121

The LT1121 was analyzed because it supplies the regulated 3.3v to the SC16IS752 SPI to dual UART chips, which provide a majority of the functionality of the telemetry system. The device is an 8-pin DIP, dissipating a mere 0.039 watts. It was assumed to be a 101 to 300 transistor linear MOS device. It is a commercial device that has been in production for over two years. Using the parameters from Table 2.4.1, the part reliability was determined to be 0.284 failures per 106 hours, giving a MTTF of over 401 years.

5.3 Failure Mode, Effects, and Criticality Analysis (FMECA)

The schematic was divided up into functional blocks, and each functional block was analyzed for possible failure modes and causes. These functional blocks are summarized in Table 5.3.0.1. Each failure mode was then analyzed for its effects on the functionality of the system, and on the end users. Finally a criticality level was assigned based on the scheme in Table 5.3.0.2.

|Block Letter |Block Description |Figure Location |

|A |5v switching regulator circuit |Figure A.1 |

|B |3.3v linear regulator circuit |Figure A.1 |

|C |RS-232 transceiver circuit |Figure A.2 |

|D |SPI-to-UART conversion circuit |Figure A.2 |

|E |Analog circuits |Figure A.3 |

|F |Microcontroller circuit |Figure A.4 |

|G |CAN transceiver circuit |Figure A.4 |

Table 5.3.0.1 – Schematic Functional Block Summary

|Criticality |Probability |Effects |

|High |λ < 10-9 |Possible fire hazard, electrocution, or other harm to user |

|Low |λ < 10-6 |Partial or complete reduction of system functionality |

Table 5.3.0.2 – Criticality Level Definitions

The FMECA Worksheet attached in Appendix B has four high criticality failure modes, all relating to the power supply circuits. The risk associated with these failures can be mitigated by modifying the design to include a fuse, or some other current limiting device, like a PTC. If the current can be limited to a safe value to eliminate the possibility of fire, then these four high criticality failure modes can be reduced to low criticality. The tradeoff for these current limiting solutions is the possibility of nuisance trips of the fuse, which can completely disable the telemetry system even though a dangerous situation would not have occurred. In this case however, the positives outweigh the negatives.

5.4 Summary

The reliability and failure mode analysis has shown that the component failure rates from Section 2, which can lead to high criticality failure modes, A1, A4, B1, and B3, do not meet the necessary λ < 10-9 probability threshold for high criticality failures. It has been determined, however, that the safety risks associated with these high criticality failure modes can be abated by modifying the design to include a current limiting device, like a fuse. Therefore, it is recommended to include this simple change before any additional boards are assembled.

6.0 Ethical and Environmental Impact Analysis

6.1 Introduction

As with anything in engineering, this project carries certain ethical and environmental impacts which will be addressed in the following sections. Specifically, from an ethical standpoint, the main concerns are the safety of the driver and others on the road during a race, as well as the durability of the design because of the nature of the environment it operates within. Along with the ethical considerations we face, environmental concerns are mainly centered on the manufacturing, normal use, and disposal of the system which could produce hazardous byproducts. This report will not only focus on these concerns, but also consider how they will be addressed.

6.2 Ethical Impact Analysis

The engineering profession has a direct, visible impact on society. It is paramount that those practicing the profession are held to the highest standards of honesty and integrity in the products and services they provide. As a result, it is important that a product follows proper ethical guidelines such as making decisions which are consistent with the safety, health, and welfare of the public. Also, a company or organization should not sell or distribute a product which will not be durable enough to withstand the environment it operates within. [13], [14] All of these ethical challenges are addressed.

First, steps will need to be taken to ensure the safety of the driver of the car, as well as those on the road during the race. The primary concern is in the event the chase vehicle sends a command to modify the contents of the Motor Controller registers while the car is moving. This could cause unpredictable behavior in the motor operation, and could ultimately result in a crash. Precautions to avoid this scenario include establishing two modes of operation, race mode and diagnostic mode. Diagnostic mode will be the only time which these registers can be modified, and the car can only be in this mode while not in motion. Software checks have been put in place to ensure that a command to change the registers will not occur while in race mode. Also, the user’s manual will mention safe operating conditions for modifying registers in the Motor Controller.

Second, in addition to the primary safety concern, the other safety considerations include the possible inability to communicate Battery Protection data to the driver interface and the possibility of electrical shock from an exposed board and wires. In the case where communication of Battery Protection data fails, the Battery Protection systems already has built in fail safe protocols to protect the batteries from exploding. Considerations have been made to include an external monitoring of Battery Protection data by the telemetry system, thus allowing the telemetry systems to shut down the battery pack. When dealing with the possibility of electrical shock, ensuring that all wires and the PCB are enclosed and covered to prevent accidental exposure will be of most importance. Warning labels will also be placed on the telemetry system case warning of possible shock if the case is opened or wires are exposed.

Third, it is important to make sure that the telemetry system is durable enough to withstand the environment which it will operate in. Since the telemetry system will be mounted inside the car during races, it will experience a lot of vibration. As a result of this vibration, components may be knocked loose. Since the microcontroller the telemetry system uses is a DIP package set in a socket, a zip tie can be wrapped around the microcontroller and attached to the board. This will ensure that the microcontroller will stay in the socket, even through adverse vibration. For mass production, it would be more advantageous to simply solder the microcontroller directly to the board. Wires connecting DB9 and MTE connectors will need to be fastened securely to the project casing to avoid them being disconnected. On top of these procedures, the casing which holds the telemetry system will need to be fastened to the solar car in a secure fashion to avoid the possibility of breaking loose during a race. All of these precautions will allow the telemetry system to have a longer lifespan and ultimately be a safer product.

Finally, it is important that all functionality of the telemetry system is tested both in operational conditions, as well as abnormal conditions. Tests need to include verification of proper communication between the telemetry system and the chase vehicle and all other devices. This testing will also occur during start-up using a self test that verifies functionality and communication. Testing will also be done using controlled software bugs to test the system’s functionality in adverse operating conditions. Once the board and system are mounted in the casing, vibration tests will be conducted to test how well the board and wires are fastened to the casing. After all of the testing and precautions are completed, the telemetry system will be fit to go to market while following all ethical guidelines.

6.3 Environmental Impact Analysis

There exists a growing concern for the environment in today’s society. People are taking steps to preserve and maintain the health of the environment and the creatures and people who live in it. Because of this, there is a greater push towards Green engineering. Green engineering is the process of design, commercialization, and use of products and processes that minimize pollution at the source, as well as minimize risk to human health and the environment. As engineers, we need to use life cycle thinking in all activities, ensure that all energy inputs and outputs are as inherently safe as possible, and strive to prevent waste. [15] There are three areas in a product’s lifecycle which need to attain these goals. Environmental analysis needs to be done on the manufacture, normal use, and disposal of the telemetry system.

The main environmental impact from the telemetry system during the manufacturing process would come from the fabrication of the printed circuit board. Negative impacts to the environment could occur during fabrication of the PCB because of the hazardous byproducts created in the process. These byproducts include air pollutants such as acid fumes, ammonia fumes, and CFCs, as well as water stream pollutants such as acid and alkaline solutions, electroless copper baths, and etchants. [16] If not properly handled by those responsible for fabrication of the PCB, these pollutants could find their way into the atmosphere and water supply. The EPA has outlined steps to help prevent these pollutants from reaching the environment. These steps include eliminating chelated baths to improve metal wastewater treatments and reuse of spent alkali and acid to neutralize the other’s waste streams before introducing them to water waste systems. [17]

There will be minimal to no adverse affects to the environment while the telemetry system is in normal use. The system’s printed circuit board will be enclosed and out of contact with the environment, as well as the fact that there are no harmful byproducts being produced or emitted. The system also uses no rechargeable batteries. Although the system interfaces to the battery system on the solar car, these batteries are not a part of the telemetry system itself.

The telemetry system will need to be disposed of and recycled properly due to the negative impact that the printed circuit board could have on the environment. One of the main concerns of disposal of the PCB is the presence of lead based solder. Due to the lead based solder and other materials considered hazardous, PCBs need to be segregated from other non-hazardous solid materials and handled separately. Several companies offer services for recycling the board by systematically removing raw material from the board matrix. Some of the recovered materials that can be recycled from the board include silver, gold, lead, and copper. As an added benefit, recycling these raw materials recovers the value of those materials for reuse in the fabrication of boards. [18]

7.0 Packaging Design Considerations

7.1 Introduction

Since the Telemetry System communicates with so many modules, the packaging for the project needs to accommodate four DB9 RS-232 connectors, and four 6-pin MTE CANbus connectors. The Telemetry System is a custom module for the solar car, so commercial issues such as attractiveness, and cost do not apply. Size is not an important issue, since the solar car has plenty of room inside. Weight, however, is the most important issue, due to the nature of solar racing.

7.2 Commercial Product Packaging

Our team was unable to find off-the-shelf Telemetry Systems designs for solar car applications, since the market for commercial solar car racing is miniscule, if it exists at all. Therefore, we will analyze the product packaging of the current Purdue Solar Racing Telemetry System, and a commercial Telemetry System designed for RC racing.

7.2.1 Current Purdue Solar Racing Telemetry System Packaging Analysis

The current Solar Racing Telemetry System is housed in a lightweight ABS plastic molded project box. The box measures 6” x 4”, with two DB9 connectors for the Battery Protection System and Packet Modem, and one connector for the Maximum Power Point Trackers. The enclosure is mounted to the solar car with double sided tape. Although double sided tape is not the strongest mounting method, it has been a successful mounting method for the Telemetry System so far.

[pic]

Figure 2.1.1 – Current Purdue Solar Racing Telemetry System

This enclosure is nothing fancy, but it meets the needs of the Telemetry System packaging perfectly. It provides adequate protection and stability to the module, and it is lightweight enough for a solar racing application. Since our project is a replacement for this old Telemetry System, and since this enclosure was successful, we plan to use a similar enclosure.

Our enclosure will be slightly larger, to accommodate the four DB9 connectors, and four MTE connectors. We will use the same ABS plastic material for our enclosure. We researched other common materials for project boxes, such as aluminum, in an attempt to minimize the total weight of the packaging. While aluminum weighs more than plastic, it can be made much thinner than plastic, possibly making the overall weight less. Plastic project boxes are commonly available in 0.100” and 0.070” thicknesses, while aluminum project boxes are commonly available in 0.040” thickness. The datasheets for these enclosures generally did not list a weight, but we found that aluminum has a specific gravity of 2.64 [19], and plastic is very close to 1.00. Since aluminum has over twice the specific gravity of plastic, and only a 57% reduction in thickness, ABS plastic is the best solution to minimize weight.

7.2.2 Spektrum Nitro Telemetry System Packaging Analysis

The Spektrum Nitro Telemetry System [20] is a commercial off-the-shelf Telemetry System intended for RC car racing. The system consists of an on-car module with connections for an infrared RPM sensor, a lap counter, a temperature sensor, and a battery voltage monitor. The on-car module uses a RF link to communicate with the handheld module. The handheld module has a display which shows the current readings from all the sensors.

[pic]

Figure 7.2.2.1 – Spektrum Nitro Telemetry System

The Spektrum Nitro Telemetry System’s on-car package is incredibly small. The entire on-car module weighs an impressive 8 grams. The mounting hardware is sturdy and lightweight, and the sensors are modular, allowing the user to place them anywhere in the car. The handheld receiver clearly displays all of the readings at once, and it even features a metric for the quality of the RF link.

Although the packaging is attractive and small, the feature set is also small. The product is designed to allow the user to test the results of tweaks such as gearing, and protect the car from low battery levels and high temperatures. However, it is difficult for a user to measure the results of tweaks without immediate feedback, like from an accelerometer. The user must use lap times as his measurement. Without logging features, it becomes difficult to really analyze the data from the Telemetry System. Additionally, this product is incredibly expensive at $189 MSRP for such a simple device.

7.3 Project Packaging Specifications

Our project packaging is very similar to the project packaging of the old Solar Car Telemetry System. The old Telemetry System is packaged in a 4”x6” plastic project box, which provides adequate protection while minimizing weight. Since the old packaging has performed adequately, and has met all it’s requirements, so there is no need for any big changes. Our packaging will use a slightly larger project box, 5”x7”, to accommodate for all of the extra connectors. A CAD drawing of our packaging can be found in Appendix A. The specifications of the project box can be found in Appendix B.

The connectors will be mounted to the project box, and connect to headers on the PCB via wires. This method ensures that there will be no issues with lining up PCB mounted connectors to holes in the packaging. The PCB will be mounted to the box with standoffs. All of the materials required to complete the packaging are listed below, in Table 7.3.0.1.

|Item |Estimated Weight (g) |Estimated Cost |

|Plastic Project Box |200 |$7.00 |

|PCB (populated) |100 |$180.00 |

|Standoffs |30 |$5.00 |

|Double Sided Tape |15 |$1.00 |

|DB9 Connectors (4) |40 |$8.00 |

|MTE Connectors (4) |20 |$3.00 |

| | | |

|Total |405 |$84.00 |

Table 7.3.0.1 – Packaging Materials List

For construction, we will only need to cut holes for the connectors, mount the connectors, and wire the connectors to headers. Therefore, our tooling requirements are: A screwdriver, a drill, a rotary hand tool (Dremel) or saw, and a soldering iron.

7.4 PCB Footprint Layout

The major components listed in the Design Constraint Analysis are the microcontroller (PIC 18F4680), the SPI to UART chips (SC16IS752), the accelerometers (MMA 2260D and MMA 1260D), and the DC to DC converter (MAX 1684). Most of the components are available only in surface mount packages, so those choices were trivial. The microcontroller, however, is available in both surface mount, and DIP packages. Since size is not a constraint, and since so much of our size is determined by the DB9 connectors, we decided that a DIP package is the most appropriate for the microcontroller. By using a DIP socket, replacing a broken microcontroller will be simple. The microcontroller can be easily replaced if it fails during debugging, or if for some reason it fails during a solar car race.

After laying out the footprint size, as seen in Appendix C, we estimate the final PCB size to be approximately 60mm by 120mm. This size should leave enough room for all of the passive components and headers.

7.5 Summary

Our project will be packaged similarly to the old Solar Car Telemetry system, in a plastic project box. This package minimizes the weight, which is the most important constraint of solar racing, while providing adequate protection to the electronics. Note that since this project is not commercial, attractiveness is not important. Since there is plenty of space available, we are using a DIP package for our microcontroller, which will allow us to easily replace it during debugging, and allow the solar racing team to easily replace it if a failure occurs during a race. Therefore, this packaging is well suited for a solar racing application.

8.0 Schematic Design Considerations

8.1 Theory of Operation

8.1.1 Power:

Our power circuit uses a MAX1684[12] and an LT1121[11]. 12v is available throughout the entire solar car so this is what we must use as the basis for our power needs. This 12v power is received through the MTE CANbus port which will be discussed later. The 1684 provides a step down from 12v to 5v DC in order to power the majority of our components[12]. The LT1121 provides a step down from 5v to 3.3v which is necessary for the SPI to UART chips. These chips have 5 volt tolerant inputs for serial connections but require a power input of 3.3v. Each of the solar teams are using the same 1684 chip for power conversion. These chips are shown to be over 90% efficient while in our operating ranges. Hopefully this will provide the most stable operation over the CANbus since this how each part will communicate with each other. The operating frequency of the microcontroller has been decided to be 10MHz. Each of the solar racing teams are using the exact same crystal to ensure that all the components of the car are running at the same speed. This may help alleviate problems with future designs by ensuring a standard clock rate and standard component usage.

8.1.2 Microcontroller:

The Microcontroller, a PIC4680[1], interfaces to most of our hardware. A DIP package was chosen for our microcontroller in order to provide an emergency solution. The telemetry system will be operating in a fairly hot environment as well as subject to vibrations. By using a DIP package this will allow the team to quickly interchange a replacement microcontroller if something were to happen to the original. Through ATD channels the microcontroller receives data from the accelerometers and the temperature sensor which all output in voltage levels. We are using three accelerometer chips, one for each axis, provided by Freescale. This solution was chosen over the single board solution because each of the accelerometers could be sampled while the board could not.

The controller has built in CAN support through which it communicates to a CAN transceiver chip, MCP2551[21]. The outputs of the CAN transceiver are then taken to headers to be connected to an external MTE port on which all of the teams have decided to be the standard connection for the CANbus. Through the MTE port we receive our 12v input from the CANbus which powers the entire board. The port itself has been chosen to be a lock-in type connector in order to ensure that the connector remains plugged in during strong vibrations which may occur during operation. The built in RS232 support on the controller will be used to communicate with the external packet modem interface or for debugging purposes. This will broadcast the available information at a regularly scheduled interval to the ‘chase car’ which is following the solar car.

The SPI system on the microcontroller is used to communicate with the SPI to UART chips. Using two general purpose I/O pins as chip selects the microcontroller will choose which chip to turn on for communication. These SPI chips also provide extra general purpose I/O pins which we will use for debugging or expansion purposes[2]. These chips are discussed further below.

The PIC18F1684 was chosen over other PIC microcontrollers because we are unsure of the size that our program will take up and this microcontroller offers one of the greatest amounts of available memory in this PIC family which we are limited to. This microcontroller also affords the solar team many possibilities for expansion by leaving many open I/O pins and access to each of the microcontroller’s modules.

8.1.3 SPI to UART Communication

The SPI system on the controller is used to communicate with the SPI to UART chips[2]. Using two general purpose I/O pins as chip selects for each chip, these chips can each talk to two serial devices. This will facilitate communication with the motor controller, battery pack, and GPS unit. The SPI chips communicate externally using the MAX238 level translator [22] which is a four driver version of the MAX232. The outputs of the MAX238 have then been taken to external connectors which will be connected to ports to which cables can be attached from the outside of the packaging. Each of these chips also provides a great number general purpose I/O pins. We have taken these I/O pins from one chip to headers since we already have a great number of pins left on the microcontroller we do not believe that we would need the general purpose I/O from both SPI chips. The interrupt lines from these chips have also been taken to headers so that the pin they connect to on the microcontroller can be used interchangeably in case future application specific pins on the PIC controller are needed and the interrupt pin needs to be changed. A possible alternative we had looked at was using a quad-UART chip which connected to a port on the microcontroller to interface to four UART lines. This would make designing our project a lot easier, but we can not afford to use that many I/O pins since many of the pins on the port are also used for A/D and other operations that we need access to.

8.1.4 Accelerometers

We have chosen to use the MMA2260D [23] and MMA1260D [24] as our accelerometers. Each of these chips provides data on a single axis. The 2260D is an X-axis chip of which we are using two and mounting one side-ways. The 1260D is a Z-axis chip. The output of each of these chips is in voltage levels and has been taken to ATD pins on the microcontroller. This solution was chosen over the single-chip solution on a breakout board because these chips are able to be sampled and the solar team felt it was not worth the extra cost to order a separate board.

8.1.5 GPS

The GPS unit that was chosen was the GPS18 from Garmin[25]. This communicates over RS232 to the microcontroller. This model was chosen over other solutions because it comes with a 12v car adapter. Since a 12v supply is available all over the car this seemed like a wise choice as most other models relied on a 5v input. This model also specifically stated that it works with RS232 levels and can be interfaced with a laptop. Many other units specify that they only work with “RS232 TTL levels” which is a misnomer. This unit appeared to be the most compatible solution with the RS232 system we have available to us. Using the Garmin unit ensures that we will be able to gather GPS data while using one of the other unit’s we may find out later that either our schematic or PCB are laid out wrong for proper communication with whatever data transfer scheme it uses. Finally the Purdue solar team already has experience using the USB version of this device so they are already familiar with how it works and what to expect from it.

An alternative to the Garmin unit would have been an onboard GPS module and using antennae, extend its range outside of the car. The solar team decided to go with the Garmin because using a module would make it very difficult to change out the GPS unit if it was desired later.

8.2 Summary

This document has described the basic operation of our circuit as well as our part consideration for our major components. We have discussed how the telemetry system will communicate with the various off-board devices such as the GPS unit and the motor controller. This data is then sent by request over the CANbus to other devices on the vehicle such as a display system. This data is also sent over packet modem to the chase car for data logging and analysis. The telemetry system acts as an overall hub for data collection and communication across the entire vehicle and is a valued addition to the solar car’s inner workings.

9.0 PCB Layout Design Considerations

9.1 Introduction

Since the Telemetry System will be housed inside the solar car, it was determined that any PCB board that fits into a 4x6 inch rectangular box can be tolerated. Within reason, cost and attractiveness do not apply because the Purdue Solar Racing Team is the only customer of this board. The most important considerations include low EMI interference, ample component spacing, intuitive placement for easy troubleshooting, and good trace width and copper trace spacings. Weight was another consideration due to the nature of the solar racing car, but little would be added by the Telemetry System so it wasn’t considered a main concern during the design. The board was designed to be as compact as possible without jeopardizing usage simplicity in order to reduce weight.

9.2 PCB Layout Design Considerations

The general layout for the Telemetry System board was designed by first grouping the subsystem circuits into their functional areas: digital, analog, and power. This serves the primary purpose of creating a board with an easier and more intuitive method of troubleshooting in the later stages, since the schematic is also grouped into areas of functionality. This grouping also serves like components together (ie. digital with digital, analog with analog, power with power). Consequently, the circuit was laid out so that the digital components were mainly at the bottom half of the board, the power circuit in the upper right-hand corner, and the analog components in the upper left-hand corner of the board (assuming the view of the board is horizontal with the microcontroller on the left-hand side).

Special considerations were taken into account when routing the board. Higher frequency lines such as the SPI feeding into the SPI-UART chip were routed through direct paths that avoided crystals to prevent noise from disrupting the SPI signals. The bottom-side of the board was created to be a ground plane to cut down on ground routes and to reduce EMI noise, and image rails were used so that higher frequency signal paths were ensured to have a short, non-looping ground return path. Image rails are routes placed on the opposite side of the ground plane in order to connect two sections of ground planes separated by a non-ground signal ground. This ensures a short ground return path that doesn’t loop around the non-ground signal. The term “image-rail” was defined in a proprietary GE documentation and therefore is not referenced in this report.

9.2.1 Power Distribution

After the parts were placed into the correct subsections, the next step was to take distribution of power into consideration. The only source of power on the Telemetry board is the 12v and ground lines feeding in through the 6-pin CAN bus connector. Consequently, this connector was placed in the upper right-hand subsection of the board along with the rest of the power circuit. The power circuit is confined in the upper right-hand side to prevent the higher current flowing throughout it from interfering with the rest of the circuit. A ground and 12v line feeds in directly through the 6-pin connector, and the power circuit’s output of 3v and 5v feeds in to the rest of the circuit through the use of a thicker 40mil 5v power rail. The bottom-side of the board was made to be a ground plane so that a short return path would always be possible. This would prevent looping currents which create unnecessary EMI interference [26].

9.2.2 Placement Themes

With the general placement of the parts and the power rails and ground plane complete, the next step was to set a consistent placement theme. One priority while choosing the orientation of each component was to simplify routing. This was done by rotating each component until the simplest rats nest was obtained. Another consideration was the proximity of the bypass capacitors and crystals(if applicable) for each IC. The recommended configuration is for the crystal to lie on the side of the IC that it will be connected to along with the two capacitors sandwiched between the crystal and its corresponding IC. This was done for both of the SPI-UART chips. Likewise, the microcontroller’s bypass capacitors and crystal oscillator were placed underneath the microcontroller to ensure proximity and to make way for the 9-pin connectors on the top side of the board to route easily to the microcontroller. Finally, many of the headers were given a location at or near the bottom edge of the board when possible. However, a few of the smaller 3-pin UART headers and a 2-pin interrupt header were placed in the middle of the board to allow for easier routing.

9.2.3 Power Section

Since there are three sections of the board: power, analog, and digital, individualized consideration of part placements had to be given to the components in each section. The power section takes a 12v and ground input from the 6-pin CAN connector and outputs 5v and 3.3v to the rest of the board. This 6-pin CAN connector was placed at the top edge of the board so that it will be easier to connect to the casing of the box that will be housing the board. The final purpose of the power circuit is to convert the 5v output to a 3.3v output to feed into the SPI-UART chips. After the 5v is fed through the linear regulator, the 3.3v output is decoupled through a 1uF capacitor (C26). This capacitor was placed next to the linear regular as specified by [27].

9.2.4 Analog Section

The analog section consists of the three accelerometers for the x, y, and z axis (3 dimensions of the physical world) and a temperature sensor. The analog section was chosen to be the top left-hand corner of the board because of its placement above the microcontroller and easier access to the analog pins. The location was chosen due to the importance of the separation of digital and analog signals. Analog signals that cross with digital signals can be easily corrupted [27]. Two of the accelerometers had to be oriented at 90 degree angles to each other so that the x and y axis could be sensed. The temperature sensor was positioned for a short routing path to the analog pin on the microcontroller. All of the analog components in this section were placed for the shortest direct route to their corresponding microcontroller pins

9.2.5 Digital Section

The digital portion of the board occupies the entire bottom half of the board. Given the placement of the power and analog portions of the board, the options were limited in regards to the positioning. The microcontroller, two SPI-UART chips, and the RS232 transceiver were spaced out and placed so that the higher frequency signals running from the microcontroller have fewer obstacles to avoid. The CAN transceiver feeds off the CAN_H and CAN_L line from the CAN connector in the power section of the board. Therefore, the CAN transceiver was placed closer to the power section so that the CAN bus signals would be close to the 6-pin connector in the power section. Image rails were added between the path from the microcontroller to the CAN transceiver in order to reduce the ground return path. This was done to prevent current from flowing through a longer path which might loop around and create EMI interference that generates noise and affects other signals in the circuit. According to the spec sheet, the microcontroller’s crystal oscillator and bypass capacitors should be placed very close to the microcontroller [1]. Therefore, they were placed underneath the microcontroller on the bottom side of the board.

9.2.6 Routing Considerations

The Telemetry System is not a high current device. The total current being drawn by the system was estimated to be under 500mA. Therefore, trace widths did not have to be too wide. 12 mil traces were used for the majority of the routes. The 3.3v and 5v power rails stemming from the power circuit are 40mils, since they carry slightly higher currents than the other routes. All via coppers were set to 20 mil widths to prevent clearance violations. Extensive effort was spent in editing traces so that nothing violates the 12 mil spacing rule as set by the ECE477 PCB Layout lecture [28]. There are currently 43 DRC errors remaining. All of the remaining errors are from pad spacings for the switch-mode regulator in the power section and the components placed underneath the microcontroller.

9.3 Summary

The final design of the Purdue Solar Racing Telemetry System Board was a logical and user-friendly layout. The single input header is the 6-pin connector located at the top edge of the board for easier access. The positions of the individual components were selected to simplify routing and at the same time model the schematic’s functional placements of the components. Noise and EMI issues were minimized through the placement of the 40 mil power rail and a ground plane on the bottom side of the board. All bypass capacitors were placed near their corresponding chips. Image rails were used to ensure a direct ground return path to minimize EMI interference.

10.0 Software Design Considerations

10.1 Introduction

The software for this project features a main polling loop which is responsible for acquiring data from the Motor Controller and Battery Protection System through SPI, as well as Maximum Power Point Tracker information through CAN. An interrupt service routine will be triggered every second to receive GPS data, as well as read both the accelerometers and temperature sensor. Requests from both CAN and the packet modem will also operate using interrupt service routines. The primary software considerations will be communication with the chase vehicle through the packet modem, constantly updating and accurate vehicle data, and translating data between devices.

10.2 Software Design Considerations

Memory Considerations:

For this project we are using the PIC18F4680 microcontroller, which has two main memory sections available on-chip. The PIC18F4680 has 64 KB of Flash and 3.25 KB of SRAM. [29]

1. 64 KB Program Flash – All of the compiled program code and static data will be located in this section. The majority of static data we will have in our software comes from a look-up table which will hold a structure for each piece of critical vehicle data. Each structure will consist of the vehicle data’s ID, update priority, command, and a pointer to it’s location in SRAM. With 97 pieces of vehicle data and a structure size of 10 bytes, the total size of this look-up table is estimated to be approximately 970 bytes. The size of the look-up table, along with other constants for the software, is estimated to be no larger than 2 KB. This allows for approximately 62 KB of space for compiled program code, which will be more than sufficient since finalized code takes up approximately 7 KB of space.

2. 3.25 KB (3328 bytes) Data SRAM – The stack and all of the temporary variables will be located in this section during program execution. Most of our temporary variables will come from the 97 variables to hold the vehicle data for updates and transmission. These 97 variables include 46 Battery Protection System variables, 20 Motor Controller variables, 5 Power Point Tracker variables times 8 PPTs, accelerometer data, temperature data, variables for text messages sent between the chase vehicle and driver interface, and variables for the send and receive buffers for CAN. This vehicle data, along with all other temporary variables, is estimated to be no larger than 350 bytes. In terms of the stack, the deepest that function calls and interrupts will be made is four deep. Available memory in SRAM should be more than sufficient.

The MPLab IDE available on Microchip’s website is being used for software development. MPLab handles memory mapping, and it was decided to be unnecessary to change from the default memory mapping because of the adequate amount of space present in both Flash and SRAM. [30]

External Interface Mapping:

The telemetry system will be interface to several external devices. The following are descriptions of what devices are connected to the microcontroller through (1) UART, (2) SPI, and (3) ADC.

(1) A packet modem for communications with the chase vehicle is connected to the UART serial communications with the microcontroller. The transfer pin of the UART communication is mapped to pin 6 of portC. The receive pin of the UART communication is mapped to pin 7 of portC. [29]

(2) Several devices are connected to the microcontroller through SPI. With a hardware implementation, the single SPI is capable of communicating with up to four UART connections. The devices using SPI to communicate with the microcontroller include the Motor Controller, Battery Protection System, and GPS. The transfer pin of SPI is mapped to pin 5 of portC. The receive pin of SPI is mapped to pin 4 of portC. [29]

(3) On-board sensors for acceleration data and temperature data are connected through the ADC. The ADC is mapped across various pins of portA, portB, and portE. The three accelerometers are mapped to ADC channels 0-2, which correspond to portA pins 0-2. The temperature sensor is mapped to ADC channel 5, which corresponds to portE pin 0. [29]

Integrated Peripheral Utilization:

The three integrated peripherals which required changes to the default configuration file provided with the MPLab IDE [31] were the (1) integrated ECAN module, (2) ADC, and (3) internal oscillator.

(1) The ECAN module on the microcontroller is being initialized to have a baud rate of 125 kbps for a clock frequency of 40 MHz.

(2) Changes to the default configuration file included setting the ADC to have channels 0-5 be analog input for the on-board sensors connected to channels 0-2 and 5. Since it was only possible to change a set number of channels in order starting from channel 0, channel 4 was set as analog input, even though it is not needed. The ADC interrupt was changed to be disabled, and the voltage reference was set to accept an external voltage reference.

(3) The default configuration file uses the microcontroller’s internal oscillator for clocking, but this was changed to be disabled. [31] The ability to use an external oscillator was enabled because the solar car teams will be using the same oscillator chip to avoid small discrepancies if everyone was using their microcontroller’s internal oscillator.

Overall Organization and Rationale:

The telemetry system utilizes a combination of a polling loop and interrupt service routines to accomplish all of its required tasks. The main routine of the software consists of an infinite loop which polls data from the Battery Protection System, Motor Controller, and Maximum Power Point Trackers. The function will poll data from the various devices, store it locally, and send it to the chase vehicle. In diagnostic mode, this is done explicitly by request from the chase vehicle. In race mode, this is done by priority system.

All other data acquisition and other functionality are interrupt-driven. First, GPS information is handled through an interrupt which occurs every second. The service routine associated with the GPS interrupt will not only receive and process GPS data, but will also read data from the accelerometers and temperature sensors. We are reading this data together because the Aerospace Engineers on the solar team need coordinated GPS and acceleration data. Second, CAN will have an interrupt service routine for handling requests for data from other devices on the CANbus. Finally, an interrupt for UART will allow the chase vehicle to make a request to change mode of operation via the packet modem.

Since all data acquisition from the Battery Protection System, Motor Controller, and Maximum Power Point Trackers is on a request basis, polling the devices in a loop was the best choice of implementation. GPS, on-board sensors, and chase car commands via packet modem are all available as output on those devices, not on a request basis. Therefore, the most appropriate way to handle acquisition of that data is through interrupts. A flowchart of the overall organization of the software is available in “Appendix A”.

10.3 Software Design Narrative

The following sections of the document highlight specific descriptions of the four main modules of code and their subroutines. Modules presented are the system start-up/initialization, race mode, diagnostic mode, and interrupt service routines. A code module hierarchy is presented in “Appendix B”. Currently, all written code can be found in the main.c file at:



System Start-Up/Initialization Module:

After the system is powered on or reset, the start-up code for setting up the stack and copying initialized data is called. [29] Upon completion of this task, the microcontroller will jump into the main function of our code. The initialization module is called first in the main program, and its job is to initialize all integrated peripherals. For initialization of all of our integrated peripherals aside from the ECAN, we are using supplied routines from header files provided with the MPLab IDE. [32] All of these routines simply require the appropriate arguments for configuration. Initialization of the ECAN will be done through a CAN initialization function which will be written collectively by the Solar Car teams. It will configure the ECAN module to have a baud rate of 125 kbps for a clock frequency of 40 MHz.

When these routines are complete, entry into the loop for main system operation will occur. The first thing done in this loop is to check a status flag and determine which mode of operation the system is currently in, race or diagnostic. Once this is determined, the appropriate module call will be made. Currently, the overall initialization routine has been written and tested, including the initialization of the ECAN.

Race Mode Module:

The primary responsibility of the race mode module is to run the main polling loop for acquiring vehicle data from the Motor Controller, Battery Protection System, and Maximum Power Point Trackers. Once data is received, it will be stored locally and sent to the chase vehicle via the packet modem. A counter will be kept for the purpose of a priority system which will decide which vehicle data is updated during that iteration of the polling loop. During an iteration of the polling loop, the lookup table holding a structure for each piece of data is scanned. The structure contains the data’s ID, update priority, command, and a pointer to the local variable for that piece of data in SRAM. If the specific piece of data is to be updated, the command for polling that data is sent to the appropriate device holding the information. Upon receiving a response, the variable in SRAM is updated. When completion of the look-up table scan is reached, the priority counter will be incremented, and an update of all vehicle data will be sent through the packet modem. The Watch Dog Timer will be kicked and the loop will start over.

Standard functions for communicating with the various devices will be used. There will be a read and write function for CANbus communication. For all other device communication the MPLab IDE provides us with some of the functions such as the following [2]:

1. ReadSPI() and getsSPI() in spi.h, which read a byte or string respectively

2. WriteSPI() and putsSPI() in spi.h which write a byte or string respectively

3. ReadUSART() and getsUSART() in usart.h, which read a byte or string respectively

4. WriteUSART() and putsUSART() in usart.h which write a byte or string respectively

Currently, the race mode routine had been written and tested. A protocol was established along with the other solar teams, and the CAN read/write functions are finished and tested.

Diagnostic Mode Module:

The primary responsibility of the diagnostic mode module is to allow members of the race team to have explicit access to the vehicle information, rather than to just have updates sent like in race mode. The ultimate goal is to give the team in the chase vehicle the ability to have direct communication to set/get registers on the car. The only data that can be modified are the registers of the Motor Controller, and all other data is read only. All of the same functions for communications that race mode uses will be used for diagnostic mode. Since it was not a part of any of the project success criteria, the diagnostic mode had been designed, but it has not been written.

Interrupt Service Routines:

The system will have interrupt service routines for (1) CAN and (2) Timer

1) CAN ISR – The CAN ISR will handle any requests or data being sent across the CANbus. It should get triggered whenever a device publishes something on the bus. In the current state of the car, the only devices which should be providing data over CAN are the Maximum Power Point Trackers, and the only device which should be sending requests for information is the driver interface. This ISR will require the use of the CAN read and write functions, and has been written and tested.

2) Timer ISR – The Timer ISR will set flags at different time intervals to be used in the main polling loop for acquiring data at specified times. For example, the BPS flag will be set every 1 ms and the GPS flag will be set every 7 ms. This ISR also has built in timeout functionality and recovery if a device is not responding. All of the code to be processed is done in the main loop based off of these flags.

11.0 Version 2 Changes

Now that the prototype for the project has been completed, there are several design changes that would be beneficial in creating a more polished product. The first design change would be to re-do the PCB layout and board. The pins on one side of the microcontroller are reversed, and because of this a device had to be constructed to swap those pins around. This needed to be done in order to insert the controller and use it in a functional manner. The pins on the temperature sensor were also reversed so that device had to be fly-wired in order to operate properly.

Along with these issues, pin usage with reset lines, IRQ’s, and chip selects were not properly designed during the schematic phase of creation and had to be fly-wired in order to operate some of our peripherals. If this device were to go into mass production a surface mount form factor would be preferable for reduction in size. The original microcontroller was chosen as a DIP package to allow the solar team to make emergency changes to the programming on the controller or in case of damaged during use.

Aside from these hardware changes, software could be greatly condensed and re-organized. Changing the software in this manner would help with the maintainability of the code as well as making changes and adding features to it. A feature of the software that was not implemented but planned for was a diagnostic mode that would allow the solar team to directly communicate with any attached device as if they had a direct terminal connection with that device. This would allow them to change settings on the various devices in the car without having to leave the chase vehicle as it could be done over the wireless packet modem.

12.0 Summary and Conclusions

The final Telemetry System that our team created was a success in terms of satisfying all of our Project Specific Success Criteria. The system was tested using both simulators and actually hooking it up to the devices that it is supposed to be hooked up to. Getting to this stage of completion was not without lessons, however. Beginning with the Component Selection and Constraint Analysis, we were able to rationalize exactly what types of functions were necessary to achieve our goals, and at the same time compare different options in order to choose the best components. For the schematic, we had to relearn how to create devices in Cadence and route them together to create our schematic. A very tough lesson that we learned was working with Layout Plus when designing our Layout. All of the team members became skillful in using Layout Plus after having to spend many hours creating footprints and routing the rats nest. Also, this project was important in bringing us a taste of the real-life industry aspects of engineering. The Patent Analysis homework assignment was a step out of the realm of academic EE and into the world of industrial EE in that it helped us realize the impact of the technology that our system was utilizing, and its real potential to infringe on existing patents. The Environmental and Safety analysis gave us another angle for viewing the project. It made us think about the lasting impact of the materials used in making the Telemetry System after its useful life. Finally, some of the most important lessons were related to programming the microcontroller. We had to review the concepts of a microcontroller's operations and utilize the knowledge we learned in ECE362 in order to program the Telemetry System to execute the correct operations. Although we didn’t assembly language as we did in ECE362, we still utilized the same types of concepts performing register settings, timer interrupts, ISR's, port pin interrupts, ATD sampling, and SPI port programming all by using C programming. All in all, this project has been an in-depth first exposure to embedded system designs from an industry viewpoint.

13.0 References

1] Microchip Technology Inc., PIC18F2585/2680/4585/4680 Data Sheet. Microchip Technology Inc., 2004. Available Online

2] Philips Semiconductors, SC16IS752/SC16IS762 Product Data Sheet. Philips Semiconductors, 2006. Available Online

3] Philips Semiconductors, SC28L198 Octal UART for 3.3V and 5V Supply Voltage Data Sheet. Philips Semiconductors, 2005. Available Online

4] Freescale Semiconductor, MMA7260Q ±1.5g - 6g Three Axis Low-g Micromachined Accelerometer Data Sheet. Freescale Semiconductor, 2005. Available Online

5] Eitzenberger, "Vehicle communication system," US Patent #6,023,232, February 8, 2000

6] Dauner, "Motor communication system and method for exchanging data in a motor vehicle," US Patent #6,941,194, November 22, 2005

7] Dauner, et al., "Vehicle communications system," US Patent #6,526,460, February 25, 2003

8] USPTO Search Engine, United States Government

9] Understanding Patent Infringement Legal Opinions, David V Radack

10] United States of America. Department of Defense. Military Handbook: Reliability Prediction of Electronic Equipment, 217F. Washington DC: Department of Defense, 1991.

11] Maxim Integrated Products, MAX1684/MAX1685 Data Sheet. Sunnyvale, CA : Maxim Integrated Products, 2001. Available Online

12] Linear Technology, LT1121/LT1121-3.3/LT1121-5 Data Sheet. Milpitas, CA : Linear Technology, 1994. Available Online

13] IEEE, “IEEE Code of Ethics,” April 2006, Available Online

14] National Society of Professional Engineers, Code of Ethics for Engineers. Alexandria, VA : National Society of Professional Engineers, 2006. Available Online

15] Environmental Protection Agency, “What is Green Engineering?,” April 2006, Available Online

16] Silicon Valley Toxics Coalition, “The Environmental Cost of Printed Circuit Boards,” April 2006, Available Online

17] A. Gemmell, “Printed Circuit Board Manufacturing Pollution Prevention Opportunities Checklist,” April 2006, Available Online

18] “Printed Circuit Board Recycling,” April 2006, Available Online

19] Reade Advanced Materials, “Specific Gravity Weights of Materials From READE,” April 2006, Available Online

20] Spektrum, “Spektrum Nitro Telemetry System,” April 2006, Available Online

21] Microchip Technology Inc., MCP2551 High-Speed CAN Transceiver Data Sheet. Microchip Technology Inc., 2003. Available Online

22] Maxim Integrated Products, MAX238 +5V-Powered, Multichannel RS-232 Drivers/Receivers Data Sheet. Sunnyvale, CA : Maxim Integrated Products, 2004. Available Online

23] Freescale Semiconductor, MMA2260D ±1.5g X-Axis Micromachined Accelerometer Data Sheet. Freescale Semiconductor, 2006. Available Online

24] Freescale Semiconductor, MMA1260D Low G Micromachined Accelerometer Data Sheet. Freescale Semiconductor, 2006. Available Online

25] Garmin International, Inc., GPS18 Technical Specifications. Olathe, KS : Garmin International, Inc., 2005. Available Online

26] D. L. Jones, PCB Design Tutorial. 2004. Available Online



27] Motorola, Inc., System Design and Layout Techniques for Noise Reduction in MCU-Based Systems. Motorola, Inc., 1995. Available Online



28] ECE477 Module 2: Digital System Design Considerations and PCB Layout Basics



29] PIC18F4680 User's Manual



30] Microchip Technology Inc., MPLAB IDE User’s Guide. Microchip Technology Inc., 2005. Available Online

31] Microchip Technology Inc., PIC18 Configuration Settings Addendum. Microchip Technology Inc., 2005. Available Online

32] Microchip Technology Inc., MPLAB C18 C Compiler Libraries. Microchip Technology Inc., 2005. Available Online

Appendix A: Individual Contributions

A.1 Contributions of Matt Cozza:

I was involved in every single phase of the project. I helped with component selection and acquisition, schematic design, PCB layout, soldering and populating the PCB, testing the populated PCB, software development, and software testing and debugging. Some of these areas I helped with more than others, but I tried to maintain an equal footing provide help in all aspects of the project. I also was the team member who maintained and updated the website on a weekly basis.

When it came to everything from component selection to soldering and populating the PCB, I was usually helping someone or making small adjustments. When components were selected for the design, I sampled a lot of them from various companies. After Evan had made the schematic, there were a few things that needed to be adjusted. I mostly cleaned up the schematic to allow for more readability and better clarity. Then, after Joe had made footprints for the PCB, I organized the footprints and routed a good portion of the traces. I soldered a lot of the 0805 surface mount capacitors and resistors, as well as the accelerometers and portions of the power circuit. I also helped to write software to test the accelerometers and there functionality after being placed on the board. I also wrote and compiled the bill of materials from the list of all the parts we used.

A majority of what I worked on for the project was the software. I helped to develop the main basis for a lot of the software and wrote a lot of the functions used in the final code. Except for a lot of the CAN functionality, I helped to develop most of the software. Some of the functions I wrote include, but are not limited to a function for reading strings from UART through the SPI chips, parsing functions for both the battery pack and motor controller, a function for polling UART through the SPI chips, send/receive functions for the motor controller, the majority of the timer ISR, and a base skeleton for the main polling loop. I also helped to set up some of the functionality for writing data to the UART through the SPI chips and the A/D functions. On top of writing all of the software, I helped to debug and test it. I noticed a discrepancy in the use of parenthesis for the function which reads a byte from UART through the SPI chips. After fixing this discrepancy, the functionality of one of the SPI to dual UART chips we had believed to be broken was restored. The majority of what I tested centered on the data processing functions like parsing motor controller and battery pack, UART and A/D capabilities, and the timer ISR.

I wrote the software considerations and narrative report, as well as the ethical and environmental impact report. I also made an effort to proof read everyone else’s reports before they turned them in. I always helped to create the power point presentations for the TC practicum, as well as the midterm and final project presentations. In addition, I made the team’s poster and helped to write the ECE senior design report. I tried to play an active role in helping in all aspects of the design process and the work accompanying it.

A.2 Contributions of Joe Waugh

In the early phases of the project, I worked on the packaging homework, and helped with some of the component and module selection. The packaging itself was mostly trivial, since there were no aesthetic or size constraints. However, the report was more challenging, since it was basically an entire report on using a plastic project box. I helped research accelerometer and GPS solutions. The accelerometers we ended up using were the single-axis chips I picked out, and the GPS solution we used was the external RS-232 module I picked out. Additionally, I selected all of the passive components in the system, and I filled out the component order form which the solar car club ordered.

During the layout phase, I did most of the layout for the second pass of the PCB. We determined that we could significantly improve on the first layout design, so Matt and Evan re-placed the components and made some initial routes. I completed the routing, and then went through many iterations of placement tweaks and route tweaks until the layout was very good. The final layout featured a near-solid ground plane on the bottom copper, with the power and analog circuitry entirely single sided. The power, digital, and analog sections were clearly separated in the layout. I used image rails around any medium to high speed traces that had ground plane interruptions. That means I basically stitched together the ground plane by pulling a trace from the ground plane up to the top layer, over the interruption, then back to the bottom layer. This technique essentially eliminated any negative effects of ground plane interruption. After I completed the layout, I prepared it for manufacturing.

After we received the actual PCB, I soldered most of the components onto it. I also helped debug the hardware. I found, and corrected problems with a feedback network in the power supply, as well as the problem with the pins on one side of our microcontroller being flipped. After the PCB was soldered, I did most of the module-by-module software testing, except for CAN and some A/D testing.

In the late phases of the project, I did the reliability homework, and a lot of the software and debugging. I created the large, constant structure which drives our data collection, the final version main loop, the final version of most CAN functions, the GPS routines, some of the underlying SPI routines, and the packet modem routines. I contributed to the timer-based heartbeat, the BPS and the motor controller routines. I created simulators in Excel which mimicked the operation of the connected UART devices, to make testing possible when the real devices were unavailable. Finally, I did most of the software debugging, and ensured all of the solar projects worked together.

A.3 Contributions of Evan Zelkowitz:

I covered a great number of roles and aspects in this project as our whole team did. In the beginning of the project I focused on component selection and constraint analysis. I received the requirements of the project from the solar team and from this determined possible solutions for the many of the parts we needed. The main aspect of the project was the data collection and information passing of the telemetry system. To accomplish this we needed a way to communicate with four UART devices and the PIC family we were restricted to only contained one. I started researching solutions to this such as UART expansion chips but most of these required an entire port on our microcontroller which we could not give up since at the start of the project we were unsure of how many general purpose I/O pins we would need. This led me use some sort of expansion through a serial bus interface and I found the Philips SPI-UART chips which used the SPI bus to let us gain the additional UART channels. I also researched accelerometers and temperature sensors.

After part selection I focused on the schematic design as it was one of the reports I had to write. I started by creating schematic parts for each of our integrated circuit chips. Using the data sheets from each of the manufacturer I laid these designs out. After creating each of the parts I started work on combining all the parts together in to a usable schematic for translation to our PCB. I did this by focusing my design in to blocks, first focusing on the SPI-UART communication since it was the most complicated and then moving to the microcontroller and CAN and then finally power and A/D functionality. After receiving feedback on the report I was helped by some of my teammates to make the schematic a bit more readable and address the concerns that were presented in the feedback. This schematic was then used to create our final PCB. I helped in creation of the PCB with my knowledge of the schematic and how everything connected in the overall design. This helped the team by allowing me to give guidance to my teammates as far as part placement and routing strategies for the best possible use of space on the board.

After the PCB and schematic were complete I helped in testing the traces of the PCB as well as the functionality of the parts as they were placed. The team started by first soldering on the power supply and testing it for correct output and then moved to all the peripherals. Once all the parts were soldered work began on software development. I helped in this area by first setting up our IDE for use in lab as well as gathering all the necessary libraries. I then start writing initial functions to gather data from the accelerometers as well as the temperature sensor. While writing these functions I also wrote much of the initialization for our devices such as the A/D, SPI, and CAN. After the initializations were complete Joe and Matt took over and did a lot more of the software development. My focus at this point was working on the CAN software when I had a chance. I did testing using the CAN simulator and finally determined how to send and receive CAN messages on the bus using this simulator and finding the correct initialization values. After CAN was initially designed the majority of my time was helping to debug the overall design since other team members wrote much of the other code. I helped in debugging the communication with most of the peripherals as well as communication over the CANbus with the other groups' projects.

After project completion I started work on the final documentation. I wrote the ECE Senior Design Report which was then proofread by Matt. I also wrote many of the slides for the final presentation. The only areas I did not cover were the patent analysis and the safety analysis since those were not my areas of expertise. Throughout the semester I always helped with the presentations whenever they arose and always tried to help out members whenever possible. I enjoyed designing a system from the ground up and learning the aspects of a team based design of a marketable product.

A.4 Contributions of Elmer Chao:

I was involved with every single aspect of the project, as was the rest of the team. Since the early stages, I was involved in the component selection and constraint analysis portions of the project. I attended the initial meetings with the solar racing team in order to determine what our constraints were and discussed with our team what our attack plans were going to be. For the components, I helped select the linear regulator later on in the component selection process when the team found out that the SPI-UART chips needed 3.3v instead of 5v.

During the design phase of the project I was an integral part in the Schematic and PCB Layout. I helped in creating the CAN transceiver part of the schematic by referencing the data sheet and deciding on what bypass capacitors and pins we needed to short to ground. For the PCB Layout, I spearheaded the team into it and completed the majority of the first pass of the Layout myself. I took on most of the learning curve for importing the schematic and learning to use the Layout program to route the components. Joe and I also spent a lot of time creating and finding footprints at the beginning of the Layout process. I also wrote up the PCB Layout report. After the PCB Layout homework submission, Matt, Joe, and Evan later created a second pass layout which included a ground plane, simpler routing, and less vias. I also participated in the second pass of the layout by helping troubleshoot problem DRC errors after the layout was completed. I also improved on many of the slides for the midterm presentation.

After the board was manufactured, I took the initiative to begin the soldering. I finished up the main components in the power circuit and tested them. The rest of the team finished up soldering the remainder of the circuit. When we began writing software to test the various functionalities of the system, I was there to help out and follow what was going on. I contributed during the testing phase by helping out in creating the function that sends messages through the UART ports. There were many difficulties that we faced during the testing phase, one of which was not being able to see messages coming from the microcontroller's UART port. I helped out by hooking up the output to the oscilloscope and verifying that the peak to peak voltages were correct. I also helped in troubleshooting other problems such as the dead SPI-CHIP, which just wouldn't work when we tried to send a UART message out of it. We later found out that it was just a parenthesis that was missing. Another problem that I helped solve was the fried temperature sensor that we borrowed from another solar racing team. I found out that the sensor was supposed to operate at 4.4V instead of 5V and realized that we were using the wrong version of the temperature sensor. During this time I was also responsible for writing the Patent Liability report. I researched and found three patents and analyzed those carefully to come up with possible solutions to avoid infringement by the Telemetry System. Since this system is custom and will most likely never be mass produced for profit, it was determined that there's very little risk for any type of a patent infringement lawsuit.

During the last phase of the project, I mainly focused on the packaging design and creation while the other team members focused on writing the main loop for the microcontroller. I made the whole packaging, drilled all the holes, and decided on all the ideal mounting positions. I mounted the 4 UART connectors and the 4 6-pin CAN connectors. I also created the cables for all of the connectors. I also collaborated with the rest of the team about placements, cable design, and mounting methods to ensure that they could work with the board while it was inside the packaging. I helped in the filming of the PSSC's and in editing the video clip. I also made the ECE362 presentation. Finally, I created the final report.

Throughout the semester I always took an active role in team homework assignments and presentations. Also, I proofread most of the other teammate's homework assignments when they were due, and offered suggestions if I had any. Although I wish I could've helped out more with software, I felt like the Joe, Evan, and Matt were very understanding in taking the time to explain to me what they were doing with much of the programming. I made sure that I was involved in all the aspects of the creation of the Telemetry system, and always tried hard to contribute my expertise to the project. It was a great experience that will definitely benefit me when I'm a product development engineer.

Appendix B: Packaging

[pic]

Figure B.1 – Packaging CAD Drawing

Appendix C: Schematic

[pic]

Figure C.1 – Analog Schematic

[pic]

Figure C.2 – Microprocessor and CAN Schematic

[pic]

Figure C.3 – Power Schematic

[pic]

Figure C.4 – SPI – UART Schematic

Appendix D: PCB Layout Top and Bottom Copper

[pic]

Figure D.1 PCB Top Copper

[pic]

Figure D.2 Bottom Copper

Appendix E: Parts List Spreadsheet

Appendix F: Software Listing

#ifndef __MAIN_H_

#define __MAIN_H_

// _ ___

// _ _ ( ) /'___)_

// _( )( )_ _| | __ | (__ (_) ___ __ ___

// (_ .. _) /'_` | /'__`\| ,__)| |/' _ `\ /'__`\/',__)

// (_ _)( (_| |( ___/| | | || ( ) |( ___/\__, \

// (_)(_) `\__,_)`\____)(_) (_)(_) (_)`\____)(____/

#define HASSELHOFF_IS_COOL 1

#define SPI_A0 1 // SPI-UART Chip A (U26), Channel 0, J15 (UART_4)

#define SPI_A1 2 // SPI-UART Chip A (U26), Channel 1, J14 (UART_3)

#define SPI_B0 3 // SPI-UART Chip B (U25), Channel 0, UNUSED

#define SPI_B1 4 // SPI-UART Chip B (U25), Channel 1, J17 (UART_2)

#define PIC_UART 5 // build in UART channel, J?? (UART_1)

#define SPI_BPS SPI_B1 // SPI-UART Channel Assignment for Battery System

#define SPI_MC SPI_A0 // SPI-UART Channel Assignment for Motor Controller

#define SPI_GPS SPI_A1 // SPI-UART Channel Assignment for GPS

#define PACKET_MODEM PIC_UART // UART Channel Assignment for Packet Modem

#define SPI_RHR 0x00 // Receive Holding Register (read)

#define SPI_THR 0x00 // Transmit Holding Register (write)

#define SPI_IER 0x01 // Interrupt Enable Register

#define SPI_FCR 0x02 // FIFO Control Register (write)

#define SPI_IIR 0x02 // Interrupt Identification Register (read)

#define SPI_LCR 0x03 // Line Control Register

#define SPI_MCR 0x04 // Modem Control Register

#define SPI_LSR 0x05 // Line Status Register (read)

#define SPI_MSR 0x06 // Modem Status Register

#define SPI_SPR 0x07 // Scratchpad Register

#define SPI_TCR 0x06 // Transmission Control Register

#define SPI_TLR 0x07 // Trigger Level Register

#define SPI_TXLVL 0x08 // Transmit FIFO Level Register (read)

#define SPI_RXLVL 0x09 // Receive FIFO Level Register (read)

#define SPI_IODir 0x0A // I/O Pins Direction Register

#define SPI_IOState 0x0B // I/O Pins State Register (read)

#define SPI_IOIntEna 0x0C // I/O Pins Interrupt Enable Register

#define SPI_IOControl 0x0E // I/O Pins Control Register

#define SPI_EFCR 0x0F // Enhanced Features Control Register

#define SPI_DLL 0x00 // Divisor Latch LSB

#define SPI_DLH 0x01 // Divisor Latch MSB

#define SPI_EFR 0x02 // Enhanced Features Register

#define SPI_XON1 0x04 // Xon1 Word

#define SPI_XON2 0x05 // Xon2 Word

#define SPI_XOFF1 0x06 // Xoff1 Word

#define SPI_XOFF2 0x07 // Xoff2 Word

#define TEMP_TOO_HIGH 90 // in F? threshold for temperature alert

#define UART_ARR_LENGTH 10 // array length for sending strings through UART

// restrictions on length of input buffer

#define MIN_GPS_BUFFER_LENGTH ( 1 )

#define MAX_GPS_BUFFER_LENGTH ( 64 ) // the SPI-UART fifo only holds 64

/*

Sentences transmitted by GPS18:

GPRMC (default) : Recommended minimum specific GNSS data

GPGGA (default) : Global positioning system fixed data

GPGSA (default) : GNSS DOP and active satellites

GPGSV (default) : GNSS satellites in view

PGRME (default) : Estimated Error

GPGLL : Geographic position - latitude / longitude

GPVTG : Course over ground and ground speed

PGRMV : 3d velocity

PGRMF : Fix Data Sentence (contains date)

PGRMB (default) : (unsupported?) DGPS beacon info

PGRMT (default) : GPS unit sensor status

*/

// GPS States for state machine

#define GPSS_IGNORE ( 0 )

#define GPSS_START ( 1 )

#define GPSS_SENTENCE_ID ( 2 )

#define GPSS_SENTENCE_ID_G ( 3 )

#define GPSS_SENTENCE_ID_GP ( 4 )

#define GPSS_SENTENCE_ID_GPG ( 5 )

#define GPSS_SENTENCE_ID_GPGG ( 6 )

#define GPSS_SENTENCE_ID_GPGGA ( 7 )

#define GPSS_SENTENCE_ID_GPGL ( 8 )

#define GPSS_SENTENCE_ID_GPGLL ( 9 )

/*

$GPGGA Sentence (Fix data)

Example (signal not acquired): $GPGGA,235947.000,0000.0000,N,00000.0000,E,0,00,0.0,0.0,M,,,,0000*00

Example (signal acquired): $GPGGA,092204.999,4250.5589,S,14718.5084,E,1,04,24.4,19.7,M,,,,0000*1F

Field Example Comments

Sentence ID $GPGGA

UTC Time 092204.999 hhmmss.sss

Latitude 4250.5589 ddmm.mmmm

N/S Indicator S N = North, S = South

Longitude 14718.5084 dddmm.mmmm

E/W Indicator E E = East, W = West

Position Fix 1 0 = Invalid, 1 = Valid SPS, 2 = Valid DGPS, 3 = Valid PPS

Satellites Used 04 Satellites being used (0-12)

HDOP 24.4 Horizontal dilution of precision

Altitude 19.7 Altitude in meters according to WGS-84 ellipsoid

Altitude Units M M Meters

Geoid Seperation Geoid seperation in meters according to WGS-84 ellipsoid

Seperation Units M Meters

DGPS Age Age of DGPS data in seconds

DGPS Station ID 0000

Checksum *1F

Terminator CR/LF

*/

#define GPSS_GPGGA_TIME ( 10 )

#define GPSS_GPGGA_LAT ( 11 )

#define GPSS_GPGGA_NS ( 12 )

#define GPSS_GPGGA_LONG ( 13 )

#define GPSS_GPGGA_EW ( 14 )

#define GPSS_GPGGA_POS_FIX ( 15 )

#define GPSS_GPGGA_SATS ( 16 )

#define GPSS_GPGGA_HDOP ( 17 )

#define GPSS_GPGGA_ALT ( 18 )

#define GPSS_GPGGA_ALT_UNIT ( 19 )

#define GPSS_GPGGA_GEOID ( 20 )

#define GPSS_GPGGA_GEOID_UNIT ( 21 )

#define GPSS_GPGGA_AGE ( 22 )

#define GPSS_GPGGA_STATION_ID ( 23 )

#define GPSS_GPGGA_CHECKSUM ( 24 )

/*

$GPGLL Sentence (Position)

Example (signal not acquired): $GPGLL,0000.0000,N,00000.0000,E,235947.000,V*2D

Example (signal acquired): $GPGLL,4250.5589,S,14718.5084,E,092204.999,A*2D

Field Example Comments

Sentence ID $GPGLL

Latitude 4250.5589 ddmm.mmmm

N/S Indicator S N = North, S = South

Longitude 14718.5084 dddmm.mmmm

E/W Indicator E E = East, W = West

UTC Time 092204.999 hhmmss.sss

Status A A = Valid, V = Invalid

Checksum *2D

Terminator CR/LF

*/

#define GPSS_GPGLL_LAT ( 25 )

#define GPSS_GPGLL_NS ( 26 )

#define GPSS_GPGLL_LONG ( 27 )

#define GPSS_GPGLL_EW ( 28 )

#define GPSS_GPGLL_TIME ( 29 )

#define GPSS_GPGLL_STATUS ( 30 )

#define GPSS_GPGLL_CHECKSUM ( 31 )

#define CR ( 13 )

#define LF ( 10 )

#define TAB ( 0x09 )

// return values from ParseGPS()

#define GPS_PARSING_COMPLETE ( 1 )

#define GPS_PARSING_INCOMPLETE ( 2 )

#define GPS_PARSE_ERROR ( 3 )

#define BUFFER_EMPTY ( 4 )

// globals for data output

#define GPS_LATITUDE_LENGTH ( 9 )

#define GPS_LONGITUDE_LENGTH ( 10 )

#define GPS_ALTITUDE_LENGTH ( 4 )

#define GPS_TIME_LENGTH ( 10 )

#define BPS_PARSING_COMPLETE GPS_PARSING_COMPLETE

#define BPS_PARSING_INCOMPLETE GPS_PARSING_INCOMPLETE

#define BPS_PARSE_ERROR GPS_PARSE_ERROR

#define RETURN_COMPLETE GPS_PARSING_COMPLETE

#define RETURN_INCOMPLETE GPS_PARSING_INCOMPLETE

#define MIN_BPS_BUFFER_LENGTH MIN_GPS_BUFFER_LENGTH

#define MAX_BPS_BUFFER_LENGTH MAX_GPS_BUFFER_LENGTH

#define MC_STATE_SEND 1

#define MC_STATE_RECV 2

#define BPS_START_CHAR ( 0x0c ) // BPS starting char set to be form feed

#define NUM_BATTERIES ( 15 )

#define BPSS_START ( 0 )

#define BPSS_CELL_VOLTAGE ( 1 )

#define BPSS_CELL_TEMP ( 2 )

#define BPSS_CELL_BALANCE ( 3 )

#define BPSS_BATTERY_CURRENT ( 4 )

// designating characters

#define DC_PPT0_IN_VOLTAGE ( 0 )

#define DC_PPT0_OUT_VOLTAGE ( 1 )

#define DC_PPT0_IN_CURRENT ( 2 )

#define DC_PPT0_OUT_CURRENT ( 3 )

#define DC_PPT0_TEMPERATURE ( 4 )

#define DC_PPT0_MAX_POWER ( 5 )

#define DC_PPT0_RESERVED ( 6 )

#define DC_PPT1_IN_VOLTAGE ( 8 )

#define DC_PPT1_OUT_VOLTAGE ( 9 )

#define DC_PPT1_IN_CURRENT ( 10 )

#define DC_PPT1_OUT_CURRENT ( 11 )

#define DC_PPT1_TEMPERATURE ( 12 )

#define DC_PPT1_MAX_POWER ( 13 )

#define DC_PPT1_RESERVED ( 14 )

#define DC_PPT2_IN_VOLTAGE ( 16 )

#define DC_PPT2_OUT_VOLTAGE ( 17 )

#define DC_PPT2_IN_CURRENT ( 18 )

#define DC_PPT2_OUT_CURRENT ( 19 )

#define DC_PPT2_TEMPERATURE ( 20 )

#define DC_PPT2_MAX_POWER ( 21 )

#define DC_PPT2_RESERVED ( 22 )

#define DC_PPT3_IN_VOLTAGE ( 24 )

#define DC_PPT3_OUT_VOLTAGE ( 25 )

#define DC_PPT3_IN_CURRENT ( 26 )

#define DC_PPT3_OUT_CURRENT ( 27 )

#define DC_PPT3_TEMPERATURE ( 28 )

#define DC_PPT3_MAX_POWER ( 29 )

#define DC_PPT3_RESERVED ( 30 )

#define DC_PPT4_IN_VOLTAGE ( 32 )

#define DC_PPT4_OUT_VOLTAGE ( 33 )

#define DC_PPT4_IN_CURRENT ( 34 )

#define DC_PPT4_OUT_CURRENT ( 35 )

#define DC_PPT4_TEMPERATURE ( 36 )

#define DC_PPT4_MAX_POWER ( 37 )

#define DC_PPT4_RESERVED ( 38 )

#define DC_PPT5_IN_VOLTAGE ( 40 )

#define DC_PPT5_OUT_VOLTAGE ( 41 )

#define DC_PPT5_IN_CURRENT ( 42 )

#define DC_PPT5_OUT_CURRENT ( 43 )

#define DC_PPT5_TEMPERATURE ( 44 )

#define DC_PPT5_MAX_POWER ( 45 )

#define DC_PPT5_RESERVED ( 46 )

#define DC_PPT6_IN_VOLTAGE ( 48 )

#define DC_PPT6_OUT_VOLTAGE ( 49 )

#define DC_PPT6_IN_CURRENT ( 50 )

#define DC_PPT6_OUT_CURRENT ( 51 )

#define DC_PPT6_TEMPERATURE ( 52 )

#define DC_PPT6_MAX_POWER ( 53 )

#define DC_PPT6_RESERVED ( 54 )

#define DC_PPT7_IN_VOLTAGE ( 56 )

#define DC_PPT7_OUT_VOLTAGE ( 57 )

#define DC_PPT7_IN_CURRENT ( 58 )

#define DC_PPT7_OUT_CURRENT ( 59 )

#define DC_PPT7_TEMPERATURE ( 60 )

#define DC_PPT7_MAX_POWER ( 61 )

#define DC_PPT7_RESERVED ( 62 )

#define DC_PPT8_IN_VOLTAGE ( 64 )

#define DC_PPT8_OUT_VOLTAGE ( 65 )

#define DC_PPT8_IN_CURRENT ( 66 )

#define DC_PPT8_OUT_CURRENT ( 67 )

#define DC_PPT8_TEMPERATURE ( 68 )

#define DC_PPT8_MAX_POWER ( 69 )

#define DC_PPT8_RESERVED ( 70 )

#define DC_PPT9_IN_VOLTAGE ( 72 )

#define DC_PPT9_OUT_VOLTAGE ( 73 )

#define DC_PPT9_IN_CURRENT ( 74 )

#define DC_PPT9_OUT_CURRENT ( 75 )

#define DC_PPT9_TEMPERATURE ( 76 )

#define DC_PPT9_MAX_POWER ( 77 )

#define DC_PPT9_RESERVED ( 78 )

#define DC_PPT10_IN_VOLTAGE ( 80 )

#define DC_PPT10_OUT_VOLTAGE ( 81 )

#define DC_PPT10_IN_CURRENT ( 82 )

#define DC_PPT10_OUT_CURRENT ( 83 )

#define DC_PPT10_TEMPERATURE ( 84 )

#define DC_PPT10_MAX_POWER ( 85 )

#define DC_PPT10_RESERVED ( 86 )

#define DC_PPT11_IN_VOLTAGE ( 88 )

#define DC_PPT11_OUT_VOLTAGE ( 89 )

#define DC_PPT11_IN_CURRENT ( 90 )

#define DC_PPT11_OUT_CURRENT ( 91 )

#define DC_PPT11_TEMPERATURE ( 92 )

#define DC_PPT11_MAX_POWER ( 93 )

#define DC_PPT11_RESERVED ( 94 )

#define DC_PPT12_IN_VOLTAGE ( 96 )

#define DC_PPT12_OUT_VOLTAGE ( 97 )

#define DC_PPT12_IN_CURRENT ( 98 )

#define DC_PPT12_OUT_CURRENT ( 99 )

#define DC_PPT12_TEMPERATURE ( 100 )

#define DC_PPT12_MAX_POWER ( 101 )

#define DC_PPT12_RESERVED ( 102 )

#define DC_PPT13_IN_VOLTAGE ( 104 )

#define DC_PPT13_OUT_VOLTAGE ( 105 )

#define DC_PPT13_IN_CURRENT ( 106 )

#define DC_PPT13_OUT_CURRENT ( 107 )

#define DC_PPT13_TEMPERATURE ( 108 )

#define DC_PPT13_MAX_POWER ( 109 )

#define DC_PPT13_RESERVED ( 110 )

#define DC_PPT14_IN_VOLTAGE ( 112 )

#define DC_PPT14_OUT_VOLTAGE ( 113 )

#define DC_PPT14_IN_CURRENT ( 114 )

#define DC_PPT14_OUT_CURRENT ( 115 )

#define DC_PPT14_TEMPERATURE ( 116 )

#define DC_PPT14_MAX_POWER ( 117 )

#define DC_PPT14_RESERVED ( 118 )

#define DC_PPT15_IN_VOLTAGE ( 120 )

#define DC_PPT15_OUT_VOLTAGE ( 121 )

#define DC_PPT15_IN_CURRENT ( 122 )

#define DC_PPT15_OUT_CURRENT ( 123 )

#define DC_PPT15_TEMPERATURE ( 124 )

#define DC_PPT15_MAX_POWER ( 125 )

#define DC_PPT15_RESERVED ( 126 )

#define DC_MC_RPM ( 128 )

#define DC_MC_THROTTLE_INPUT ( 129 )

#define DC_MC_REGEN_INPUT ( 130 )

#define DC_MC_PHASE_CURRENT ( 131 )

#define DC_MC_SUPPLY_VOLTAGE ( 132 )

#define DC_MC_MOTOR_TEMP ( 133 )

#define DC_MC_HEATSINK_TEMP ( 134 )

#define DC_MC_OPERATING_STATUS ( 135 )

#define DC_MC_OBSERVED_ROTATION_DIR ( 136 )

#define DC_MC_FAULT1 ( 137 )

#define DC_MC_FAULT2 ( 138 )

#define DC_MC_FAULT3 ( 139 )

#define DC_MC_FAULT4 ( 140 )

#define DC_MC_THROTTLE_ENABLE ( 141 )

#define DC_MC_INPUT_DIR ( 142 )

#define DC_MC_ACTUAL_DIR ( 143 )

#define DC_MC_SPEED_CONTROL ( 144 )

#define DC_MC_DIGITAL_DISABLE_STATE ( 145 )

#define DC_MC_THROTTLE_ENABLE_STATE ( 146 )

#define DC_MC_FORWARD_INPUT_STATE ( 147 )

#define DC_BPS_CELL_1_VOLTAGE ( 148 )

#define DC_BPS_CELL_2_VOLTAGE ( 149 )

#define DC_BPS_CELL_3_VOLTAGE ( 150 )

#define DC_BPS_CELL_4_VOLTAGE ( 151 )

#define DC_BPS_CELL_5_VOLTAGE ( 152 )

#define DC_BPS_CELL_6_VOLTAGE ( 153 )

#define DC_BPS_CELL_7_VOLTAGE ( 154 )

#define DC_BPS_CELL_8_VOLTAGE ( 155 )

#define DC_BPS_CELL_9_VOLTAGE ( 156 )

#define DC_BPS_CELL_10_VOLTAGE ( 157 )

#define DC_BPS_CELL_11_VOLTAGE ( 158 )

#define DC_BPS_CELL_12_VOLTAGE ( 159 )

#define DC_BPS_CELL_13_VOLTAGE ( 160 )

#define DC_BPS_CELL_14_VOLTAGE ( 161 )

#define DC_BPS_CELL_15_VOLTAGE ( 162 )

#define DC_BPS_CELL_1_TEMPERATURE ( 163 )

#define DC_BPS_CELL_2_TEMPERATURE ( 164 )

#define DC_BPS_CELL_3_TEMPERATURE ( 165 )

#define DC_BPS_CELL_4_TEMPERATURE ( 166 )

#define DC_BPS_CELL_5_TEMPERATURE ( 167 )

#define DC_BPS_CELL_6_TEMPERATURE ( 168 )

#define DC_BPS_CELL_7_TEMPERATURE ( 169 )

#define DC_BPS_CELL_8_TEMPERATURE ( 170 )

#define DC_BPS_CELL_9_TEMPERATURE ( 171 )

#define DC_BPS_CELL_10_TEMPERATURE ( 172 )

#define DC_BPS_CELL_11_TEMPERATURE ( 173 )

#define DC_BPS_CELL_12_TEMPERATURE ( 174 )

#define DC_BPS_CELL_13_TEMPERATURE ( 175 )

#define DC_BPS_CELL_14_TEMPERATURE ( 176 )

#define DC_BPS_CELL_15_TEMPERATURE ( 177 )

#define DC_BPS_CELL_1_BALANCING ( 178 )

#define DC_BPS_CELL_2_BALANCING ( 179 )

#define DC_BPS_CELL_3_BALANCING ( 180 )

#define DC_BPS_CELL_4_BALANCING ( 181 )

#define DC_BPS_CELL_5_BALANCING ( 182 )

#define DC_BPS_CELL_6_BALANCING ( 183 )

#define DC_BPS_CELL_7_BALANCING ( 184 )

#define DC_BPS_CELL_8_BALANCING ( 185 )

#define DC_BPS_CELL_9_BALANCING ( 186 )

#define DC_BPS_CELL_10_BALANCING ( 187 )

#define DC_BPS_CELL_11_BALANCING ( 188 )

#define DC_BPS_CELL_12_BALANCING ( 189 )

#define DC_BPS_CELL_13_BALANCING ( 190 )

#define DC_BPS_CELL_14_BALANCING ( 191 )

#define DC_BPS_CELL_15_BALANCING ( 192 )

#define DC_BPS_BATTERY_CURRENT ( 193 )

#define DC_BPS_UNKNOWN1 ( 194 )

#define DC_BPS_UNKNOWN2 ( 195 )

#define DC_DI_TEXT_MESSAGE_0_6 ( 196 )

#define DC_DI_TEXT_MESSAGE_7_13 ( 197 )

#define DC_DI_TEXT_MESSAGE_14_20 ( 198 )

#define DC_DI_TEXT_MESSAGE_21_27 ( 199 )

#define DC_DI_TEXT_MESSAGE_28_34 ( 200 )

#define DC_DI_TEXT_MESSAGE_35_41 ( 201 )

#define DC_DI_TEXT_MESSAGE_42_48 ( 202 )

#define DC_DI_TEXT_MESSAGE_49_55 ( 203 )

#define DC_DI_TEXT_MESSAGE_56_62 ( 204 )

#define DC_DI_TEXT_MESSAGE_63_69 ( 205 )

#define DC_DI_TEXT_MESSAGE_70_76 ( 206 )

#define DC_DI_TEXT_MESSAGE_77_79 ( 207 )

#define DC_TELEM_GPS_TIME ( 208 )

#define DC_TELEM_GPS_LATITUDE ( 209 )

#define DC_TELEM_GPS_LONGITUDE ( 210 )

#define DC_TELEM_GPS_ALTITUDE ( 211 )

#define DC_TELEM_X_ACCELERATION ( 212 )

#define DC_TELEM_Y_ACCELERATION ( 213 )

#define DC_TELEM_Z_ACCELERATION ( 214 )

#define DC_TELEM_TEMPERATURE ( 215 )

#define DC_TELEM_TEMPERATURE_ALERT ( 216 )

#define DC_CONNAND_TURN_OFF ( 254 )

#define DC_COMMAND_REQUEST ( 255 )

// constants for the data_type field of the polled_data_type struct

#define TYPE_INT ( 1 )

#define TYPE_CHAR_POINTER ( 2 )

#define TYPE_ASCII_DECIMAL ( 3 )

#define TYPE_ASCII_HEX ( 4 )

#define TYPE_ASCII_FLOAT ( 5 )

#define TYPE_UCHAR ( 6 )

// constants for the device_id field of the polled_data_type struct

#define DEVID_PPT0 ( 0 )

#define DEVID_PPT1 ( 1 )

#define DEVID_PPT2 ( 2 )

#define DEVID_PPT3 ( 3 )

#define DEVID_PPT4 ( 4 )

#define DEVID_PPT5 ( 5 )

#define DEVID_PPT6 ( 6 )

#define DEVID_PPT7 ( 7 )

#define DEVID_PPT8 ( 8 )

#define DEVID_PPT9 ( 9 )

#define DEVID_PPT10 ( 10 )

#define DEVID_PPT11 ( 11 )

#define DEVID_PPT12 ( 12 )

#define DEVID_PPT13 ( 13 )

#define DEVID_PPT14 ( 14 )

#define DEVID_PPT15 ( 15 )

#define DEVID_MOTOR ( 16 )

#define DEVID_BPS ( 17 )

#define DEVID_DI ( 18 )

#define DEVID_TELEM ( 19 )

#define MAX_COMMAND_SIZE ( 4 )

#define POLLED_DATA_SIZE ( 148 )

#define ALL_DATA_SIZE ( 217 )

#define MAX_PPTS ( 16 ) // maximum number of power point trackers in the system

#define NUM_PPTS ( 8 ) // maximum number of power point trackers in the system

#define RACE_MODE_SEND 0

#define RACE_MODE_WAIT 1

#define RACE_MODE_RCV 2

#define INC_COUNTER 3

#define DIAGNOSTIC_MODE 4

#define ERROR 5

#define POLL_GPS 6

#define POLL_BPS 7

#define COUNTER_TOO_BIG 500 // counter value maximum limit for detecting error

#define GPS_ERR_STATUS 0x0001 // mask to access GPS error bit

#define BPS_ERR_STATUS 0x0002 // mask to access BPS error bit

#define MC_ERR_STATUS 0x0004 // mask to access MC error bit

#define CAN_ERR_STATUS 0x0008 // mask to access CAN error bit

#define POLL_ADC_FLAG 0x0010 // mask to access ADC poll flag bit

#define POLL_GPS_FLAG 0x0020 // mask to access GPS poll flag bit

#define POLL_BPS_FLAG 0x0040 // mask to access BPS poll flag bit

#define SEND_STATUS_FLAG 0x0080 // we should spew our data at PM

#define POLL_CAN_FLAG 0x0100 // we should spew our data at PM

#define POLL_MC_FLAG 0x0200 // we should spew our data at PM

#define SERVICE_CAN_INT 0x0400 // we got a can interrupt, service it

#define ROTATE_TAGS_FLAG 0x0800 // rotate our flags

#define TAG_ECE 1

#define TAG_BXR 2

#define TAG_HG 3

#define TAG_SD 4

#define MAX_RESPONSE_LENGTH 10 // response length from SPI-UART devices

#define CAN_POLL_STATE_IDLE 1 // not polling ppts

#define CAN_POLL_STATE_REQUEST 2 // requesting data

#define CAN_POLL_STATE_RESPONSE 3 // waiting for response

#define CAN_POLL_STATE_NEXT 4 // response recieved

#define CAN_POLL_STATE_COMPLETE 5 // response recieved

#define CAN_POLL_INCOMPLETE 6

#define CAN_POLL_COMPLETED 7

#define GPS_STATE_MEASURE_ADC 1

#define GPS_STATE_INCOMPLETE 2

#define PM_STATE_POLLED 1

#define PM_STATE_TEMP 2

#define PM_STATE_TEMP_ALERT 3

#define PM_STATE_GPS_TIME 4

#define PM_STATE_ACCEL_X 5

#define PM_STATE_ACCEL_Y 6

#define PM_STATE_ACCEL_Z 7

#define PM_STATE_GPS_LAT 8

#define PM_STATE_GPS_LON 9

#define PM_STATE_GPS_ALT 10

#define PM_STATE_BPS_VOLTAGE 11

#define PM_STATE_BPS_TEMPERATURE 12

#define PM_STATE_BPS_BALANCE 13

#define PM_STATE_BPS_CURRENT 14

#define PM_START_CHARACTER 12

#define PM_DELIMITER ','

#define PM_END_CHARACTER ';'

#define PM_TRANSMIT_INCOMPLETE 1

#define PM_TRANSMIT_COMPLETE 2

//#define PM_STATE_PPT 6

//CAN Definitions

//---------------------------------//

//--------NODE IDENTIFIERS---------//

//---------------------------------//

#define PPT0 0x00 //MPPT boards

#define PPT1 0x01

#define PPT2 0x02

#define PPT3 0x03

#define PPT4 0x04

#define PPT5 0x05

#define PPT6 0x06

#define PPT7 0x07

#define PPT8 0x08

#define PPT9 0x09

#define PPT10 0x0A

#define PPT11 0x0B

#define PPT12 0x0C

#define PPT13 0x0D

#define PPT14 0x0E

#define PPT15 0x0F

#define DI 0x10 //driver interface board

#define TELEM 0x11 //telemetry board

//First byte to indicate a change

//of state for an MPPT

#define MPPX_CHNG_STATE 0xFE

//the second data byte in the CAN message

//indicates to the MPPT whether to

//connect or disconnect the array

#define MPP_CON 0x01

#define MPP_DISCON 0x00

//BATTERY PROTECTION SYSTEM

#define BPS_CELL_VOLT 0x94

//to get other cells, just add cell number - 1 to BPS_CELL_VOLT

//15 CELLS TOTAL

#define BPS_CELL_TEMP 0xA3

//to get other cells, just add cell number - 1 to BPS_CELL_TEMP

//15 CELLS TOTAL

#define BPS_CELL_BAL 0xB2

//to get other cells, just add cell number - 1 to BPS_CELL_BAL

//15 CELLS TOTAL

#define BPS_BATT_CUR 0xC1

//DRIVER INTERFACE

#define DI_TEXT_MESSAGE 0xC4

//to get at all of the characters, start at DI_TEXT_MESSAGE

// and add 1 to get at chars 7-13, 2 to get at chars 14-20, etc

// until 0xCF which is chars 77-79 and clear command

//TELEMETRY

#define TELEM_GPS_TIME 0xD0

#define TELEM_GPS_LOC_1 0xD1

#define TELEM_GPS_LOC_2 0xD2

#define TELEM_GPS_LOC_3 0xD3

#define TELEM_X_ACCEL 0xD4

#define TELEM_Y_ACCEL 0xD5

#define TELEM_Z_ACCEL 0xD6

#define TELEM_TEMP 0xD7

#define TELEM_ALERT 0xD8

#define TEMPERATURE_TOO_HIGH 200

#define MC_COUNTER_TOO_BIG 1000

#define CAN_TIMEOUT 10 //(ms)

// is can data little or big endian?

//#define CAN_BIG_ENDIAN

// ___ _

// /'___) ( )_ _

// | (__ _ _ ___ ___ | ,_)(_) _ ___

// | ,__)( ) ( )/' _ `\ /'___)| | | | /'_`\ /' _ `\

// | | | (_) || ( ) |( (___ | |_ | |( (_) )| ( ) |

// (_) `\___/'(_) (_)`\____)`\__)(_)`\___/'(_) (_)

// _ _

// ( )_ ( )_

// _ _ _ __ _ | ,_) _ | ,_) _ _ _ _ __ ___

// ( '_`\ ( '__)/'_`\ | | /'_`\ | | ( ) ( )( '_`\ /'__`\/',__)

// | (_) )| | ( (_) )| |_ ( (_) )| |_ | (_) || (_) )( ___/\__, \

// | ,__/'(_) `\___/'`\__)`\___/'`\__)`\__, || ,__/'`\____)(____/

// | | ( )_| || |

// (_) `\___/'(_)

#pragma idata my_isection_proto

/* Function Prototypes */

void writecSPI_UART( unsigned char, unsigned char, unsigned char);

char readcSPI_UART( unsigned char, unsigned char);

void readsSPI_UART( unsigned char, unsigned char, unsigned char *, unsigned char );

void write_byte_UART(unsigned char);

void write_str_UART(unsigned char);

void write_array_UART(unsigned char [], unsigned char);

unsigned char poll_SPI_UART( unsigned char );

void disable_interrupts(void);

void enable_interrupts(void);

void polled_loopback(unsigned char);

void initialize_CAN(void);

void init(void);

void readAccel(void);

void readTemp(void);

unsigned char ParseGPS( unsigned char* gps_buffer, unsigned char length );

unsigned char ParseBPS( unsigned char *, unsigned char);

void CANintrequest(void);

unsigned char CANpollPPT(unsigned char pptID);

void send_MC (unsigned char );

unsigned char recv_MC ( unsigned char );

unsigned char ParseMC (unsigned char *, unsigned char, unsigned char );

void write_u16_UART( unsigned int write_me );

void write_u8_UART( unsigned char write_me );

unsigned char send_PM(void);

int hatoi(char *hexStg);

unsigned char UARTIntGetTxBufferEmptySpace(void);

//void can_test(void);

//void send_to_device( unsigned char, char* );

//void receive_from_device( unsigned char );

// _ _ _ _ _

// (_ ) ( ) (_ ) ( ) ( )_

// __ | | _ | |_ _ _ | | _| | _ _ | ,_) _ _

// /'_ `\ | | /'_`\ | '_`\ /'_` ) | | /'_` | /'_` )| | /'_` )

// ( (_) | | | ( (_) )| |_) )( (_| | | | ( (_| |( (_| || |_ ( (_| |

// `\__ |(___)`\___/'(_,__/'`\__,_)(___) `\__,_)`\__,_)`\__)`\__,_)

// ( )_) |

// \___/'

#pragma idata my_isection_globo

/*

struct status

{

unsigned UARTIntTxBufferFull :1;

unsigned UARTIntTxBufferEmpty :1;

unsigned UARTIntRxBufferFull :1;

unsigned UARTIntRxBufferEmpty :1;

unsigned UARTIntRxOverFlow :1;

unsigned UARTIntRxError :1;

};

struct status vUARTIntStatus;

#pragma idata my_isection_uart1

#pragma idata my_usection_uart1

#define TX_BUFFER_SIZE 64

unsigned char vUARTIntTxBuffer[TX_BUFFER_SIZE];

#pragma idata my_isection_uart2

#pragma idata my_usection_uart2

unsigned char vUARTIntTxBufDataCnt = 0;

unsigned char vUARTIntTxBufWrPtr = 0;

unsigned char vUARTIntTxBufRdPtr = 0;

*/

char response[MAX_RESPONSE_LENGTH]; // response from SPI-UART

// polled data structure

typedef struct

{

void* data_location; // void pointer to where the data should be stored in memory

char command[ MAX_COMMAND_SIZE ]; // the command needed to request the specified information

unsigned char device_id; // the device id of the device which has the data, see above

unsigned char priority; // how frequently is the data updated (1=most, 8=least)

unsigned char designating_char; // the designating character needed by labview

unsigned char data_type; // what type should the void pointer be casted back to?

unsigned char data_length; // if the void pointer corresponded to an array, how long is it?

} polled_data_type;

// structure for holding power point tracker data

typedef struct

{

unsigned int in_voltage;

unsigned int out_voltage;

unsigned int in_current;

unsigned int out_current;

unsigned int temperature;

unsigned int max_power;

unsigned int reserved;

} ppt_type;

// structure to hold acceleration data recieved from accelerometers

struct Acceleration

{

unsigned int x;

unsigned int y;

unsigned int z;

};

char write_UART[UART_ARR_LENGTH]; // array for sending a message through UART

typedef struct cell_struct1

{

unsigned char data[4];

} cell_type_3byte;

typedef struct cell_struct2

{

unsigned char data[5];

} cell_type_4byte;

#pragma udata my_section_1

#pragma idata my_isection_1

unsigned char CAN_poll_state = CAN_POLL_STATE_IDLE;

unsigned char temperature_alert = 0;

unsigned int current_temperature = 0;

struct Acceleration accel = {0,0,0}; //acceleration data

char temp_buf[6]= {0,0,0,0,0,0}; //temperature buffer

// globals for GPS data return

unsigned char gps_latitude[ GPS_LATITUDE_LENGTH + 1 ] = {'0','0','0','0','0','0','0','0','0',0}; // ddmm.mmmm

unsigned char gps_longitude[ GPS_LONGITUDE_LENGTH + 1 ] = {'0','0','0','0','0','0','0','0','0','0',0}; // dddmm.mmmm

unsigned char gps_altitude[ GPS_ALTITUDE_LENGTH + 1 ] = {'0','0','0','0',0}; // mm.m

unsigned char gps_time[ GPS_TIME_LENGTH + 1 ] = {'0','0','0','0','0','0','0','0','0','0',0}; // hhmmss.sss

unsigned char gps_ew = '0'; // E or W

unsigned char gps_ns = '0'; // N or S

unsigned char gps_alt_unit = '0';

#pragma idata my_isection_ppt

ppt_type ppt[ MAX_PPTS ] = { {10,10,10,10,10,10,10}, // ppt0

{10,10,10,10,10,10,10}, // ppt1

{10,10,10,10,10,10,10}, // ppt2

{10,10,10,10,10,10,10}, // ppt3

{10,10,10,10,10,10,10}, // ppt4

{60,61,62,62,62,62,62}, // ppt5

{64,64,64,64,64,64,64}, // ppt6

{10,10,10,10,10,10,10} };

#pragma idata my_isection_ppt2

ppt_type ppt2[ MAX_PPTS ] = { {11,12,13, 32000 ,15,16,17}, // ppt8

{10,10,10,10,10,10,10}, // ppt9

{10,10,10,10,10,10,10}, // ppt10

{10,10,10,10,10,10,10}, // ppt11

{10,10,10,10,10,10,10}, // ppt12

{10,10,10,10,10,10,10}, // ppt13

{10,10,10,10,10,10,10}, // ppt14

{10,10,10,10,10,10,10} };

#pragma udata my_section_2

#pragma idata my_isection_2

char mc_rpm[6] = {'0','0','0','0','0',0};

char mc_throttle_input[6] = {'0','0','0','0','0',0};

char mc_regen_input[6] = {'0','0','0','0','0',0};

char mc_phase_current[7] = {'0','0','0','0','0','0',0};

char mc_supply_voltage[7] = {'0','0','0','0','0','0',0};

char mc_motor_temp[7] = {'0','0','0','0','0','0',0};

char mc_heatsink_temp[7] = {'0','0','0','0','0','0',0};

char mc_operating_status[4] = {'0','0','0',0};

char mc_observed_rotation_dir[4] = {'0','0','0',0};

char mc_fault1[4] = {'0','0','0',0};

char mc_fault2[4] = {'0','0','0',0};

char mc_fault3[4] = {'0','0','0',0};

char mc_fault4[4] = {'0','0','0',0};

char mc_throttle_enable[4] = {'0','0','0',0};

char mc_input_dir[4] = {'0','0','0',0};

char mc_actual_dir[4] = {'0','0','0',0};

char mc_speed_control[4] = {'0','0','0',0};

char mc_digital_disable_state[4] = {'0','0','0',0};

char mc_throttle_enable_state[4] = {'0','0','0',0};

char mc_forward_input_state[4] = {'0','0','0',0};

#pragma idata section_imain

#pragma idata section_umain

// GLOBAL VARIABLES FOR MAIN AND INTERRUPTS

unsigned int GPS_counter = 0; // timeout counter for GPS

unsigned int BPS_counter = 0; // timeout counter for BPS

unsigned int MC_counter = 0; // timeout counter for MC

unsigned int CAN_counter = 0; // timeout counter for CAN

unsigned int device_flags = 0x0000; // status register for device flags

unsigned int ppt_status_flags = 0x0000;

unsigned char main_state = POLL_GPS;

unsigned long int unreal_time_clock = 0;

#pragma idata section_isection_3

#pragma udata section_usection_3

unsigned char mc_state = MC_STATE_SEND;

unsigned char pm_state = PM_STATE_POLLED;

unsigned int wait_counter = 0;

char cell_voltage[ NUM_BATTERIES ][4] = { {'0','0','0',0},

{'0','0','0',0},

{'0','0','0',0},

{'0','0','0',0},

{'0','0','0',0},

{'0','0','0',0},

{'0','0','0',0},

{'0','0','0',0},

{'0','0','0',0},

{'0','0','0',0},

{'0','0','0',0},

{'0','0','0',0},

{'0','0','0',0},

{'0','0','0',0},

{'0','0','0',0} };

char cell_temperature[ NUM_BATTERIES ][4] = { {'0','0','0',0},

{'0','0','0',0},

{'0','0','0',0},

{'0','0','0',0},

{'0','0','0',0},

{'0','0','0',0},

{'0','0','0',0},

{'0','0','0',0},

{'0','0','0',0},

{'0','0','0',0},

{'0','0','0',0},

{'0','0','0',0},

{'0','0','0',0},

{'0','0','0',0},

{'0','0','0',0} };

char battery_current[4] = {'0','0','0',0};

char cell_balance[5] = {'0','0','0','0',0};

#define ROTATE_TEXT_MESSAGES

#pragma idata section_itext_message

#pragma udata section_utext_message

char di_text_message[12][7] = { {' ',' ','_','_',' ',' ',' '},

{' ',' ',' ',' ',' ',' ',' '},

{' ',' ',' ',' ',' ',' ',' '},

/* __ */ {'|',' ',' ','|','-','-','.'},

/* | |--.--.--.----. */ {'-','-','.','-','-','.','-'},

/* | _ |_ _| _| */ {'-','-','-','.',' ',' ','|'},

/* |_____|__.__|__|bxr*/ {' ',' ','_',' ',' ','|','_'},

{' ',' ',' ','_','|',' ',' '},

{' ','_','|',' ',' ','|','_'},

{'_','_','_','_','|','_','_'},

{'.','_','_','|','_','_','|'},

{'b','x','r',0 ,0 ,0 ,0 } };

#pragma idata section_ibxr_tag

#pragma udata section_ubxr_tag

const rom char bxr_tag[12][7] = { {' ',' ','_','_',' ',' ',' '},

{' ',' ',' ',' ',' ',' ',' '},

{' ',' ',' ',' ',' ',' ',' '},

/* __ */ {'|',' ',' ','|','-','-','.'},

/* | |--.--.--.----. */ {'-','-','.','-','-','.','-'},

/* | _ |_ _| _| */ {'-','-','-','.',' ',' ','|'},

/* |_____|__.__|__|bxr*/ {' ',' ','_',' ',' ','|','_'},

{' ',' ',' ','_','|',' ',' '},

{' ','_','|',' ',' ','|','_'},

{'_','_','_','_','|','_','_'},

{'.','_','_','|','_','_','|'},

{'b','x','r',0 ,0 ,0 ,0 } };

#pragma idata section_iece

#pragma udata section_uece

const rom char ece_tag[12][7] = { {'_','/',' ','_','_',' ','`'},

{'_','/',' ','_','_','_','`'},

{'/',' ','_','_',' ','`','`'},

/* _/ __ \_/ ___\/ __ \ */ {' ',' ','_','_','_','/','`'},

/* \ ___/\ \__\ ___/ */ {' ',' ','`','_','_','`',' '},

/* \___ >\___ >__ > */ {' ','_','_','_','/',' ','`'},

/* \/ \/ece\/ */ {'_','_','_',' ',' ','>','`'},

{'_','_','_',' ',' ','>','_'},

{'_',' ',' ','>',' ',' ',' '},

{' ',' ','`','/',' ',' ',' '},

{' ',' ','`','/','e','c','e'},

{'`','/',' ',0 ,0 ,0 ,0 } };

#pragma idata section_isd

#pragma udata section_usd

const rom char sd_tag[12][7] = { {' ',' ',' ',' ',' ',' ',' '},

{' ',' ',' ',' ',' ',' ',' '},

{' ','|',' ',' ',' ',' ',' '},

/* | */ {' ',' ',' ',' ','_','_','|'},

/* __| _` | */ {' ',' ',' ',' ','_','`',' '},

/* \__ \ ( | */ {'|',' ',' ',' ',' ',' ',' '},

/* ____/_)\__,_|s.d. */ {' ','`','_','_',' ','`',' '},

{' ',' ','(',' ',' ',' ','|'},

{' ',' ',' ',' ',' ',' ',' '},

{'_','_','_','_','/','_',')'},

{'`','_','_',',','_','|','s'},

{'.','d','.',0 ,0 ,0 ,0 } };

#pragma idata section_ihg

#pragma udata section_uhg

const rom char hg_tag[12][7] = { {' ',' ',' ',' ','/',' ','/'},

{' ',' ','_','_','_',' ','_'},

{'/',' ','/',' ',' ',' ',' '},

{' ',' ','/',' ','_',' ','`'},

/* / / ___ _/ / */ {'/',' ','_',' ','`','/','_'},

/* / _ \/ _ `/_/ */ {'/',' ',' ',' ',' ',' ',' '},

/* /_//_/\_, (_) */ {'/','_','/','/','_','/','`'},

/* /___/hg! */ {'_',',',' ','(','_',')',' '},

{' ',' ',' ',' ',' ',' ',' '},

{' ',' ',' ',' ','/','_','_'},

{'_','/','h','g','!',' ',' '},

{' ',' ',' ',0 ,0 ,0 ,0 } };

#pragma idata section_ipd

#pragma udata section_upd

// _ _ _ _ _

// (_ ) (_ ) ( ) ( ) ( )_

// _ _ _ | | | | __ _| | _| | _ _ | ,_) _ _

// ( '_`\ /'_`\ | | | | /'__`\ /'_` | /'_` | /'_` )| | /'_` )

// | (_) )( (_) ) | | | | ( ___/( (_| | ( (_| |( (_| || |_ ( (_| |

// | ,__/'`\___/'(___)(___)`\____)`\__,_) `\__,_)`\__,_)`\__)`\__,_)

// | |

// (_)

#pragma idata section_ipolled

#pragma udata section_upolled

const rom polled_data_type polled_data[ ALL_DATA_SIZE ] =

{

/* ------------------------------------------------- POWER POINT TRACKERS ----------------------------------------------------- */

/* data location, command, device_id, p, designating char, type, size */

{ (void*)&(ppt[0].in_voltage), {DC_COMMAND_REQUEST, DC_PPT0_IN_VOLTAGE, 0, 0}, DEVID_PPT0, 1, DC_PPT0_IN_VOLTAGE, TYPE_INT, 1 }, //0

{ (void*)&(ppt[0].out_voltage), {DC_COMMAND_REQUEST, DC_PPT0_OUT_VOLTAGE, 0, 0}, DEVID_PPT0, 1, DC_PPT0_OUT_VOLTAGE, TYPE_INT, 1 }, //1

{ (void*)&(ppt[0].in_current), {DC_COMMAND_REQUEST, DC_PPT0_IN_CURRENT, 0, 0}, DEVID_PPT0, 1, DC_PPT0_IN_CURRENT, TYPE_INT, 1 }, //2

{ (void*)&(ppt[0].out_current), {DC_COMMAND_REQUEST, DC_PPT0_OUT_CURRENT, 0, 0}, DEVID_PPT0, 1, DC_PPT0_OUT_CURRENT, TYPE_INT, 1 }, //3

{ (void*)&(ppt[0].temperature), {DC_COMMAND_REQUEST, DC_PPT0_TEMPERATURE, 0, 0}, DEVID_PPT0, 1, DC_PPT0_TEMPERATURE, TYPE_INT, 1 }, //4

{ (void*)&(ppt[0].max_power), {DC_COMMAND_REQUEST, DC_PPT0_MAX_POWER, 0, 0}, DEVID_PPT0, 1, DC_PPT0_MAX_POWER, TYPE_INT, 1 }, //5

{ (void*)&(ppt[0].reserved), {DC_COMMAND_REQUEST, DC_PPT0_RESERVED, 0, 0}, DEVID_PPT0, 1, DC_PPT0_RESERVED, TYPE_INT, 1 }, //6

{ (void*)&(ppt[0].reserved), {0,0,0,0}, 0, 0, 0, 0, 0 }, //7

{ (void*)&(ppt[1].in_voltage), {DC_COMMAND_REQUEST, DC_PPT1_IN_VOLTAGE, 0, 0}, DEVID_PPT1, 1, DC_PPT1_IN_VOLTAGE, TYPE_INT, 1 }, //8

{ (void*)&(ppt[1].out_voltage), {DC_COMMAND_REQUEST, DC_PPT1_OUT_VOLTAGE, 0, 0}, DEVID_PPT1, 1, DC_PPT1_OUT_VOLTAGE, TYPE_INT, 1 }, //9

{ (void*)&(ppt[1].in_current), {DC_COMMAND_REQUEST, DC_PPT1_IN_CURRENT, 0, 0}, DEVID_PPT1, 1, DC_PPT1_IN_CURRENT, TYPE_INT, 1 }, //10

{ (void*)&(ppt[1].out_current), {DC_COMMAND_REQUEST, DC_PPT1_OUT_CURRENT, 0, 0}, DEVID_PPT1, 1, DC_PPT1_OUT_CURRENT, TYPE_INT, 1 }, //11

{ (void*)&(ppt[1].temperature), {DC_COMMAND_REQUEST, DC_PPT1_TEMPERATURE, 0, 0}, DEVID_PPT1, 1, DC_PPT1_TEMPERATURE, TYPE_INT, 1 }, //12

{ (void*)&(ppt[1].max_power), {DC_COMMAND_REQUEST, DC_PPT1_MAX_POWER, 0, 0}, DEVID_PPT1, 1, DC_PPT1_MAX_POWER, TYPE_INT, 1 }, //13

{ (void*)&(ppt[1].reserved), {DC_COMMAND_REQUEST, DC_PPT1_RESERVED, 0, 0}, DEVID_PPT1, 1, DC_PPT1_RESERVED, TYPE_INT, 1 }, //14

{ (void*)&(ppt[1].reserved), {0,0,0,0}, 0, 0, 0, 0, 0 }, //15

{ (void*)&(ppt[2].in_voltage), {DC_COMMAND_REQUEST, DC_PPT2_IN_VOLTAGE, 0, 0}, DEVID_PPT2, 1, DC_PPT2_IN_VOLTAGE, TYPE_INT, 1 }, //16

{ (void*)&(ppt[2].out_voltage), {DC_COMMAND_REQUEST, DC_PPT2_OUT_VOLTAGE, 0, 0}, DEVID_PPT2, 1, DC_PPT2_OUT_VOLTAGE, TYPE_INT, 1 }, //17

{ (void*)&(ppt[2].in_current), {DC_COMMAND_REQUEST, DC_PPT2_IN_CURRENT, 0, 0}, DEVID_PPT2, 1, DC_PPT2_IN_CURRENT, TYPE_INT, 1 }, //18

{ (void*)&(ppt[2].out_current), {DC_COMMAND_REQUEST, DC_PPT2_OUT_CURRENT, 0, 0}, DEVID_PPT2, 1, DC_PPT2_OUT_CURRENT, TYPE_INT, 1 }, //19

{ (void*)&(ppt[2].temperature), {DC_COMMAND_REQUEST, DC_PPT2_TEMPERATURE, 0, 0}, DEVID_PPT2, 1, DC_PPT2_TEMPERATURE, TYPE_INT, 1 }, //20

{ (void*)&(ppt[2].max_power), {DC_COMMAND_REQUEST, DC_PPT2_MAX_POWER, 0, 0}, DEVID_PPT2, 1, DC_PPT2_MAX_POWER, TYPE_INT, 1 }, //21

{ (void*)&(ppt[2].reserved), {DC_COMMAND_REQUEST, DC_PPT2_RESERVED, 0, 0}, DEVID_PPT2, 1, DC_PPT2_RESERVED, TYPE_INT, 1 }, //22

{ (void*)&(ppt[2].reserved), {0,0,0,0}, 0, 0, 0, 0, 0 }, //23

{ (void*)&(ppt[3].in_voltage), {DC_COMMAND_REQUEST, DC_PPT3_IN_VOLTAGE, 0, 0}, DEVID_PPT3, 1, DC_PPT3_IN_VOLTAGE, TYPE_INT, 1 }, //24

{ (void*)&(ppt[3].out_voltage), {DC_COMMAND_REQUEST, DC_PPT3_OUT_VOLTAGE, 0, 0}, DEVID_PPT3, 1, DC_PPT3_OUT_VOLTAGE, TYPE_INT, 1 }, //25

{ (void*)&(ppt[3].in_current), {DC_COMMAND_REQUEST, DC_PPT3_IN_CURRENT, 0, 0}, DEVID_PPT3, 1, DC_PPT3_IN_CURRENT, TYPE_INT, 1 }, //26

{ (void*)&(ppt[3].out_current), {DC_COMMAND_REQUEST, DC_PPT3_OUT_CURRENT, 0, 0}, DEVID_PPT3, 1, DC_PPT3_OUT_CURRENT, TYPE_INT, 1 }, //27

{ (void*)&(ppt[3].temperature), {DC_COMMAND_REQUEST, DC_PPT3_TEMPERATURE, 0, 0}, DEVID_PPT3, 1, DC_PPT3_TEMPERATURE, TYPE_INT, 1 }, //28

{ (void*)&(ppt[3].max_power), {DC_COMMAND_REQUEST, DC_PPT3_MAX_POWER, 0, 0}, DEVID_PPT3, 1, DC_PPT3_MAX_POWER, TYPE_INT, 1 }, //29

{ (void*)&(ppt[3].reserved), {DC_COMMAND_REQUEST, DC_PPT3_RESERVED, 0, 0}, DEVID_PPT3, 1, DC_PPT3_RESERVED, TYPE_INT, 1 }, //30

{ (void*)&(ppt[3].reserved), {0,0,0,0}, 0, 0, 0, 0, 0 }, //31

{ (void*)&(ppt[4].in_voltage), {DC_COMMAND_REQUEST, DC_PPT4_IN_VOLTAGE, 0, 0}, DEVID_PPT4, 1, DC_PPT4_IN_VOLTAGE, TYPE_INT, 1 }, //32

{ (void*)&(ppt[4].out_voltage), {DC_COMMAND_REQUEST, DC_PPT4_OUT_VOLTAGE, 0, 0}, DEVID_PPT4, 1, DC_PPT4_OUT_VOLTAGE, TYPE_INT, 1 }, //33

{ (void*)&(ppt[4].in_current), {DC_COMMAND_REQUEST, DC_PPT4_IN_CURRENT, 0, 0}, DEVID_PPT4, 1, DC_PPT4_IN_CURRENT, TYPE_INT, 1 }, //34

{ (void*)&(ppt[4].out_current), {DC_COMMAND_REQUEST, DC_PPT4_OUT_CURRENT, 0, 0}, DEVID_PPT4, 1, DC_PPT4_OUT_CURRENT, TYPE_INT, 1 }, //35

{ (void*)&(ppt[4].temperature), {DC_COMMAND_REQUEST, DC_PPT4_TEMPERATURE, 0, 0}, DEVID_PPT4, 1, DC_PPT4_TEMPERATURE, TYPE_INT, 1 }, //36

{ (void*)&(ppt[4].max_power), {DC_COMMAND_REQUEST, DC_PPT4_MAX_POWER, 0, 0}, DEVID_PPT4, 1, DC_PPT4_MAX_POWER, TYPE_INT, 1 }, //37

{ (void*)&(ppt[4].reserved), {DC_COMMAND_REQUEST, DC_PPT4_RESERVED, 0, 0}, DEVID_PPT4, 1, DC_PPT4_RESERVED, TYPE_INT, 1 }, //38

{ (void*)&(ppt[4].reserved), {0,0,0,0}, 0, 0, 0, 0, 0 }, //39

{ (void*)&(ppt[5].in_voltage), {DC_COMMAND_REQUEST, DC_PPT5_IN_VOLTAGE, 0, 0}, DEVID_PPT5, 1, DC_PPT5_IN_VOLTAGE, TYPE_INT, 1 }, //40

{ (void*)&(ppt[5].out_voltage), {DC_COMMAND_REQUEST, DC_PPT5_OUT_VOLTAGE, 0, 0}, DEVID_PPT5, 1, DC_PPT5_OUT_VOLTAGE, TYPE_INT, 1 }, //41

{ (void*)&(ppt[5].in_current), {DC_COMMAND_REQUEST, DC_PPT5_IN_CURRENT, 0, 0}, DEVID_PPT5, 1, DC_PPT5_IN_CURRENT, TYPE_INT, 1 }, //42

{ (void*)&(ppt[5].out_current), {DC_COMMAND_REQUEST, DC_PPT5_OUT_CURRENT, 0, 0}, DEVID_PPT5, 1, DC_PPT5_OUT_CURRENT, TYPE_INT, 1 }, //43

{ (void*)&(ppt[5].temperature), {DC_COMMAND_REQUEST, DC_PPT5_TEMPERATURE, 0, 0}, DEVID_PPT5, 1, DC_PPT5_TEMPERATURE, TYPE_INT, 1 }, //44

{ (void*)&(ppt[5].max_power), {DC_COMMAND_REQUEST, DC_PPT5_MAX_POWER, 0, 0}, DEVID_PPT5, 1, DC_PPT5_MAX_POWER, TYPE_INT, 1 }, //45

{ (void*)&(ppt[5].reserved), {DC_COMMAND_REQUEST, DC_PPT5_RESERVED, 0, 0}, DEVID_PPT5, 1, DC_PPT5_RESERVED, TYPE_INT, 1 }, //46

{ (void*)&(ppt[5].reserved), {0,0,0,0}, 0, 0, 0, 0, 0 }, //47

/* data location, command, device_id, p, designating char, type, size */

{ (void*)&(ppt[6].in_voltage), {DC_COMMAND_REQUEST, DC_PPT6_IN_VOLTAGE, 0, 0}, DEVID_PPT6, 1, DC_PPT6_IN_VOLTAGE, TYPE_INT, 1 },//48

{ (void*)&(ppt[6].out_voltage), {DC_COMMAND_REQUEST, DC_PPT6_OUT_VOLTAGE, 0, 0}, DEVID_PPT6, 1, DC_PPT6_OUT_VOLTAGE, TYPE_INT, 1 },//49

{ (void*)&(ppt[6].in_current), {DC_COMMAND_REQUEST, DC_PPT6_IN_CURRENT, 0, 0}, DEVID_PPT6, 1, DC_PPT6_IN_CURRENT, TYPE_INT, 1 },//50

{ (void*)&(ppt[6].out_current), {DC_COMMAND_REQUEST, DC_PPT6_OUT_CURRENT, 0, 0}, DEVID_PPT6, 1, DC_PPT6_OUT_CURRENT, TYPE_INT, 1 },//51

{ (void*)&(ppt[6].temperature), {DC_COMMAND_REQUEST, DC_PPT6_TEMPERATURE, 0, 0}, DEVID_PPT6, 1, DC_PPT6_TEMPERATURE, TYPE_INT, 1 },//52

{ (void*)&(ppt[6].max_power), {DC_COMMAND_REQUEST, DC_PPT6_MAX_POWER, 0, 0}, DEVID_PPT6, 1, DC_PPT6_MAX_POWER, TYPE_INT, 1 },//53

{ (void*)&(ppt[6].reserved), {DC_COMMAND_REQUEST, DC_PPT6_RESERVED, 0, 0}, DEVID_PPT6, 1, DC_PPT6_RESERVED, TYPE_INT, 1 },//54

{ (void*)&(ppt[6].reserved), {0,0,0,0}, 0, 0, 0, 0, 0 },//55

{ (void*)&(ppt[7].in_voltage), {DC_COMMAND_REQUEST, DC_PPT7_IN_VOLTAGE, 0, 0}, DEVID_PPT7, 1, DC_PPT7_IN_VOLTAGE, TYPE_INT, 1 },//56

{ (void*)&(ppt[7].out_voltage), {DC_COMMAND_REQUEST, DC_PPT7_OUT_VOLTAGE, 0, 0}, DEVID_PPT7, 1, DC_PPT7_OUT_VOLTAGE, TYPE_INT, 1 },//57

{ (void*)&(ppt[7].in_current), {DC_COMMAND_REQUEST, DC_PPT7_IN_CURRENT, 0, 0}, DEVID_PPT7, 1, DC_PPT7_IN_CURRENT, TYPE_INT, 1 },//58

{ (void*)&(ppt[7].out_current), {DC_COMMAND_REQUEST, DC_PPT7_OUT_CURRENT, 0, 0}, DEVID_PPT7, 1, DC_PPT7_OUT_CURRENT, TYPE_INT, 1 },//59

{ (void*)&(ppt[7].temperature), {DC_COMMAND_REQUEST, DC_PPT7_TEMPERATURE, 0, 0}, DEVID_PPT7, 1, DC_PPT7_TEMPERATURE, TYPE_INT, 1 },//60

{ (void*)&(ppt[7].max_power), {DC_COMMAND_REQUEST, DC_PPT7_MAX_POWER, 0, 0}, DEVID_PPT7, 1, DC_PPT7_MAX_POWER, TYPE_INT, 1 },//61

{ (void*)&(ppt[7].reserved), {DC_COMMAND_REQUEST, DC_PPT7_RESERVED, 0, 0}, DEVID_PPT7, 1, DC_PPT7_RESERVED, TYPE_INT, 1 },//62

{ (void*)&(ppt[7].reserved), {0,0,0,0}, 0, 0, 0, 0, 0 },//63

{ (void*)&(ppt2[0].in_voltage), {DC_COMMAND_REQUEST, DC_PPT8_IN_VOLTAGE, 0, 0}, DEVID_PPT8, 1, DC_PPT8_IN_VOLTAGE, TYPE_INT, 1 },//64

{ (void*)&(ppt2[0].out_voltage), {DC_COMMAND_REQUEST, DC_PPT8_OUT_VOLTAGE, 0, 0}, DEVID_PPT8, 1, DC_PPT8_OUT_VOLTAGE, TYPE_INT, 1 },//65

{ (void*)&(ppt2[0].in_current), {DC_COMMAND_REQUEST, DC_PPT8_IN_CURRENT, 0, 0}, DEVID_PPT8, 1, DC_PPT8_IN_CURRENT, TYPE_INT, 1 },//66

{ (void*)&(ppt2[0].out_current), {DC_COMMAND_REQUEST, DC_PPT8_OUT_CURRENT, 0, 0}, DEVID_PPT8, 1, DC_PPT8_OUT_CURRENT, TYPE_INT, 1 },//67

{ (void*)&(ppt2[0].temperature), {DC_COMMAND_REQUEST, DC_PPT8_TEMPERATURE, 0, 0}, DEVID_PPT8, 1, DC_PPT8_TEMPERATURE, TYPE_INT, 1 },//68

{ (void*)&(ppt2[0].max_power), {DC_COMMAND_REQUEST, DC_PPT8_MAX_POWER, 0, 0}, DEVID_PPT8, 1, DC_PPT8_MAX_POWER, TYPE_INT, 1 },//69

{ (void*)&(ppt2[0].reserved), {DC_COMMAND_REQUEST, DC_PPT8_RESERVED, 0, 0}, DEVID_PPT8, 1, DC_PPT8_RESERVED, TYPE_INT, 1 },//70

{ (void*)&(ppt2[0].reserved), {0,0,0,0}, 0, 0, 0, 0, 0 },//71

{ (void*)&(ppt2[1].in_voltage), {DC_COMMAND_REQUEST, DC_PPT9_IN_VOLTAGE, 0, 0}, DEVID_PPT9, 1, DC_PPT9_IN_VOLTAGE, TYPE_INT, 1 },//72

{ (void*)&(ppt2[1].out_voltage), {DC_COMMAND_REQUEST, DC_PPT9_OUT_VOLTAGE, 0, 0}, DEVID_PPT9, 1, DC_PPT9_OUT_VOLTAGE, TYPE_INT, 1 },//73

{ (void*)&(ppt2[1].in_current), {DC_COMMAND_REQUEST, DC_PPT9_IN_CURRENT, 0, 0}, DEVID_PPT9, 1, DC_PPT9_IN_CURRENT, TYPE_INT, 1 },//74

{ (void*)&(ppt2[1].out_current), {DC_COMMAND_REQUEST, DC_PPT9_OUT_CURRENT, 0, 0}, DEVID_PPT9, 1, DC_PPT9_OUT_CURRENT, TYPE_INT, 1 },//75

{ (void*)&(ppt2[1].temperature), {DC_COMMAND_REQUEST, DC_PPT9_TEMPERATURE, 0, 0}, DEVID_PPT9, 1, DC_PPT9_TEMPERATURE, TYPE_INT, 1 },//76

{ (void*)&(ppt2[1].max_power), {DC_COMMAND_REQUEST, DC_PPT9_MAX_POWER, 0, 0}, DEVID_PPT9, 1, DC_PPT9_MAX_POWER, TYPE_INT, 1 },//77

{ (void*)&(ppt2[1].reserved), {DC_COMMAND_REQUEST, DC_PPT9_RESERVED, 0, 0}, DEVID_PPT9, 1, DC_PPT9_RESERVED, TYPE_INT, 1 },//78

{ (void*)&(ppt2[1].reserved), {0,0,0,0}, 0, 0, 0, 0, 0 },//79

{ (void*)&(ppt2[2].in_voltage), {DC_COMMAND_REQUEST, DC_PPT10_IN_VOLTAGE, 0, 0}, DEVID_PPT10, 1, DC_PPT10_IN_VOLTAGE, TYPE_INT, 1 },//80

{ (void*)&(ppt2[2].out_voltage), {DC_COMMAND_REQUEST, DC_PPT10_OUT_VOLTAGE, 0, 0}, DEVID_PPT10, 1, DC_PPT10_OUT_VOLTAGE, TYPE_INT, 1 },//81

{ (void*)&(ppt2[2].in_current), {DC_COMMAND_REQUEST, DC_PPT10_IN_CURRENT, 0, 0}, DEVID_PPT10, 1, DC_PPT10_IN_CURRENT, TYPE_INT, 1 },//82

{ (void*)&(ppt2[2].out_current), {DC_COMMAND_REQUEST, DC_PPT10_OUT_CURRENT, 0, 0}, DEVID_PPT10, 1, DC_PPT10_OUT_CURRENT, TYPE_INT, 1 },//83

{ (void*)&(ppt2[2].temperature), {DC_COMMAND_REQUEST, DC_PPT10_TEMPERATURE, 0, 0}, DEVID_PPT10, 1, DC_PPT10_TEMPERATURE, TYPE_INT, 1 },//84

{ (void*)&(ppt2[2].max_power), {DC_COMMAND_REQUEST, DC_PPT10_MAX_POWER, 0, 0}, DEVID_PPT10, 1, DC_PPT10_MAX_POWER, TYPE_INT, 1 },//85

{ (void*)&(ppt2[2].reserved), {DC_COMMAND_REQUEST, DC_PPT10_RESERVED, 0, 0}, DEVID_PPT10, 1, DC_PPT10_RESERVED, TYPE_INT, 1 },//86

{ (void*)&(ppt2[2].reserved), {0,0,0,0}, 0, 0, 0, 0, 0 },//87

/* data location, command, device_id, p, designating char, type, size */

{ (void*)&(ppt2[3].in_voltage), {DC_COMMAND_REQUEST, DC_PPT11_IN_VOLTAGE, 0, 0}, DEVID_PPT11, 1, DC_PPT11_IN_VOLTAGE, TYPE_INT, 1 },//88

{ (void*)&(ppt2[3].out_voltage), {DC_COMMAND_REQUEST, DC_PPT11_OUT_VOLTAGE, 0, 0}, DEVID_PPT11, 1, DC_PPT11_OUT_VOLTAGE, TYPE_INT, 1 },//89

{ (void*)&(ppt2[3].in_current), {DC_COMMAND_REQUEST, DC_PPT11_IN_CURRENT, 0, 0}, DEVID_PPT11, 1, DC_PPT11_IN_CURRENT, TYPE_INT, 1 },//90

{ (void*)&(ppt2[3].out_current), {DC_COMMAND_REQUEST, DC_PPT11_OUT_CURRENT, 0, 0}, DEVID_PPT11, 1, DC_PPT11_OUT_CURRENT, TYPE_INT, 1 },//91

{ (void*)&(ppt2[3].temperature), {DC_COMMAND_REQUEST, DC_PPT11_TEMPERATURE, 0, 0}, DEVID_PPT11, 1, DC_PPT11_TEMPERATURE, TYPE_INT, 1 },//92

{ (void*)&(ppt2[3].max_power), {DC_COMMAND_REQUEST, DC_PPT11_MAX_POWER, 0, 0}, DEVID_PPT11, 1, DC_PPT11_MAX_POWER, TYPE_INT, 1 },//93

{ (void*)&(ppt2[3].reserved), {DC_COMMAND_REQUEST, DC_PPT11_RESERVED, 0, 0}, DEVID_PPT11, 1, DC_PPT11_RESERVED, TYPE_INT, 1 },//94

{ (void*)&(ppt2[3].reserved), {0,0,0,0}, 0, 0, 0, 0, 0 },//95

{ (void*)&(ppt2[4].in_voltage), {DC_COMMAND_REQUEST, DC_PPT12_IN_VOLTAGE, 0, 0}, DEVID_PPT12, 1, DC_PPT12_IN_VOLTAGE, TYPE_INT, 1 },//96

{ (void*)&(ppt2[4].out_voltage), {DC_COMMAND_REQUEST, DC_PPT12_OUT_VOLTAGE, 0, 0}, DEVID_PPT12, 1, DC_PPT12_OUT_VOLTAGE, TYPE_INT, 1 },//97

{ (void*)&(ppt2[4].in_current), {DC_COMMAND_REQUEST, DC_PPT12_IN_CURRENT, 0, 0}, DEVID_PPT12, 1, DC_PPT12_IN_CURRENT, TYPE_INT, 1 },//98

{ (void*)&(ppt2[4].out_current), {DC_COMMAND_REQUEST, DC_PPT12_OUT_CURRENT, 0, 0}, DEVID_PPT12, 1, DC_PPT12_OUT_CURRENT, TYPE_INT, 1 },//99

{ (void*)&(ppt2[4].temperature), {DC_COMMAND_REQUEST, DC_PPT12_TEMPERATURE, 0, 0}, DEVID_PPT12, 1, DC_PPT12_TEMPERATURE, TYPE_INT, 1 },//100

{ (void*)&(ppt2[4].max_power), {DC_COMMAND_REQUEST, DC_PPT12_MAX_POWER, 0, 0}, DEVID_PPT12, 1, DC_PPT12_MAX_POWER, TYPE_INT, 1 },//101

{ (void*)&(ppt2[4].reserved), {DC_COMMAND_REQUEST, DC_PPT12_RESERVED, 0, 0}, DEVID_PPT12, 1, DC_PPT12_RESERVED, TYPE_INT, 1 },//102

{ (void*)&(ppt2[4].reserved), {0,0,0,0}, 0, 0, 0, 0, 0 },//103

{ (void*)&(ppt2[5].in_voltage), {DC_COMMAND_REQUEST, DC_PPT13_IN_VOLTAGE, 0, 0}, DEVID_PPT13, 1, DC_PPT13_IN_VOLTAGE, TYPE_INT, 1 },//104

{ (void*)&(ppt2[5].out_voltage), {DC_COMMAND_REQUEST, DC_PPT13_OUT_VOLTAGE, 0, 0}, DEVID_PPT13, 1, DC_PPT13_OUT_VOLTAGE, TYPE_INT, 1 },//105

{ (void*)&(ppt2[5].in_current), {DC_COMMAND_REQUEST, DC_PPT13_IN_CURRENT, 0, 0}, DEVID_PPT13, 1, DC_PPT13_IN_CURRENT, TYPE_INT, 1 },//106

{ (void*)&(ppt2[5].out_current), {DC_COMMAND_REQUEST, DC_PPT13_OUT_CURRENT, 0, 0}, DEVID_PPT13, 1, DC_PPT13_OUT_CURRENT, TYPE_INT, 1 },//107

{ (void*)&(ppt2[5].temperature), {DC_COMMAND_REQUEST, DC_PPT13_TEMPERATURE, 0, 0}, DEVID_PPT13, 1, DC_PPT13_TEMPERATURE, TYPE_INT, 1 },//108

{ (void*)&(ppt2[5].max_power), {DC_COMMAND_REQUEST, DC_PPT13_MAX_POWER, 0, 0}, DEVID_PPT13, 1, DC_PPT13_MAX_POWER, TYPE_INT, 1 },//109

{ (void*)&(ppt2[5].reserved), {DC_COMMAND_REQUEST, DC_PPT13_RESERVED, 0, 0}, DEVID_PPT13, 1, DC_PPT13_RESERVED, TYPE_INT, 1 },//110

{ (void*)&(ppt2[5].reserved), {0,0,0,0}, 0, 0, 0, 0, 0 },//111

{ (void*)&(ppt2[6].in_voltage), {DC_COMMAND_REQUEST, DC_PPT14_IN_VOLTAGE, 0, 0}, DEVID_PPT14, 1, DC_PPT14_IN_VOLTAGE, TYPE_INT, 1 },//112

{ (void*)&(ppt2[6].out_voltage), {DC_COMMAND_REQUEST, DC_PPT14_OUT_VOLTAGE, 0, 0}, DEVID_PPT14, 1, DC_PPT14_OUT_VOLTAGE, TYPE_INT, 1 },//113

{ (void*)&(ppt2[6].in_current), {DC_COMMAND_REQUEST, DC_PPT14_IN_CURRENT, 0, 0}, DEVID_PPT14, 1, DC_PPT14_IN_CURRENT, TYPE_INT, 1 },//114

{ (void*)&(ppt2[6].out_current), {DC_COMMAND_REQUEST, DC_PPT14_OUT_CURRENT, 0, 0}, DEVID_PPT14, 1, DC_PPT14_OUT_CURRENT, TYPE_INT, 1 },//115

{ (void*)&(ppt2[6].temperature), {DC_COMMAND_REQUEST, DC_PPT14_TEMPERATURE, 0, 0}, DEVID_PPT14, 1, DC_PPT14_TEMPERATURE, TYPE_INT, 1 },//116

{ (void*)&(ppt2[6].max_power), {DC_COMMAND_REQUEST, DC_PPT14_MAX_POWER, 0, 0}, DEVID_PPT14, 1, DC_PPT14_MAX_POWER, TYPE_INT, 1 },//117

{ (void*)&(ppt2[6].reserved), {DC_COMMAND_REQUEST, DC_PPT14_RESERVED, 0, 0}, DEVID_PPT14, 1, DC_PPT14_RESERVED, TYPE_INT, 1 },//118

{ (void*)&(ppt2[6].reserved), {0,0,0,0}, 0, 0, 0, 0, 0 },//119

{ (void*)&(ppt2[7].in_voltage), {DC_COMMAND_REQUEST, DC_PPT15_IN_VOLTAGE, 0, 0}, DEVID_PPT15, 1, DC_PPT15_IN_VOLTAGE, TYPE_INT, 1 },//120

{ (void*)&(ppt2[7].out_voltage), {DC_COMMAND_REQUEST, DC_PPT15_OUT_VOLTAGE, 0, 0}, DEVID_PPT15, 1, DC_PPT15_OUT_VOLTAGE, TYPE_INT, 1 },//121

{ (void*)&(ppt2[7].in_current), {DC_COMMAND_REQUEST, DC_PPT15_IN_CURRENT, 0, 0}, DEVID_PPT15, 1, DC_PPT15_IN_CURRENT, TYPE_INT, 1 },//122

{ (void*)&(ppt2[7].out_current), {DC_COMMAND_REQUEST, DC_PPT15_OUT_CURRENT, 0, 0}, DEVID_PPT15, 1, DC_PPT15_OUT_CURRENT, TYPE_INT, 1 },//123

{ (void*)&(ppt2[7].temperature), {DC_COMMAND_REQUEST, DC_PPT15_TEMPERATURE, 0, 0}, DEVID_PPT15, 1, DC_PPT15_TEMPERATURE, TYPE_INT, 1 },//124

{ (void*)&(ppt2[7].max_power), {DC_COMMAND_REQUEST, DC_PPT15_MAX_POWER, 0, 0}, DEVID_PPT15, 1, DC_PPT15_MAX_POWER, TYPE_INT, 1 },//125

{ (void*)&(ppt2[7].reserved), {DC_COMMAND_REQUEST, DC_PPT15_RESERVED, 0, 0}, DEVID_PPT15, 1, DC_PPT15_RESERVED, TYPE_INT, 1 },//126

{ (void*)&(ppt2[7].reserved), {0,0,0,0}, 0, 0, 0, 0, 0 },//127

/* ------------------------------------------------- MOTOR CONTROLLER --------------------------------------------------- */

/* data location, command, device_id, p, designating char, data_type, data_size */

{ (void*)mc_rpm, {'0','C','?', CR}, DEVID_MOTOR, 1, DC_MC_RPM, TYPE_ASCII_DECIMAL, 5 },//128

{ (void*)mc_throttle_input, {'1','7','?', CR}, DEVID_MOTOR, 1, DC_MC_THROTTLE_INPUT, TYPE_ASCII_DECIMAL, 5 },//129

{ (void*)mc_regen_input, {'1','8','?', CR}, DEVID_MOTOR, 1, DC_MC_REGEN_INPUT, TYPE_ASCII_DECIMAL, 5 },//130

{ (void*)mc_phase_current, {'6','1','?', CR}, DEVID_MOTOR, 1, DC_MC_PHASE_CURRENT, TYPE_ASCII_DECIMAL, 6 },//131

{ (void*)mc_supply_voltage, {'6','4','?', CR}, DEVID_MOTOR, 1, DC_MC_SUPPLY_VOLTAGE, TYPE_ASCII_DECIMAL, 6 },//132

{ (void*)mc_motor_temp, {'6','5','?', CR}, DEVID_MOTOR, 1, DC_MC_MOTOR_TEMP, TYPE_ASCII_DECIMAL, 6 },//133

{ (void*)mc_heatsink_temp, {'6','6','?', CR}, DEVID_MOTOR, 1, DC_MC_HEATSINK_TEMP, TYPE_ASCII_DECIMAL, 6 },//134

{ (void*)mc_operating_status, {'9','6','?', CR}, DEVID_MOTOR, 1, DC_MC_OPERATING_STATUS, TYPE_ASCII_DECIMAL, 3 },//135

{ (void*)mc_observed_rotation_dir, {'9','7','?', CR}, DEVID_MOTOR, 1, DC_MC_OBSERVED_ROTATION_DIR, TYPE_ASCII_DECIMAL, 3 },//136

{ (void*)mc_fault1, {'9','9','?', CR}, DEVID_MOTOR, 1, DC_MC_FAULT1, TYPE_ASCII_DECIMAL, 3 },//137

{ (void*)mc_fault2, {'9','A','?', CR}, DEVID_MOTOR, 1, DC_MC_FAULT2, TYPE_ASCII_DECIMAL, 3 },//138

{ (void*)mc_fault3, {'9','B','?', CR}, DEVID_MOTOR, 1, DC_MC_FAULT3, TYPE_ASCII_DECIMAL, 3 },//139

{ (void*)mc_fault4, {'9','C','?', CR}, DEVID_MOTOR, 1, DC_MC_FAULT4, TYPE_ASCII_DECIMAL, 3 },//140

{ (void*)mc_throttle_enable, {'9','F','?', CR}, DEVID_MOTOR, 1, DC_MC_THROTTLE_ENABLE, TYPE_ASCII_DECIMAL, 3 },//141

{ (void*)mc_input_dir, {'A','0','?', CR}, DEVID_MOTOR, 1, DC_MC_INPUT_DIR, TYPE_ASCII_DECIMAL, 3 },//142

{ (void*)mc_actual_dir, {'A','1','?', CR}, DEVID_MOTOR, 1, DC_MC_ACTUAL_DIR, TYPE_ASCII_DECIMAL, 3 },//143

{ (void*)mc_speed_control, {'A','2','?', CR}, DEVID_MOTOR, 1, DC_MC_SPEED_CONTROL, TYPE_ASCII_DECIMAL, 3 },//144

{ (void*)mc_digital_disable_state, {'A','A','?', CR}, DEVID_MOTOR, 1, DC_MC_DIGITAL_DISABLE_STATE, TYPE_ASCII_DECIMAL, 3 },//145

{ (void*)mc_throttle_enable_state, {'A','B','?', CR}, DEVID_MOTOR, 1, DC_MC_THROTTLE_ENABLE_STATE, TYPE_ASCII_DECIMAL, 3 },//146

{ (void*)mc_forward_input_state, {'A','C','?', CR}, DEVID_MOTOR, 1, DC_MC_FORWARD_INPUT_STATE, TYPE_ASCII_DECIMAL, 3 },//147

/* ------------------------------------------------- BATTERY!!!!!!!!! --------------------------------------------------- */

/* data location, command, device_id, p, designating char, data_type, data_size */

{ (void*)&(cell_voltage[0]), {0,0,0,0}, DEVID_BPS, 0, DC_BPS_CELL_1_VOLTAGE, TYPE_ASCII_HEX, 3 },//148

{ (void*)&(cell_voltage[1]), {0,0,0,0}, DEVID_BPS, 0, DC_BPS_CELL_2_VOLTAGE, TYPE_ASCII_HEX, 3 },//149

{ (void*)&(cell_voltage[2]), {0,0,0,0}, DEVID_BPS, 0, DC_BPS_CELL_3_VOLTAGE, TYPE_ASCII_HEX, 3 },//150

{ (void*)&(cell_voltage[3]), {0,0,0,0}, DEVID_BPS, 0, DC_BPS_CELL_4_VOLTAGE, TYPE_ASCII_HEX, 3 },//151

{ (void*)&(cell_voltage[4]), {0,0,0,0}, DEVID_BPS, 0, DC_BPS_CELL_5_VOLTAGE, TYPE_ASCII_HEX, 3 },//152

{ (void*)&(cell_voltage[5]), {0,0,0,0}, DEVID_BPS, 0, DC_BPS_CELL_6_VOLTAGE, TYPE_ASCII_HEX, 3 },//153

{ (void*)&(cell_voltage[6]), {0,0,0,0}, DEVID_BPS, 0, DC_BPS_CELL_7_VOLTAGE, TYPE_ASCII_HEX, 3 },//154

{ (void*)&(cell_voltage[7]), {0,0,0,0}, DEVID_BPS, 0, DC_BPS_CELL_8_VOLTAGE, TYPE_ASCII_HEX, 3 },//155

{ (void*)&(cell_voltage[8]), {0,0,0,0}, DEVID_BPS, 0, DC_BPS_CELL_9_VOLTAGE, TYPE_ASCII_HEX, 3 },//156

{ (void*)&(cell_voltage[9]), {0,0,0,0}, DEVID_BPS, 0, DC_BPS_CELL_10_VOLTAGE, TYPE_ASCII_HEX, 3 },//157

{ (void*)&(cell_voltage[10]), {0,0,0,0}, DEVID_BPS, 0, DC_BPS_CELL_11_VOLTAGE, TYPE_ASCII_HEX, 3 },//158

{ (void*)&(cell_voltage[11]), {0,0,0,0}, DEVID_BPS, 0, DC_BPS_CELL_12_VOLTAGE, TYPE_ASCII_HEX, 3 },//159

{ (void*)&(cell_voltage[12]), {0,0,0,0}, DEVID_BPS, 0, DC_BPS_CELL_13_VOLTAGE, TYPE_ASCII_HEX, 3 },//160

{ (void*)&(cell_voltage[13]), {0,0,0,0}, DEVID_BPS, 0, DC_BPS_CELL_14_VOLTAGE, TYPE_ASCII_HEX, 3 },//161

{ (void*)&(cell_voltage[14]), {0,0,0,0}, DEVID_BPS, 0, DC_BPS_CELL_15_VOLTAGE, TYPE_ASCII_HEX, 3 },//162

{ (void*)&(cell_temperature[0]), {0,0,0,0}, DEVID_BPS, 0, DC_BPS_CELL_1_TEMPERATURE, TYPE_ASCII_HEX, 3 },//163

{ (void*)&(cell_temperature[1]), {0,0,0,0}, DEVID_BPS, 0, DC_BPS_CELL_2_TEMPERATURE, TYPE_ASCII_HEX, 3 },//164

{ (void*)&(cell_temperature[2]), {0,0,0,0}, DEVID_BPS, 0, DC_BPS_CELL_3_TEMPERATURE, TYPE_ASCII_HEX, 3 },//165

{ (void*)&(cell_temperature[3]), {0,0,0,0}, DEVID_BPS, 0, DC_BPS_CELL_4_TEMPERATURE, TYPE_ASCII_HEX, 3 },//166

{ (void*)&(cell_temperature[4]), {0,0,0,0}, DEVID_BPS, 0, DC_BPS_CELL_5_TEMPERATURE, TYPE_ASCII_HEX, 3 },//167

{ (void*)&(cell_temperature[5]), {0,0,0,0}, DEVID_BPS, 0, DC_BPS_CELL_6_TEMPERATURE, TYPE_ASCII_HEX, 3 },//168

{ (void*)&(cell_temperature[6]), {0,0,0,0}, DEVID_BPS, 0, DC_BPS_CELL_7_TEMPERATURE, TYPE_ASCII_HEX, 3 },//169

{ (void*)&(cell_temperature[7]), {0,0,0,0}, DEVID_BPS, 0, DC_BPS_CELL_8_TEMPERATURE, TYPE_ASCII_HEX, 3 },//170

{ (void*)&(cell_temperature[8]), {0,0,0,0}, DEVID_BPS, 0, DC_BPS_CELL_9_TEMPERATURE, TYPE_ASCII_HEX, 3 },//171

{ (void*)&(cell_temperature[9]), {0,0,0,0}, DEVID_BPS, 0, DC_BPS_CELL_10_TEMPERATURE, TYPE_ASCII_HEX, 3 },//172

{ (void*)&(cell_temperature[10]), {0,0,0,0}, DEVID_BPS, 0, DC_BPS_CELL_11_TEMPERATURE, TYPE_ASCII_HEX, 3 },//173

{ (void*)&(cell_temperature[11]), {0,0,0,0}, DEVID_BPS, 0, DC_BPS_CELL_12_TEMPERATURE, TYPE_ASCII_HEX, 3 },//174

{ (void*)&(cell_temperature[12]), {0,0,0,0}, DEVID_BPS, 0, DC_BPS_CELL_13_TEMPERATURE, TYPE_ASCII_HEX, 3 },//175

{ (void*)&(cell_temperature[13]), {0,0,0,0}, DEVID_BPS, 0, DC_BPS_CELL_14_TEMPERATURE, TYPE_ASCII_HEX, 3 },//176

{ (void*)&(cell_temperature[14]), {0,0,0,0}, DEVID_BPS, 0, DC_BPS_CELL_15_TEMPERATURE, TYPE_ASCII_HEX, 3 },//177

{ (void*)cell_balance, {0,0,0,0}, DEVID_BPS, 0, DC_BPS_CELL_1_BALANCING, TYPE_ASCII_HEX, 3 },//178

{ (void*)cell_balance, {0,0,0,0}, DEVID_BPS, 0, DC_BPS_CELL_2_BALANCING, TYPE_ASCII_HEX, 3 },//179

{ (void*)cell_balance, {0,0,0,0}, DEVID_BPS, 0, DC_BPS_CELL_3_BALANCING, TYPE_ASCII_HEX, 3 },//180

{ (void*)cell_balance, {0,0,0,0}, DEVID_BPS, 0, DC_BPS_CELL_4_BALANCING, TYPE_ASCII_HEX, 3 },//181

{ (void*)cell_balance, {0,0,0,0}, DEVID_BPS, 0, DC_BPS_CELL_5_BALANCING, TYPE_ASCII_HEX, 3 },//182

{ (void*)cell_balance, {0,0,0,0}, DEVID_BPS, 0, DC_BPS_CELL_6_BALANCING, TYPE_ASCII_HEX, 3 },//183

{ (void*)cell_balance, {0,0,0,0}, DEVID_BPS, 0, DC_BPS_CELL_7_BALANCING, TYPE_ASCII_HEX, 3 },//184

{ (void*)cell_balance, {0,0,0,0}, DEVID_BPS, 0, DC_BPS_CELL_8_BALANCING, TYPE_ASCII_HEX, 3 },//185

{ (void*)cell_balance, {0,0,0,0}, DEVID_BPS, 0, DC_BPS_CELL_9_BALANCING, TYPE_ASCII_HEX, 3 },//186

{ (void*)cell_balance, {0,0,0,0}, DEVID_BPS, 0, DC_BPS_CELL_10_BALANCING, TYPE_ASCII_HEX, 3 },//187

{ (void*)cell_balance, {0,0,0,0}, DEVID_BPS, 0, DC_BPS_CELL_11_BALANCING, TYPE_ASCII_HEX, 3 },//188

{ (void*)cell_balance, {0,0,0,0}, DEVID_BPS, 0, DC_BPS_CELL_12_BALANCING, TYPE_ASCII_HEX, 3 },//189

{ (void*)cell_balance, {0,0,0,0}, DEVID_BPS, 0, DC_BPS_CELL_13_BALANCING, TYPE_ASCII_HEX, 3 },//190

{ (void*)cell_balance, {0,0,0,0}, DEVID_BPS, 0, DC_BPS_CELL_14_BALANCING, TYPE_ASCII_HEX, 3 },//191

{ (void*)cell_balance, {0,0,0,0}, DEVID_BPS, 0, DC_BPS_CELL_15_BALANCING, TYPE_ASCII_HEX, 3 },//192

{ (void*)battery_current, {0,0,0,0}, DEVID_BPS, 0, DC_BPS_BATTERY_CURRENT, TYPE_ASCII_HEX, 3 },//193

{ (void*)battery_current, {0,0,0,0}, 0, 0, DC_BPS_UNKNOWN1, 0, 0 },//194

{ (void*)battery_current, {0,0,0,0}, 0, 0, DC_BPS_UNKNOWN2, 0, 0 },//195

/* ------------------------------------------------- DRIVER INTERFACE --------------------------------------------------- */

/* data location, command, device_id, p, designating char, data_type, data_size */

{ (void*)di_text_message[0], {0,0,0,0}, DEVID_DI, 0, DC_DI_TEXT_MESSAGE_0_6, TYPE_CHAR_POINTER, 7 }, //196

{ (void*)di_text_message[1], {0,0,0,0}, DEVID_DI, 0, DC_DI_TEXT_MESSAGE_7_13, TYPE_CHAR_POINTER, 7 }, //197

{ (void*)di_text_message[2], {0,0,0,0}, DEVID_DI, 0, DC_DI_TEXT_MESSAGE_14_20, TYPE_CHAR_POINTER, 7 }, //198

{ (void*)di_text_message[3], {0,0,0,0}, DEVID_DI, 0, DC_DI_TEXT_MESSAGE_21_27, TYPE_CHAR_POINTER, 7 }, //199

{ (void*)di_text_message[4], {0,0,0,0}, DEVID_DI, 0, DC_DI_TEXT_MESSAGE_28_34, TYPE_CHAR_POINTER, 7 }, //200

{ (void*)di_text_message[5], {0,0,0,0}, DEVID_DI, 0, DC_DI_TEXT_MESSAGE_35_41, TYPE_CHAR_POINTER, 7 }, //201

{ (void*)di_text_message[6], {0,0,0,0}, DEVID_DI, 0, DC_DI_TEXT_MESSAGE_42_48, TYPE_CHAR_POINTER, 7 }, //202

{ (void*)di_text_message[7], {0,0,0,0}, DEVID_DI, 0, DC_DI_TEXT_MESSAGE_49_55, TYPE_CHAR_POINTER, 7 }, //203

{ (void*)di_text_message[8], {0,0,0,0}, DEVID_DI, 0, DC_DI_TEXT_MESSAGE_56_62, TYPE_CHAR_POINTER, 7 }, //204

{ (void*)di_text_message[9], {0,0,0,0}, DEVID_DI, 0, DC_DI_TEXT_MESSAGE_63_69, TYPE_CHAR_POINTER, 7 }, //205

{ (void*)di_text_message[10], {0,0,0,0}, DEVID_DI, 0, DC_DI_TEXT_MESSAGE_70_76, TYPE_CHAR_POINTER, 7 }, //206

{ (void*)di_text_message[11], {0,0,0,0}, DEVID_DI, 0, DC_DI_TEXT_MESSAGE_77_79, TYPE_CHAR_POINTER, 4 }, //207

/* ------------------------------------------------- TELEMETRY LOCALS --------------------------------------------------- */

/* data location, command, device_id, p, designating char, data_type, data_size */

{ (void*)gps_time, {0,0,0,0}, DEVID_TELEM, 0, DC_TELEM_GPS_TIME, TYPE_ASCII_FLOAT, GPS_TIME_LENGTH }, //208

{ (void*)gps_latitude, {0,0,0,0}, DEVID_TELEM, 0, DC_TELEM_GPS_LATITUDE, TYPE_ASCII_FLOAT, GPS_LATITUDE_LENGTH }, //209

{ (void*)gps_longitude, {0,0,0,0}, DEVID_TELEM, 0, DC_TELEM_GPS_LONGITUDE, TYPE_ASCII_FLOAT, GPS_LONGITUDE_LENGTH }, //210

{ (void*)gps_altitude, {0,0,0,0}, DEVID_TELEM, 0, DC_TELEM_GPS_ALTITUDE, TYPE_ASCII_FLOAT, GPS_ALTITUDE_LENGTH }, //211

{ (void*)&(accel.x), {0,0,0,0}, DEVID_TELEM, 0, DC_TELEM_X_ACCELERATION, TYPE_INT, 1 }, //212

{ (void*)&(accel.y), {0,0,0,0}, DEVID_TELEM, 0, DC_TELEM_Y_ACCELERATION, TYPE_INT, 1 }, //213

{ (void*)&(accel.z), {0,0,0,0}, DEVID_TELEM, 0, DC_TELEM_Z_ACCELERATION, TYPE_INT, 1 }, //214

{ (void*)¤t_temperature, {0,0,0,0}, DEVID_TELEM, 0, DC_TELEM_TEMPERATURE, TYPE_INT, 1 }, //215

{ (void*)&temperature_alert, {0,0,0,0}, DEVID_TELEM, 0, DC_TELEM_TEMPERATURE_ALERT, TYPE_UCHAR, 0 } //216

};

// turn off the watch dog timer

//#pragma config WDT = ON

#pragma config WDT = ON, WDTPS = 32768

//CLRWDT asm instruction clears watchdog

//maybe reset_wdt() as well, not sure

#endif

/* Compile options: -ml (Large code model) */

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include "ECAN.h"

#include "main.h"

#include "main2.h"

int CANPOLL =0; //used to determine if we are currently polling

//the PPT's, if so, then ignore the recieved CAN interrupt

// _

// ( )_

// _ _ _ _ _ __ | ,_)

// ( ) ( ) /'_` )( '__)| |

// | (_) |( (_| || | | |_

// `\___/'`\__,_)(_) `\__)

#pragma idata my_isection_3

#pragma idata my_usection_3

void writecSPI_UART( unsigned char device, unsigned char addr, unsigned char data )

{

disable_interrupts();

if(( device == SPI_A0 ) || ( device == SPI_A1 ))

{

LATAbits.LATA3 = 1; // negates chip select for SPIb

LATAbits.LATA5 = 0; // enables chip select for SPIA

putcSPI( ((addr&0x0F) 0)

{

readsSPI_UART(SPI_BPS, SPI_RHR, FIFO_buffer, FIFO_num_bytes);

// send the data in the FIFO to be parsed for BPS

data_status = ParseBPS( FIFO_buffer, FIFO_num_bytes );

}

break;

default:

break;

}

// return GPS status

return data_status;

}

void send_MC (unsigned char index)

{

unsigned char i = 0;

// check for out of bounds on polled_data

if( ( index < ALL_DATA_SIZE ) &&

( index >= 0 ) )

{

for(i = 0; i < MAX_COMMAND_SIZE; i++)

{

writecSPI_UART(SPI_MC, SPI_THR, polled_data[index].command[i]);

}

}

}

unsigned char recv_MC (unsigned char index)

{

unsigned char FIFO_buffer[MAX_BPS_BUFFER_LENGTH];

unsigned char FIFO_num_bytes = 0;

unsigned char i = 0;

unsigned char status = RETURN_INCOMPLETE;

FIFO_num_bytes = readcSPI_UART( SPI_MC, SPI_RXLVL );

// if data is present, read the string of chars in from the FIFO

if(FIFO_num_bytes > 0)

{

readsSPI_UART(SPI_MC, SPI_RHR, FIFO_buffer, FIFO_num_bytes);

status = ParseMC(FIFO_buffer, FIFO_num_bytes, index);

}

return status;

}

unsigned char ParseMC (unsigned char *MC_buffer, unsigned char buff_len, unsigned char index)

{

unsigned char i = 0;

static unsigned char position = 0;

unsigned char status = RETURN_INCOMPLETE;

if( ( buff_len >= MIN_BPS_BUFFER_LENGTH ) &&

( buff_len = 0 ) )

{

for(i = 0; i < buff_len; i++)

{

if(MC_buffer[i] == LF)

{

position = 0;

status = RETURN_COMPLETE;

}

else if(MC_buffer[i] == CR)

{

*((char *)(polled_data[index].data_location + position)) = 0; // put a null termination at the end of the data

}

else if( position < polled_data[index].data_length )

{

*((char *)(polled_data[index].data_location + position)) = MC_buffer[i];

++position;

}

}

}

return status;

}

#pragma idata section_ipm

#pragma udata section_upm

unsigned char send_PM(void)

{

static unsigned char current_item = 0;

unsigned char data_length = 0;

unsigned char x = 0;

unsigned char return_me = PM_TRANSMIT_INCOMPLETE;

unsigned int temp_int;

switch( pm_state )

{

case PM_STATE_POLLED:

if( current_item < POLLED_DATA_SIZE )

{

if( current_item == 0 )

{

write_byte_UART( PM_START_CHARACTER );

}

if( polled_data[current_item].data_length != 0 )

{

// determine the size of the response

if ( polled_data[current_item].data_type == TYPE_INT )

{

data_length = sizeof(int) * polled_data[current_item].data_length;

}

else

{

data_length = sizeof(char) * polled_data[current_item].data_length;

}

write_u8_UART( polled_data[current_item].designating_char );

if ( polled_data[current_item].data_type == TYPE_INT )

{

write_u16_UART( *((int *)polled_data[current_item].data_location) );

}

else

{

for( x = 0; x < data_length; ++x )

{

if( *((char *)(polled_data[current_item].data_location + x)) != 0 )

{

write_byte_UART( *((char *)(polled_data[current_item].data_location + x)) );

}

else

{

break;

}

}

}

write_byte_UART( PM_DELIMITER );

}

++current_item;

}

else

{

current_item = 0;

pm_state = PM_STATE_TEMP;

}

break;

case PM_STATE_TEMP:

write_u8_UART( DC_TELEM_TEMPERATURE );

write_u16_UART( current_temperature );

write_byte_UART( PM_DELIMITER );

if( temperature_alert == 1 )

{

pm_state = PM_STATE_TEMP_ALERT;

}

else

{

pm_state = PM_STATE_GPS_TIME;

}

break;

case PM_STATE_TEMP_ALERT:

write_u8_UART( DC_TELEM_TEMPERATURE_ALERT );

write_byte_UART( PM_DELIMITER );

pm_state = PM_STATE_GPS_TIME;

break;

case PM_STATE_GPS_TIME:

write_u8_UART( DC_TELEM_GPS_TIME );

if( device_flags & GPS_ERR_STATUS )

{

write_u32_UART( unreal_time_clock );

}

else

{

while( BusyUSART() );

putsUSART( gps_time );

}

write_byte_UART( PM_DELIMITER );

pm_state = PM_STATE_ACCEL_X;

break;

case PM_STATE_ACCEL_X:

write_u8_UART( DC_TELEM_X_ACCELERATION );

write_u16_UART( accel.x );

write_byte_UART( PM_DELIMITER );

pm_state = PM_STATE_ACCEL_Y;

break;

case PM_STATE_ACCEL_Y:

write_u8_UART( DC_TELEM_Y_ACCELERATION );

write_u16_UART( accel.y );

write_byte_UART( PM_DELIMITER );

pm_state = PM_STATE_ACCEL_Z;

break;

case PM_STATE_ACCEL_Z:

write_u8_UART( DC_TELEM_Z_ACCELERATION );

write_u16_UART( accel.z );

write_byte_UART( PM_DELIMITER );

pm_state = PM_STATE_GPS_LAT;

break;

case PM_STATE_GPS_LAT:

write_u8_UART( DC_TELEM_GPS_LATITUDE );

while( BusyUSART() );

putsUSART( gps_latitude );

write_byte_UART( PM_DELIMITER );

pm_state = PM_STATE_GPS_LON;

break;

case PM_STATE_GPS_LON:

write_u8_UART( DC_TELEM_GPS_LONGITUDE );

while( BusyUSART() );

putsUSART( gps_longitude );

write_byte_UART( PM_DELIMITER );

pm_state = PM_STATE_GPS_ALT;

break;

case PM_STATE_GPS_ALT:

write_u8_UART( DC_TELEM_GPS_ALTITUDE );

while( BusyUSART() );

putsUSART( gps_altitude );

write_byte_UART( PM_DELIMITER );

pm_state = PM_STATE_BPS_VOLTAGE;

break;

case PM_STATE_BPS_VOLTAGE:

if( current_item < NUM_BATTERIES )

{

write_u8_UART( DC_BPS_CELL_1_VOLTAGE + current_item );

write_byte_UART( cell_voltage[current_item][0] );

write_byte_UART( cell_voltage[current_item][1] );

write_byte_UART( cell_voltage[current_item][2] );

write_byte_UART( PM_DELIMITER );

++current_item;

}

else

{

current_item = 0;

pm_state = PM_STATE_BPS_TEMPERATURE;

}

break;

case PM_STATE_BPS_TEMPERATURE:

if( current_item < NUM_BATTERIES )

{

write_u8_UART( DC_BPS_CELL_1_TEMPERATURE + current_item );

write_byte_UART( cell_temperature[current_item][0] );

write_byte_UART( cell_temperature[current_item][1] );

write_byte_UART( cell_temperature[current_item][2] );

write_byte_UART( PM_DELIMITER );

++current_item;

}

else

{

current_item = 0;

pm_state = PM_STATE_BPS_BALANCE;

}

break;

case PM_STATE_BPS_BALANCE:

write_u8_UART( DC_BPS_CELL_1_BALANCING );

write_byte_UART( cell_balance[0] );

write_byte_UART( cell_balance[1] );

write_byte_UART( cell_balance[2] );

write_byte_UART( cell_balance[3] );

write_byte_UART( PM_DELIMITER );

pm_state = PM_STATE_BPS_CURRENT;

break;

case PM_STATE_BPS_CURRENT:

write_u8_UART( DC_BPS_BATTERY_CURRENT );

write_byte_UART( battery_current[0] );

write_byte_UART( battery_current[1] );

write_byte_UART( battery_current[2] );

write_byte_UART( PM_END_CHARACTER );

pm_state = PM_STATE_POLLED;

return_me = PM_TRANSMIT_COMPLETE;

break;

default:

pm_state = PM_STATE_POLLED;

current_item = 0;

break;

}

return return_me;

}

#pragma idata section_iint

#pragma udata section_uint

// _ _

// _ ( )_ ( )_

// (_) ___ | ,_) __ _ __ _ __ _ _ _ _ | ,_) ___

// | |/' _ `\| | /'__`\( '__)( '__)( ) ( )( '_`\ | | /',__)

// | || ( ) || |_ ( ___/| | | | | (_) || (_) )| |_ \__, \

// (_)(_) (_)`\__)`\____)(_) (_) `\___/'| ,__/'`\__)(____/

// | |

// (_)

void disable_interrupts(void)

{

// disables interrupts

INTCONbits.GIEH = 0;

INTCONbits.GIEL = 0;

}

void enable_interrupts(void)

{

// enables interrupts

INTCONbits.GIEH = 1;

INTCONbits.GIEL = 1;

}

void high_ISR(void);

void low_ISR(void);

#pragma code high_vector = 0x08

void high_interrupt (void)

{

_asm

goto high_ISR

_endasm

}

#pragma code low_vector = 0x18

void low_interrupt (void)

{

_asm

goto low_ISR

_endasm

}

#pragma code

#pragma interrupt high_ISR

#pragma idata section_imain

#pragma idata section_umain

void high_ISR (void)

{

static long timer_count_7ms = 0;

static long timer_count_1000ms = 0;

char crap;

unsigned int id = (RXB0SIDH > 5);

if( PIR1bits.TMR2IF )

{

T2CON = 0x00; // close timer

PIR1bits.TMR2IF = 0; // clear interrupt

++timer_count_7ms;

++timer_count_1000ms;

// 1 ms tasks

// poll bps

++BPS_counter;

if(BPS_counter >= COUNTER_TOO_BIG) // BPS is taking too long and probably not working

{

device_flags = device_flags | BPS_ERR_STATUS;

BPS_counter = 0;

}

else

{

device_flags = device_flags | POLL_BPS_FLAG;

}

if( mc_state == MC_STATE_RECV )

{

++MC_counter;

}

else

{

MC_counter = 0;

}

if( CAN_poll_state == CAN_POLL_STATE_RESPONSE )

{

++CAN_counter;

}

else

{

CAN_counter = 0;

}

if( MC_counter > MC_COUNTER_TOO_BIG )

{

mc_state = MC_STATE_SEND;

MC_counter = 0;

}

if( timer_count_7ms % 7 == 0 )

{

// 7 ms tasks

// poll gps

++GPS_counter;

if(GPS_counter >= COUNTER_TOO_BIG) // GPS is taking too long and probably not working

{

device_flags = device_flags | GPS_ERR_STATUS;

GPS_counter = 0;

}

else

{

device_flags = device_flags | POLL_GPS_FLAG;

}

timer_count_7ms = 0;

}

if( timer_count_1000ms % 500 == 0 )

{

device_flags = device_flags | POLL_MC_FLAG;

}

if( timer_count_1000ms % 1000 == 0)

{

++unreal_time_clock;

if( device_flags & GPS_ERR_STATUS )

{

device_flags = device_flags | POLL_ADC_FLAG;

}

device_flags = device_flags | SEND_STATUS_FLAG | POLL_CAN_FLAG;

}

#ifdef ROTATE_TEXT_MESSAGES

// retry any errored ppts after 60s

if( timer_count_1000ms % 5000 == 0 )

{

device_flags = device_flags | ROTATE_TAGS_FLAG;

}

#endif

// retry any errored ppts after 60s

if( timer_count_1000ms % 60000 == 0 )

{

ppt_status_flags = 0x0000;

timer_count_1000ms = 0;

}

T2CON = 0b01110111; // initialize and open timer .. 15 postscale, 16 prescale

}

if ((PIR3 & 0x01) || (PIR3 & 0x02)) //CAN Interrupt

{

PIR3bits.RXB0IF = 0; //clear the interrupt flag

if( id == TELEM )

{

device_flags = device_flags | SERVICE_CAN_INT;

}

else

{

RXB0CONbits.RXFUL = 0;

}

}

if( PIR1 & 0x20 ) // UART Rx

{

PIR1bits.RCIF = 0; // clear interrupt flag

if( DataRdyUSART() )

{

crap = ReadUSART();

if( RCSTAbits.OERR || RCSTAbits.FERR )

{

RCSTAbits.CREN = 0;

RCSTAbits.CREN = 1;

}

}

}

INTCON = 0b11000000; // (bit 7) enable high priority ints (bit 6) enable low priority ints (bit 4) enable INT0 external int

INTCON2 = 0b00000000; // (bit 6) rising edge of int0 interrupt (bit 5) rising edge of int1 interrupt

INTCON3 = 0b00000000; // (bit 3) enable int1 interrupt

}

#pragma code

#pragma interruptlow low_ISR

void low_ISR (void)

{

}

#pragma idata section_iad

#pragma udata section_uad

// _

// ( )

// _ _ ______ _| |

// /'_` )(______)/'_` |

// ( (_| | ( (_| |

// `\__,_) `\__,_)

void readAccel(void)

{

OpenADC( ADC_FOSC_64 &

ADC_RIGHT_JUST &

ADC_16_TAD,

ADC_CH0 &

ADC_CH1 &

ADC_CH2 &

ADC_CH5 &

ADC_INT_OFF &

ADC_VREFPLUS_VDD &

ADC_VREFMINUS_VSS,

9);

SetChanADC(ADC_CH0);

ConvertADC();

while(BusyADC());

accel.z = ReadADC();

SetChanADC(ADC_CH2);

ConvertADC();

while(BusyADC());

accel.x = ReadADC();

SetChanADC(ADC_CH1);

ConvertADC();

while(BusyADC());

accel.y = ReadADC();

CloseADC();

return;

}

void readTemp(void)

{

// this code does not really apply.. the software was written assuming there was an

// opamp circuit to scale the temperature voltage to the A/D range... so we need to

// modify this to read 0.1-1.75v as -40 to 125 C

//Found exact code in Pic Microcontroller: An Intro to software and hardware interfacing pg.594

OpenADC( ADC_FOSC_64 &

ADC_RIGHT_JUST &

ADC_16_TAD,

ADC_CH0 &

ADC_CH1 &

ADC_CH2 &

ADC_CH5 &

ADC_INT_OFF &

ADC_VREFPLUS_VDD &

ADC_VREFMINUS_VSS,

9);

SetChanADC(ADC_CH5);

ConvertADC();

while( BusyADC() );

current_temperature = ReadADC();

CloseADC();

if( current_temperature > TEMPERATURE_TOO_HIGH )

{

temperature_alert = 1;

}

else

{

temperature_alert = 0;

}

return;

}

// ___ _ _ ___

// /'___) /'_` )/' _ `\

// ( (___ ( (_| || ( ) |

// `\____)`\__,_)(_) (_)

#pragma idata my_section_6

/***************************************************************************

Function name: void initial_Can

Despription: This function initializes the ECAN module to

have a baud rate of 125kbps for a clock frequency

of 40MHz and returns upon successful completion.

Return value: None

*****************************************************************************/

void initialize_CAN(void)

{

CANCON = 0x80; // enter configuration mode

while (CANSTAT != 0x80); // wait until configuration mode is entered

ECANCON = 0x00; // mode 0

BRGCON1 = 0x49; // Sync width = 2, Prescale = 9

BRGCON2 = 0xB1; // Phase Seg 1 = 7, Propegation Time = 2

BRGCON3 = 0x05; // Phase Seg 2 = 6

CIOCON = 0x30; // drive high bit... enable can capture

// RXF0SIDH = 0xFF; // set to recieve identifier 0x7F8 - 11-bit only

// RXF0SIDL = 0xE0;

// RXM0SIDH = 0x00; // Set to look at entire identifier

// RXM0SIDL = 0x00;

RXF0SIDH = 0x02; // set to recieve identifier 0x7F8 - 11-bit only

RXF0SIDL = 0x20;

RXM0SIDH = 0xFF; // Set to look at entire identifier

RXM0SIDL = 0xE0;

RXB0SIDH = 0x00;

RXB0SIDL = 0x00;

RXB0CON = 0x20;

RXB1CON = 0x20;

RXFCON0 = 0x01; // enable filter 0

RXFBCON0 = 0x00; // filter 0 associated with RXB0

MSEL0 = 0x00; // acceptance mask 0?

CANCON = 0x00; // return to normal mode

while ((CANSTAT & 0xE0) == 0x00); // wait until normanl mode is entered

}

/* UNUSED

void can_test(void)

{

unsigned long id;

BYTE data[4];

BYTE dataLen;

ECAN_RX_MSG_FLAGS flags;

while( !ECANSendMessage(0x123, data, 0, ECAN_TX_STD_FRAME) );

do

{

// Wait for a message to get received.

while( !ECANReceiveMessage(&id, data, &dataLen, &flags) );

// Increment received id and echo it back.

id++;

while( BusyUSART() ); WriteUSART( 'C' );

while( !ECANSendMessage(id, data, dataLen, flags) );

} while(1);

}

*/

#pragma idata my_section_cannycannycanny

int hatoi(char *hexStg) {

/* stolen from */

unsigned char n = 0; // position in string

unsigned char m = 0; // position in digit[] to shift

unsigned char count; // loop index

int digit[5]; // hold values to convert

int intValue = 0; // integer value of hex string

while (n < 4) {

if (hexStg[n]=='\0')

break;

if (hexStg[n] > 0x29 && hexStg[n] < 0x40 ) //if 0 to 9

digit[n] = hexStg[n] & 0x0f; //convert to int

else if (hexStg[n] >='a' && hexStg[n] ='A' && hexStg[n] 7 )

{

dataLen = 7;

}

// start filling the transmit buffer

cpt = &TXB0D0;

cpt[0] = recieved_data[1]; // the first byte will be the designating character requested

// fill the transmit buffer with the data from memory

if ( polled_data[recieved_data[1]].data_type == TYPE_ASCII_DECIMAL )

{

tmp_int = atoi( (char *)(polled_data[recieved_data[1]].data_location) );

#ifdef CAN_BIG_ENDIAN

for( x = 0; x < dataLen; ++x )

{

cpt[dataLen-x] = *( ((char *)&(tmp_int)) +x);

}

#else

for( x = 0; x < dataLen; ++x )

{

cpt[x+1] = *( ((char *)&(tmp_int)) +x);

}

#endif

}

else if ( polled_data[recieved_data[1]].data_type == TYPE_ASCII_HEX )

{

tmp_int = hatoi( (char *)(polled_data[recieved_data[1]].data_location) );

#ifdef CAN_BIG_ENDIAN

for( x = 0; x < dataLen; ++x )

{

cpt[dataLen-x] = *( ((char *)&(tmp_int)) +x);

}

#else

for( x = 0; x < dataLen; ++x )

{

cpt[x+1] = *( ((char *)&(tmp_int)) +x);

}

#endif

}

else if ( polled_data[recieved_data[1]].data_type == TYPE_ASCII_FLOAT )

{

tmp_float = atof( (char *)(polled_data[recieved_data[1]].data_location) );

#ifdef CAN_BIG_ENDIAN

for( x = 0; x < dataLen; ++x )

{

cpt[dataLen-x] = *( ((char *)&(tmp_float)) +x);

}

#else

for( x = 0; x < dataLen; ++x )

{

cpt[x+1] = *( ((char *)&(tmp_float)) +x);

}

#endif

}

else /* direct memory copy */

{

#ifdef CAN_BIG_ENDIAN

for( x = 0; x < dataLen; ++x )

{

cpt[dataLen-x] = *((char *)(polled_data[recieved_data[1]].data_location + x));

}

#else

for( x = 0; x < dataLen; ++x )

{

cpt[x+1] = *((char *)(polled_data[recieved_data[1]].data_location + x));

}

#endif

}

TXB0SIDH = 0b00000010; //send back to driver CAN ID

TXB0SIDL = 0b00000000;

TXB0DLC = dataLen+1;

TXB0CON = 0x08; //initiate transmission

}

}

else if ( CAN_poll_state == CAN_POLL_STATE_RESPONSE ) // the packet is a response from a CAN poll

{

// check for out of bounds on polled_data

if( ( recieved_data[0] < ALL_DATA_SIZE ) &&

( recieved_data[0] >= 0 ) )

{

// determine the size of the response

if ( polled_data[recieved_data[0]].data_type == 0 )

{

dataLen = 0;

}

else if ( polled_data[recieved_data[0]].data_type == TYPE_INT )

{

dataLen = sizeof(int) * polled_data[recieved_data[0]].data_length;

}

else if ( polled_data[recieved_data[0]].data_type == TYPE_ASCII_FLOAT )

{

dataLen = sizeof(float);

}

else if ( ( polled_data[recieved_data[0]].data_type == TYPE_ASCII_DECIMAL ) ||

( polled_data[recieved_data[0]].data_type == TYPE_ASCII_HEX ) )

{

dataLen = sizeof(int);

}

else // uchar and char* both get caught here

{

dataLen = sizeof(char) * polled_data[recieved_data[0]].data_length;

}

// put a cap on the length of a message

if( dataLen > 7 )

{

dataLen = 7;

}

// update our memory with the new data

for( x = 0; x < dataLen; ++x )

{

#ifdef CAN_BIG_ENDIAN

*((char *)(polled_data[recieved_data[0]].data_location + x)) = recieved_data[dataLen-x];

#else

*((char *)(polled_data[recieved_data[0]].data_location + x)) = recieved_data[x+1];

#endif

}

}

// update can poll's state

CAN_poll_state = CAN_POLL_STATE_NEXT;

}

//clear RXFUL flag, since we are done with the recieved data

RXB0CONbits.RXFUL = 0;

//}

/*else // data not for us

{

//clear RXFUL flag

RXB0CONbits.RXFUL = 0;

}*/

}

unsigned char CANpollPPT(unsigned char pptID)

{

static unsigned char *cpt;

static unsigned int dchar_offset; // designating character offset

unsigned char return_me = CAN_POLL_INCOMPLETE;

switch( CAN_poll_state )

{

case CAN_POLL_STATE_IDLE:

// initialize

dchar_offset = 0;

CAN_poll_state = CAN_POLL_STATE_REQUEST;

break;

case CAN_POLL_STATE_REQUEST:

CANPOLL = 1;

// start filling the transmit buffer

cpt = &TXB0D0;

cpt[0] = DC_COMMAND_REQUEST; // first character is a request

cpt[1] = (pptID * 8) + dchar_offset;

// fill the transmit ID buffers with the CAN ID to send to

TXB0SIDH = ( pptID >> 3 ) & 0x00FF;

TXB0SIDL = ( pptID 100 )

{

ppt_status_flags = ppt_status_flags | ( 1 DC_PPT0_RESERVED )

{

CAN_poll_state = CAN_POLL_STATE_COMPLETE;

}

else

{

CAN_poll_state = CAN_POLL_STATE_REQUEST;

}

break;

case CAN_POLL_STATE_COMPLETE:

CAN_poll_state = CAN_POLL_STATE_IDLE;

return_me = CAN_POLL_COMPLETED;

break;

default:

CAN_poll_state = CAN_POLL_STATE_IDLE;

break;

}

return return_me;

}

// _

// _ _ ( )_

// (_) ___ (_)| ,_)

// | |/' _ `\| || |

// | || ( ) || || |_

// (_)(_) (_)(_)`\__)

#pragma idata my_section_7

#define PIC_BAUD_9600 255

#define PIC_BAUD_115200 21

#define SPI_BAUD_9600 12

#define SPI_BAUD_115200 1

void init (void)

{

/****************************************/

// Setup interrupt registers.

// This enables interrupts on the UART,

// 2 of the interrupt input pins

// and CAN recieve and send buffers

/****************************************/

unsigned int delay_counter = 0;

// 76543210

INTCON = 0b00000000; // (bit 7) enable high priority ints (bit 6) enable low priority ints (bit 4) enable INT0 external int

INTCON2 = 0b00000000; // (bit 6) rising edge of int0 interrupt (bit 5) rising edge of int1 interrupt

INTCON3 = 0b00000000; // (bit 3) enable int1 interrupt

RCON = 0b10000000; // (bit 7, IPEN) enable priority based interrupts

T2CON = 0b01110111; // initialize and open timer .. 15 postscale, 16 prescale

PIR1 = 0b00000000; // clear int flags

PIR2 = 0b00000000; // clear int flags

PIR3 = 0b00000000; // clear int flags

PIE1 = 0b00100010; // interrupt on UART Rx (bit 5), UART Tx (bit 4), timer 2 interrupt (bit 1)

PIE2 = 0b00000000;

PIE3 = 0b00000011; // enable interrupts on CAN recieve buffers 0 and 1

IPR1 = 0b11111111; // every interrupt is low priorty, except timer (bit 1)

IPR2 = 0b11111111; // every interrupt is low priorty, except (bit 5) UART Rx

IPR3 = 0b11111111; // every interrupt is low priorty

TRISC = 0b10010000; // UART Rx is input (bit 7) SDI is input (bit 4)

TRISAbits.TRISA5 = 0; // set RA5 to be output for chip select on SPIA

TRISAbits.TRISA3 = 0; // set RA3 to be output for chip select on SPIB

TRISBbits.TRISB0 = 1; // set RB0 to be input

TRISBbits.TRISB1 = 1; // set RB1 to be input

PR2 = 41; // 1.008 ms (or 0.981 ms)

LATCbits.LATC0 = 0; // reset SPIs

/**********************************************/

// Setting intial stuff

//OpenSPI(SPI_FOSC_4, MODE_00, SMPEND);

/**********************************************/

OpenUSART( USART_TX_INT_OFF &

USART_RX_INT_ON &

USART_EIGHT_BIT &

USART_ASYNCH_MODE &

USART_BRGH_HIGH &

USART_CONT_RX,

PIC_BAUD_115200);

// need to set an3 and ra5 to be digital i/o for chip selects for spi

OpenSPI( SPI_FOSC_64,

MODE_00,

SMPMID );

LATCbits.LATC0 = 1; // sets SPIA out of reset

for( delay_counter = 0; delay_counter < 30000; ++delay_counter ); // delay after spi-uart pulled out of reset

//writecSPI_UART( SPI_A0, SPI_IODir, 0xFF ); // make all I/O pins outputs

writecSPI_UART( SPI_A0, SPI_LCR, 0b10000011 ); // enable baud rate setting for A0

writecSPI_UART( SPI_A1, SPI_LCR, 0b10000011 ); // enable baud rate setting for A0

writecSPI_UART( SPI_A0, SPI_DLL, SPI_BAUD_9600 ); // set A0 low divisor to 12 (for 9600 baud for MC)

writecSPI_UART( SPI_A1, SPI_DLL, SPI_BAUD_9600 ); // set A1 low divisor to 12 (for 9600 baud for GPS)

writecSPI_UART( SPI_A0, SPI_DLH, 0 ); // set A0 high divisor to 0 (for 9600 baud)

writecSPI_UART( SPI_A1, SPI_DLH, 0 ); // set A1 high divisor to 0 (for 9600 baud)

writecSPI_UART( SPI_A0, SPI_LCR, 0b00000011 ); // disable baud rate setting for A0

writecSPI_UART( SPI_A1, SPI_LCR, 0b00000011 ); // disable baud rate setting for A0

writecSPI_UART( SPI_A0, SPI_FCR, 0b00000111 ); // enable FIFO

writecSPI_UART( SPI_A1, SPI_FCR, 0b00000111 ); // enable FIFO

writecSPI_UART( SPI_A0, SPI_IER, 0b00000001 ); // enable Rx interrupt

writecSPI_UART( SPI_A1, SPI_IER, 0b00000001 ); // enable Rx interrupt

//writecSPI_UART( SPI_B0, SPI_IODir, 0xFF ); // make all I/O pins outputs

writecSPI_UART( SPI_B0, SPI_LCR, 0b10000011 ); // enable baud rate setting for B0

writecSPI_UART( SPI_B1, SPI_LCR, 0b10000011 ); // enable baud rate setting for B0

writecSPI_UART( SPI_B0, SPI_DLL, SPI_BAUD_115200 ); // set B0 low divisor to 1 (for 115,200 baud)

writecSPI_UART( SPI_B1, SPI_DLL, SPI_BAUD_115200 ); // set B1 low divisor to 1 (for 115,200 baud for BPS)

writecSPI_UART( SPI_B0, SPI_DLH, 0 ); // set B0 high divisor to 0 (for 9600 baud)

writecSPI_UART( SPI_B1, SPI_DLH, 0 ); // set B1 high divisor to 0 (for 9600 baud)

writecSPI_UART( SPI_B0, SPI_LCR, 0b00000011 ); // enable baud rate setting for B0

writecSPI_UART( SPI_B1, SPI_LCR, 0b00000011 ); // enable baud rate setting for B0

writecSPI_UART( SPI_B0, SPI_FCR, 0b00000111 ); // enable FIFO

writecSPI_UART( SPI_B1, SPI_FCR, 0b00000111 ); // enable FIFO

writecSPI_UART( SPI_B0, SPI_IER, 0b00000001 ); // enable Rx interrupt

writecSPI_UART( SPI_B1, SPI_IER, 0b00000001 ); // enable Rx interrupt

_asm

clrwdt

_endasm

}

// _ _ _ _ _ __ ___ __

// ( '_`\ /'_` )( '__)/',__) /'__`\

// | (_) )( (_| || | \__, \( ___/

// | ,__/'`\__,_)(_) (____/`\____)

// | |

// (_)

/* -----------------------------------------------------------------------------

Function: ParseGPS()

Inputs: (char*) gps_buffer - a char pointer to the partial gps string to be

parsed

(int) length - the size of the gps_buffer, can range from 1 to 64 chars

Outputs: Returns GPS_PARSING_COMPLETE when the end of a sentence has been

reached, and the data from that sentence is contained in the globals:

(char[]) gps_latitude - the latitide string in ddmm.mmmm format

(char[]) gps_longitude - the longitude string in dddmm.mmmm format

(char[]) gps_altitude - the altitude string in mm.m format

(char[]) gps_time - the UTC time string in hhmmss.sss format

(char) gps_ew - whether longitude is E or W

(char) gps_ns - whether latitude is N or S

(char) gps_alt_unit - units on altitude string (M is meters)

Otherwise, returns GPS_PARSING_INCOMPLETE if a complete sentence has

not been found yet, and GPS_PARSE_ERROR on non syntax related errors.

On sentence syntax errors, all characters are ignored until the start

of a new sentence ('$')

---------------------------------------------------------------------------- */

#pragma idata my_section_8

unsigned char ParseGPS( unsigned char* gps_buffer, unsigned char length )

{

unsigned char x = 0;

unsigned char return_me = GPS_PARSING_INCOMPLETE;

static unsigned char gps_state = GPSS_START;

static unsigned char gps_latitude_position = 0;

static unsigned char gps_longitude_position = 0;

static unsigned char gps_altitude_position = 0;

static unsigned char gps_time_position = 0;

if(( length >= MIN_GPS_BUFFER_LENGTH ) &&

( length GPS_TIME_LENGTH ))

{

gps_state = GPSS_GPGGA_LAT;

gps_time_position = 0;

}

else

{

gps_time[ gps_time_position ] = gps_buffer[x];

++gps_time_position;

}

break;

case GPSS_GPGGA_LAT:

if(( gps_buffer[x] == ',' ) || ( gps_latitude_position > GPS_LATITUDE_LENGTH ))

{

gps_state = GPSS_GPGGA_NS;

gps_latitude_position = 0;

}

else

{

gps_latitude[ gps_latitude_position ] = gps_buffer[x];

++gps_latitude_position;

}

break;

case GPSS_GPGGA_NS:

if( gps_buffer[x] == ',' )

{

gps_state = GPSS_GPGGA_LONG;

}

else

{

gps_ns = gps_buffer[x];

}

break;

case GPSS_GPGGA_LONG:

if(( gps_buffer[x] == ',' ) || ( gps_longitude_position > GPS_LONGITUDE_LENGTH ))

{

gps_state = GPSS_GPGGA_EW;

gps_longitude_position = 0;

}

else

{

gps_longitude[ gps_longitude_position ] = gps_buffer[x];

++gps_longitude_position;

}

break;

case GPSS_GPGGA_EW:

if( gps_buffer[x] == ',' )

{

gps_state = GPSS_GPGGA_POS_FIX;

}

else

{

gps_ew = gps_buffer[x];

}

break;

case GPSS_GPGGA_POS_FIX:

if( gps_buffer[x] == ',' )

{

gps_state = GPSS_GPGGA_SATS;

}

break;

case GPSS_GPGGA_SATS:

if( gps_buffer[x] == ',' )

{

gps_state = GPSS_GPGGA_HDOP;

}

break;

case GPSS_GPGGA_HDOP:

if( gps_buffer[x] == ',' )

{

gps_state = GPSS_GPGGA_ALT;

}

break;

case GPSS_GPGGA_ALT:

if(( gps_buffer[x] == ',' ) || ( gps_altitude_position > GPS_ALTITUDE_LENGTH ))

{

gps_state = GPSS_GPGGA_ALT_UNIT;

gps_altitude_position = 0;

}

else

{

gps_altitude[ gps_altitude_position ] = gps_buffer[x];

++gps_altitude_position;

}

break;

case GPSS_GPGGA_ALT_UNIT:

if( gps_buffer[x] == ',' )

{

gps_state = GPSS_START; // use GPSS_GPGGA_GEOID if any additional data is needed, see below

return_me = GPS_PARSING_COMPLETE;

}

else

{

gps_alt_unit = gps_buffer[x];

}

break;

/* These states are here for completeness. If any of this data was

needed, uncomment these states and insert the correct code. But

since our needs end at altitude unit, we stop parsing there.

case GPSS_GPGGA_GEOID:

if( gps_buffer[x] == ',' )

{

gps_state = GPSS_GPGGA_GEOID_UNIT;

}

break;

case GPSS_GPGGA_GEOID_UNIT:

if( gps_buffer[x] == ',' )

{

gps_state = GPSS_GPGGA_AGE;

}

break;

case GPSS_GPGGA_AGE:

if( gps_buffer[x] == ',' )

{

gps_state = GPSS_GPGGA_STATION_ID;

}

break;

case GPSS_GPGGA_STATION_ID:

if( gps_buffer[x] == ',' )

{

gps_state = GPSS_GPGGA_CHECKSUM;

}

break;

case GPSS_GPGGA_CHECKSUM:

if( gps_buffer[x] == LF )

{

gps_state = GPSS_START;

}

break;

*/

// ------------------------

// PARSE GPGLL

// ------------------------

/* This sentence is extraneous

case GPSS_GPGLL_LAT:

if(( gps_buffer[x] == ',' ) || ( gps_latitude_position > GPS_LATITUDE_LENGTH ))

{

gps_state = GPSS_GPGLL_NS;

gps_latitude_position = 0;

}

else

{

gps_latitude[ gps_latitude_position ] = gps_buffer[x];

++gps_latitude_position;

}

break;

case GPSS_GPGLL_NS:

if( gps_buffer[x] == ',' )

{

gps_state = GPSS_GPGLL_LONG;

}

else

{

gps_ns = gps_buffer[x];

}

break;

case GPSS_GPGLL_LONG:

if(( gps_buffer[x] == ',' ) || ( gps_longitude_position > GPS_LONGITUDE_LENGTH ))

{

gps_state = GPSS_GPGLL_EW;

gps_longitude_position = 0;

}

else

{

gps_longitude[ gps_longitude_position ] = gps_buffer[x];

++gps_longitude_position;

}

break;

case GPSS_GPGLL_EW:

if( gps_buffer[x] == ',' )

{

gps_state = GPSS_GPGLL_TIME;

}

else

{

gps_ew = gps_buffer[x];

}

break;

case GPSS_GPGLL_TIME:

if(( gps_buffer[x] == ',' ) || ( gps_time_position > GPS_TIME_LENGTH ))

{

gps_state = GPSS_START; // use GPSS_GPGLL_POS_FIX if any additional data is needed, see below

return_me = GPS_PARSING_COMPLETE;

gps_time_position = 0;

}

else

{

gps_time[ gps_time_position ] = gps_buffer[x];

++gps_time_position;

}

break;

*/

/* These states are here for completeness. If any of this data was

needed, uncomment these states and insert the correct code. But

since our needs end at altitude unit, we stop parsing there.

case GPSS_GPGLL_POS_FIX:

if( gps_buffer[x] == ',' )

{

gps_state = GPSS_GPGLL_SATS;

}

break;

case GPSS_GPGLL_SATS:

if( gps_buffer[x] == ',' )

{

gps_state = GPSS_GPGLL_HDOP;

}

break;

*/

default: // invalid state

gps_latitude_position = 0;

gps_longitude_position = 0;

gps_altitude_position = 0;

gps_time_position = 0;

gps_state = GPSS_START;

return_me = GPS_PARSE_ERROR;

break;

}

}

}

else // length out of bounds

{

return GPS_PARSE_ERROR;

}

return return_me;

}

/* -------------------------------------------------------------------------------

Function: parseBPS()

Inputs: (char*) BPS_buffer - a char pointer to the partial gps string to be parsed

(int) buff_len - the size of the gps_buffer, can range from 1 to 64 chars

Outputs: returns a status based on whether the parse is completed or not

---------------------------------------------------------------------------------- */

unsigned char ParseBPS( unsigned char *BPS_buffer, unsigned char buff_len)

{

unsigned char index = 0;

unsigned char status_return = BPS_PARSING_INCOMPLETE;

static unsigned char BPS_state = BPSS_START;

static unsigned char battery_num = 0;

static unsigned char data_field = 0;

if( (buff_len >= MIN_BPS_BUFFER_LENGTH)

&& (buff_len ................
................

In order to avoid copyright disputes, this page is only a partial summary.

Google Online Preview   Download