You are on page 1of 45

Proof of Concept Implementation With the SPARTAN 3E FPGA Evaluation Board for the CAL POLY SuPER Project

By Tony Wonsyld

Senior Project

ELECTRICAL ENGINEERING DEPARTMENT California Polytechnic State University San Luis Obispo 2008

TABLE OF CONTENTS
Section Page

Acknowledgments..4 I. Introduction...5 II. Background7 III. Requirements.9 IV. Hardware Design and Configuration ..11
PWM Signal and Timer/Counter..11 Sensor ADC and Pre-Amp...13 MUX Layout and Control....14 Data Logging and Memory Control.17 Load Switch Control and LED Verification....20 LCD User Display....21 V. Software Integration23 VI. Testing and Verification.25 A. ADC and MUX.25 B. Memory26 C. PWM Output....27 D. Overall Timing.28 VII. Recommendations.31 VIII. Conclusions33 A. B. C. D. E. F. Appendices A: Bibliography32 B: UCF File..33 C: C Software File and Headers...35 1. Main.c.35 2. Lcd.c and Lcd.h..39 3. Inputs.c and Inputs.h 4. Output.h.. 5. IntC.c and IntC.h 6. Spi.c and Spi.h. D: Senior Project Analysis.

List of Figures
Figures Page

Figure 2.1: Current Phase 1 Block Diagram..6 Figure 2.2: Projected Block Diagram Using A Spartan 3E FPGA..8 Figure 3.1: Spartan 3E FPGA Development Kit..10 Figure 4.1: Analog-to-Digital Converter Interface..13 Figure 4.2: Detailed View of Analog Capture Circuit..14 Figure 4.3: Functional Diagram and Truth Table For The LF 13508 MUX16 Figure 4.4: DDR Controller Clocking Option For Asynchronous System18 Figure 4.5: Functional Block Diagram For On-Board DDR SDRAM..19 Figure 4.6: Character Display Address Map For The LCD...21 Figure 4.7: Sectioned LCD Screen Design22 Figure 5.1: Software Flow Diagram...24 Figure 6.2: Excerpt From main.c Program for Memory Test26 Figure 6.3: PWM Output27

List of Table
Figures Page

Table 4.1: Programmable Gain Settings For The Pre-Amp...15 Table 6.1: A/D Conversion Accuracy25 Table 6.2: Elapsed Time for a Single Poll29 Table 6.2: Lower Time Bound of System 30

Acknowledgments
I would like to thank Dr. Harris for bringing me on-board and letting me be involved in this wonderful program. I cannot tell you how much Ive learned. Also, my family who have all been so supportive, especially my mother and father, who I have everything to thank because of them. I love you so much. Lastly, I would like to thank Tom Hickock, for all of your help and wisdom. Your knowledge is priceless.

I. Introduction
In 2005, Dr. James Harris presented his white paper discussing a proposed activity to develop a low-cost, sustainable source of solar power with a 20 year life cycle[1]. The project is intended to help financially troubled regions with high levels of solar radiation. In an ever-growing weak global economy, where government aid and humanitarian projects lack funding, a possible solution has been brought to research by the members of Cal Polys Sustainable Power for Electronic Resources (SuPER). With solar technology and energy conversion efficiency increasing every year, Dr. Harris, along with Dr. Ali Shaban and various EE and CPE students have started a prototype that aims to solve the fundamental problem of power distribution and affordability. The idea is to harness solar energy via a solar panel to bring energy to household necessities such as lighting and refrigeration for a cost of under $500. Currently the project is still in Phase 1 and the estimated price tag is about $1500, but great strides and improvements have been made along the way. This project will help move into Phase 2 by producing a proof of concept that will dramatically reduce overhead by replacing the current laptop with an FPGA device. The lab top acts as the central device that stabilizes the entire system and processes all the data and controlling algorithms. Technology has brought the FPGA industry into the high performance market of computers, yet can be reprogrammed rapidly to adapt to changing circumstances and environments. For greater control and reliability, progress is currently underway to install an OS onto the FPGA [12]. This project focuses on the actual interface functions for the FPGA to handle.

II. Background
The system is currently controlled by a laptop computer. The laptop is the interface between data acquisition, the PIC microcontroller, the DC-DC converter, and the MOSFET switches, shown in Figure 2.1. It is an integral component to the functionality of the SuPER design, but consumes a large portion of power and is also very costly.

Figure 2.1: Current Phase 1 Block Diagram [7]

In order to make the design more economically feasible, an FPGA is proposed to substitute for the laptop. An FPGA offers a powerful alternative in terms of accessibility, cost, and speed. The Spartan 3E development board is capable of performing all the necessary control and acquisition requirements at a fraction of the cost. Not only will the laptop be replaced but also several other components: TTL-to-Serial Converter, PIC Microcontroller, and two NiDAQ 6009s. The Spartan 3E runs at 50MHz and can be tailored to the users demands. The only significant drawbacks are to the user interface and available on-board memory. The system uses the Xilinxs EDK to configure the FPGAs hardware and create and update the software. The Spartan 3E comes with an LCD display and is the only available interface for the user to verify and check data and address values. It is limited in physical size, but along with other troubleshooting and measurement devices, such as scope probes and logic analyzers, the designer can gather enough information to verify the systems functionality. With all of its on-board hardware, the development kit satisfies current demands as well as possible future additions such as a PS2 module for a keyboard or other user interface I/O. Below, in Figure 2.2, is a simplified block diagram with the Spartan 3E as the central controlling component. As you can see, several parts are cut out of the design and will be replaced with on-board devices and internal modules. Other additions have been added to the overall project, like the pyrometer and thermocouple, which need new routed signals for future operation. Two multiplexers will be added to handle all sensor signals, instead of the NiDAQ 6009s, because the Spartan 3E has a limited A/D interface.

Thermocouple PV Array

Pyrometer

PWM Signal 5

DC/DC Converter

Sensors

FPGA

32:1 MUX Battery

Note: Does not show sensor placement or MOSFET switch outputs from FPGA

DC Motor

TV

LEDs

Fridge

Figure 2.2: Projected Block Diagram With A Spartan 3E FPGA

Requirements:
As stated in his thesis, Eral Tan [8] understood and realized the importance of replacing the PC with an FPGA. The entire system could efficiently be controlled and thereby limit the power consumption and wiring complexity. Brian Estrada and Patrick Mariano [3] furthered this idea with their senior project porting UClinux to the Spartan3E development board from Digilent Inc. Thus, the requirements for the system are: Ensure the battery is being charged/discharged properly via switch control and sensor monitoring. Adjust the PWM signal to the DC-DC converter according to the MPPT algorithm. Create multiplexing and interfacing design to handle all sensor data lines. Allow user to select desired loads via the on-board switches. Allow for emergency shut-off to all loads and hardware to protect against reversed currents and current overload with a response time of 1/100 seconds. Log and display all sensor data. Do all above requirements within a period of at least 1/10 of a second or faster. Due to the flexibility of the Spartan-3E board we will be able to replace several expensive components and ultimately lower the wiring complexity and simplify the user interface. The Spartan 3E will allow the designers to remove with the PIC

microcontroller and TTL-to-serial converter, along with the USB interface consisting of the two National Instrument 6009 DAQs.

Figure 3.1: Spartan 3E FPGA Development Kit The Spartan-3E development board has over 100 I/Os that can handle all of the systems proposed 32 signals according to Estrada and Mariano [3]. Due to the design of the FPGA, half of those I/Os are shared with the FX2. In reality, there are only about 50 usable pins to interface the system. This allows us to either directly connect each system signal line to the board or to create a generic MUX design to handle the multiplexing. This latter approach would significantly reduce the number of I/O signals coming off the board to a few data lines, but would also require several MUX selector lines if the design is external to the board. The Spartan-3E has on-board ADC and DAC to handle the sensor conversions. The sensors will require a simple voltage divider to bring the voltage level within a 0-5V range and can easily be implemented with an additional PCB design. The Spartan-3E has 16Mbytes of RAM and 4Mbytes of Flash. Estrada and Mariano [2] suggested that uCLinux operating platform will require a major portion of

10

the flash memory and further stated that an external memory device may need to be implemented to store a reasonable amount of senor data. This will not be a large expense, but a necessary one. In order to log a sufficient amount of the sensor data, including time stamps, the on-board memory devices, such as SDRAM, would not be a viable solution. Converting and logging the sensor data, as well as monitoring the MOSFET switches, can easily be performed to satisfy the timing requirements above. The Spartan-3Es clock can be varied to run at 25, 50, or 100MHz, so timing constraints should not be a factor and should allow ample time to cycle through the design program. The Xilinxs MicroBlaze (uBlaze) Embedded Development Kit (EDK) will be the softcore-based operating platform. MicroBlaze EDK has numerous IP cores that give designers pre-made modules through user friendly software. The platform allows the user to custom tailor their designs by adding modules and adjusting their parameters to fit their design needs. In particular, there is a timer/counter IP core that can be designed specifically as a PWM generator. This module will produce the required PWM scheme according to the MPPT algorithm, and can connect to the high-side driver that drives the DC-DC converter.

11

Hardware Design and Configuration


PWM Signal and Timer/Counter
As stated in the last section, the MicroBlaze EDK supports a Timer/Counter IP core that can operate in several timing modes. The IP core can be configured using two separate counter registers within the core architecture that act as a PWMs period and duty-cycle. Witts[9] had found the ideal operating frequency to be 25 kHz for the DCDC converter; therefore, this system was modeled according to that specification. The PWM core also offers an interrupt signal which is connected to the Interrupt Controller IP core to maximize the codes efficiency, since the system will not have to poll the PWM to check its status. The interrupt is sent to the uBlaze processor and the proper interrupt service routine (ISR) is followed. Within this routine, a pseudo-MPPT algorithm was created to adjust the duty-cycle according to a specific power supply voltage acting as a system sensor. The original MPPT algorithm is very complicated and requires several of the systems status signals and sensor readings in order to calculate the proper operating mode and duty-cycle adjustment. Another requirement of the design is providing all acquired sensor and system data a time-stamp. This allows to the user/designer to add a timeline to the gathered information. It is important to be able to distinguish different data points, and plot trend lines for error correction, power, and comparisons. Since the system has a desired duty cycle of at least 1/10 of a second, an internal clock is implemented with .1s period increments, which will provide sufficient accuracy and precision. The easiest solution is use the 25 kHz PWM generated signal and implement a simple software algorithm that increments a counter every 250 times the PWM ISR is accessed: 12

(1/25 kHz) * 2500 = .1s Every logged data point will be concatenated with this count value. The counter width will have a maximum width of 16 bits (due to the memories data interface). This will give a rollover time of: (2^16 1) * .1s = 1.82 Hours That allows plenty of time to gather sufficient data before the system backs up all saved data to another larger storage device or simply begin writing over pre-existing entries. It should be noted, though, that if the PWM desing frequency changes, the timer in software must be adjusted as well. As of now, the timer accuracy is dependent of PWM frequency and should be changed future stages of the FPGA integration into the SuPER system.

Sensor ADC and Pre-Amp


The Spartan 3E development kit has an ADC, DAC, and a pre-amp chip on-board. For the purposes of this project, only the ADC and pre-amp will be used (see Figure 4.1). The ADC is a LTC 1407A-1 and the pre-amp is a LTC 6912-1, and they work concurrently when sampling analog data using a serial peripheral interface (SPI). The maximum sampling rate is approximately 1.5MHz, which is a total sample period (conversion + acquisition period) of 667ns for the ADC [3].

Figure 4.1: Analog-to-Digital Conversion Interface [3]

13

It requires 34 SCK cycles (SPI clock) to convert a sample analog input to digital data, including conversion and acquisition times. The SCK, therefore, can operate at maximum of 50 MHz. The Pre-Amp has a clock limitation of 10MHz [6], so the maximum system clock to SCK ratio is 5:1. The SPI IP core in Xilinxs EDK allows for several parameterized configuration options regarding the two clock ratios. A ratio of 16 (system clock / SCK) was chosen to allow for extra design leeway, but, if necessary, a higher ratio of 8 can be implemented. The complete analog capture circuit below demonstrates the SPI interface with both devices and the Spartan 3E pin assignments. The SPI has a tri-stated output and is configured as the master, while each subsequent device are defined as one-hot encode slaves to the master, thereby ensuring only one device is selected at a time and wont block communication on the bus.

Figure 4.2: Detailed View of Analog Capture Circuit [3]

14

The ADC is a dual channel device which samples two separate signals during the same SPI read cycle. For system testing purposes, channel 0 is used solely while the other channel is left unconnected. It should be noted that during the SPI read cycle, both 14-bit samples are properly placed into separate channel variables within the C code of the project.

Table 4.1: Programmable Gain Settings for the Pre-Amp [3] A gain of -1 was chosen primarily because it offered the largest input voltage range, which, in return, will make scaling the input sensor voltages much easier. The ADC output is a twos complement value where the output is equated by:

In order to make it more readable, some data processing must be implemented to solve for the actual Vin voltage. By solving for Vin, the user can compare the result directly with an oscilloscope or voltmeter to check the accuracy. The old system used two NiDAQ 6009s which interfaced between the sensors and the laptop and each input sensor was multiplexed via software over the USB connection. The two possible solutions for multiplexing the data using the FPGA are: 1. Connect each signal to I/O pin on the board and multiplex using C or a VHDL state diagram.

15

2. Use an external N:1 MUX connected to the ADC (or N/2:1 using both ADC channels) , which requires a certain amount of selector lines. Due to the lack (i.e. over-lapping) usable I/O pins, it was decided to use solution 2, an external MUX, which will also reduce the complexity of the FPGAs internal software algorithm and also allow for easier signal troubleshooting.

MUX Layout and Control


The current SuPER design uses 21 sensors and 11 switches to monitor and control the entire system. There are plans to add at least an additional three signals for the ultracapacitor, and more for other components. Therefore, to allow for the additions, this design recommends planning for 32 individual input sensors. Since the ADC offers two channels, the most efficient MUX solution would be implementing two separate selector devices to maximize throughput. This will require two 16:1 MUXs, each requiring four selector control lines, a chip-enable, and supply voltages. The selector lines are defined in the uBlaze project as general-purpose I/Os (GPIOs). The GPIOs can be configured to any data width (< system data bus width) and can varied within software to select the desired channel.

Figure 4.3: Functional Diagram and Truth Table for LF 13508 MUX [5].

16

As a proof of concept, this design used an available analog MUX from the EE department. Two LF 13508 8-channel analog multiplexers, in Figure 4.3, were acquired and wired to a bread board that comes with the Hirose FX2-100P-1.27DS expansion kit[3] . To show that the system can handle switching between different sensors, two MUX input lines were connected to separate power supplies so act as voltages coming from two separate sensors. The other MUX input lines were grounded in order to make sure the device did not malfunction due to floating pins. This particular MUX has a worst case switching speed of 1.8s, therefore, an entire sweep of all sixteen inputs causes a delay of: 16 * 1.8s = 28.8s This delay can be minimized by switching the control lines in the program when other processes are being performed that dont require the current value of the sensor data such as data processing or memory writes and reads. The inputs will be simply changed by incrementing the value of the GPIO MUX register value in software. The width is pre-parameterized to equal to 3 and the output will follow the truth table shown above. Once 111 has been sampled and stored, incrementing it will start the address back over to 000.

Data Logging and Memory Control


The Spartan 3E has a Micron (MT46V32M16) 64Mbyte DDR SDRAM chip, 16bit data interface that can be accessed through a DDR SDRAM IP Memory Controller core within uBlaze. Since the controller requires two fast clocks, out of sync by 180 degrees, two additional Digital Clock Managers (DCM) (Figure 4.4) are needed to

17

ensure proper timing and eliminate clock skewing. Clocking is the most important issue facing the memory interface, and below is the clocking scheme used to connect the DDR SDRAM Controller to memory and the FPGA. The External Clock below was used as the OBP clock initially, which caused problems due to clock lagging through the top DCM. By switching the OPB clock to the output of the top DCM, the system resembled the recommended clocking setup more precisely and worked accordingly. The DCMs also require buffers for the clock outputs to clean up the signals before being passed to the DDR SDRAM controller. Because the clock rate is so high, it is very susceptible to noise which can comprimise the signal.

Figure 4.4: DDR Controller Clocking Option for Asynchronous System [11] The DDR SDRAM Controller acts as an intermediate device which connects the OPB bus and all other necessary control lines to the on-board memory device. The physical connections can be viewed in Appendix B, the UCF file, that uBlaze uses to route the net signals to external pins. As aforementioned, the A/D values are 14-bit, and

18

can fit into one memory address, but offer little extra room for the time stamp. For each sensor value, its time stamp will be stored in the address space above it. With a maximum of 32 sensors, this leaves a total of: 32M/32 = 1M individually logged data samples, before the DDR SDRAM is full. The address is 15-bit addressable, which includes the two bits to signify which bank is being accessed. The memory device itself is broken into four banks and the details of which are handled by the DDR SDRAM Controller internally. The memory can be easily written to and read from through assignment statements in software.

Figure 4.5: Functional Block Diagram For On-Board DDR SDRAM [4] After initialization, which is handled by the controller, the memory goes through a software check to ensure all addresses are being accessed and all data is being read/write

19

properly. Since the memory device is double data rate (DDR) and has a parallel connection (Figure 4.5), the read/write times are on the order of eight clock cycles, where the clock rate is the system clock, running at 50MHz. This will amount to a delay of less than .2s per memory write.

Load Switch Control and LED Verification


As with the MUX control lines, the load switch control lines are treated as GPIOs that are mapped to specific I/O pins on the FPGA. These load lines act as the MOSFET switch signals that allow the loads to turn on, while being powered by the battery. The idea behind the design is for the on-board LEDs to act as visual verifiers to the status of the selected loads. The Spartan 3E comes with four on-board switches that are active high in the up position. The user can select a desired load to be turned by flipping a switch and the corresponding LED will illuminate. Part of the requirement is to shut-off a load if a given threshold is reached, be it a current, voltage or temperature warning level. The basic algorithm takes into account the switch position and corresponding sensor information for a particular load. If the sensor information is within safe operating conditions, then the LED will illuminate, and the mapped I/O pin will output 3.3 V when in the ON position. If the threshold is breached, then regardless of the switch position, the LED will deactivate and MOSFET load control signal will be brought to ground, 0V. Throughout the main polling software algorithm, the status of the switches and corresponding sensor data will be checked and subsequently turn ON/OFF the LEDs and MOSFET switches accordingly.

20

At this moment, there are a five system loads and the Spartan 3E has only four switches. For experimental purposes this offers enough user input to conduct the proof of concept design, but will need additional hardware to be able to interface the entire SuPER system design. The Spartan 3E I/Os have a switching speed of 5ns, much faster than the system clock frequency. This ensures that when emergency shut-off levels are reached the system will disable the MOSFET switch control lines and protect the system devices and circuitry.

LCD User Display


The Spartan 3E Development Kit features an LCD that comes with an internal controller with which the FPGA communicates with the display. The controller uses three control lines and four data lines to interface with the device. Older Spartan versions had an eight-bit data line interface; in order to communication properly, the controller is fed two four-bit nibbles to via the data interface. The display itself is limited in size and can handle a total of 32 characters (Figure 4.6).

Figure 4.6: Character Display Addresses Map For The LCD [3] Therefore, the design is limited to how much information the user can display at one time. For our purpose, the screen was split into four sections shown in Figure 4.7.

21

ADC Channel 0 Output

ADC Channel 1 Output

ADC Channel 0 From Memory

ADC Channel 0 Time Stamp From Memory

Figure 4.7.: Sectioned LCD Screen Design This configuration allows the designer to monitor important sensors and time values for verification purposes. The big drawback is not allowing user input to change the data being displayed. This is a static display design for proof of concept purposes only. Later, the report will offer possible solutions and recommendations.

22

V. Software Integration
After building the uBlaze project with the described components above, software must be added to make each module communicate with each other and external devices. It produces a VHDL file that specifies names associated with each module. By using those pre-defined names in software, the programmer can interface with each of the components via the OPB bus. The EDK platform is capable of quickly adding pre-made C files and header files. Each I/O pin has a specific pin value that is associated with certain module components and GPIO. These pins are declared in the UCF and lets uBlaze know where to be expecting the signals, while EDK takes care of all of the routing. Figure 5.1 shows the flow diagram for the entire system design. Most of the modules used within uBlaze, as mentioned before, require some initialization. Appendix C includes C files and headers in full detail with comments to explain the process better. Included in the ISR is the pseudo MPPT algorithm, which better explains how the PWM is changed depending on battery voltage levels. The start-up mode increases the duty cycle much faster to reach normal range, where the MPPT is truly needed and most efficient. That is why it increments using 5% steps until it reaches 35%, then the increase/decrease step becomes about .5%. Since the ISR is entered at a frequency of 25 KHz, the small step size can still have a major effect in the overall duty cycle compared to the systems 1/10 second polling period. The quicker the PWM can adjust to the isolation levels of the PV array, along with battery power level, the more responsive the DC-DC converter.

23

Main:

ISR

Initialize Timer/ Counter to 25KHz PWM Mode Increment Duty Cycle by 5%

Is in StartMode? N N N Battery < 2.5V N

Initialize Interrupt Controller, LCD, and SPI

Is Battery <1.5V? Y

1.5V <= Battery < 2V? Y

Set LED, MUX, and LOAD GPIOs as Outputs

Duty Cycle is <35%? N Y Increment Duty Cycle by ~.5% Duty Cycle Unchanged Decrement Duty Cycle by ~.5% Duty Cycle = 0%

Set SWITCH GPIO as Input

Switch to Monitor Mode Clear Interrupt Bit

Set Pre-Amp Gain to -1 Via SPI Write Return Enable MicroBlaze and IntC Interrupts

Sample A/D Channels

Increment MUX by 1 and Mem. Addr by 4

Process A/D Values

Read Back From Memory (data and time)

Display A/D Values on LCD

Write A/D Value(addr = i) and Time Stamp(addr = i+1) to Memory

Figure 5.1: Software Flow Diagram Once all initializations are completed and interrupts are enabled, the program enters into its polling algorithm. Here, the MUX selects the proper analog signals to pass through to the ADC where they are sampled, processed, and stored. For user verification purposes, those stored memory values are read back out to compare them acutal ADC values on the LCD, along with the time stamp. The memory address MUX control lines are then incremented before the process begins all over again. 24

VI. Testing and Verification


Sensor ADC and MUX
Two separate power supplies were connected to S0 and S15 on the MUX while the system polled through all sixteen MUX inputs and the LCD only displayed the two operating inputs. Table 6.1 shows the accuracy of A/D conversion and data processing results. The actual voltage was read using an oscilloscope probe. The lower limit for the ADC was found to be at about .78 volts, rather than .4 volts specified in the Spartan 3E data sheet[3]. The high limit was around 2.9V, which agrees with the spec sheet.

CH 0 (V) 0.8 0.88 0.93 1.04 1.21 1.46 1.77 2.05 2.28 2.53 2.79 2.92

CH 1 (V) 0.78 0.85 0.92 1.04 1.24 1.43 1.74 2.06 2.29 2.54 2.8 2.85

Actual (V) 0.74 0.81 0.88 1 1.21 1.4 1.74 2.01 2.25 2.5 2.76 2.89

%error (CH0) 8.11% 8.64% 5.68% 4.00% 0.00% 4.29% 1.72% 1.99% 1.33% 1.20% 1.09% 1.04%

%error (CH1) 5.41% 4.94% 4.55% 4.00% 2.48% 2.14% 0.00% 2.49% 1.78% 1.60% 1.45% 1.38%

Table 6.1: A/D Conversion Accuracy

The results verify that ADC is working properly, yet there is relative error (>5%) associated with some data points. One reason of excess error is due to the 15V analog power supplies used in the test. They are not capable of accurate output voltages below 1V, which is seen in the lower ADC readings. As the voltages are increased, the error

25

seems to be diminished. One solution would be to use a voltage divider or potentiometer with a constant 5V to get more accurate voltage readings from the power supplies.

Memory
The DDR SDRAM memory passed all initialization tests during the start-up of the system. The test below in Figure 6.2 is an excerpt from the main.c software file (Appendix C) that writes to every address and reads back from that address to verify the proper data was stored.

for (a = 0; a < SDRAM_MAX; a++){ SDRAM[a] = a & 0xFFFF; if ((a&0xFFFF) !=SDRAM[a]) fail = true; }

//stores value a at address a //checks each address for correct value //if wrong, fail = true

while(fail){ //displays -1, repeatedly on LCD display_num(-1) } Figure 6.2: Excerpt From main.c Program For Memory Test If this test ever fails, a -1 will appear in the upper left of the LCD. The test passed every time the program was loaded onto the board, and has yet to fail. The variable a is masked with 0xFFFF to ensure that any data being passed to SDRAM is only 16-bit wide. After passing the test, the program enters into the polling algorithm where sensor data is stored, along with the time stamp, in the address above it. The LCD verified this result as well. The value in memory matched exactly to the input voltage applied to the ADC. The SDRAM memory appears to work and do so quickly enough to pass the requirements stated.

26

One small glitch occurs and a fix has not been found yet. There is threshold of around 1.6 volts and below where LCD periodically adds 130mVs to ADC value. Both of those values are related to the ADC conversion equation and were factoring into the softwares conversion of the data. The problem was solved by introducing temporary variables to do all data processing and manipulation. The temporay variables passed the processed sensor data to variables that only were called by the LCD displays and memory R/Ws.

PWM Output
The PWM output signal performed as designed, according to the pseudo-MPPT algorithm. In order to get a better visualization of the signal, the PWM period was slowed down to 25Hz so measurements could be taken of the duty cycle step size. During the start-up mode, the duty-cycle increases by 5% until 35% was reached, at which point, by adjusting the incoming channel 0 ADC voltage, the duty cycle could be increased or decreased by ~.25% steps. Figure 6.3 are snapshots of the PWM right at start-up, and the increase can be seen quite clearly. The top is the initial 5% duty-cycle followed by the next ISR iteration, (b), where the duty cycle is 10%. Furthermore, as the voltage is raised above 2.5V, not only does the PWM duty-cycle drop to zero, the LED corresponding to that battery load line shuts off, demonstrating the emergency shut-off requirement was also met. The purpose was to show that a clean PWM signal can be produced and adjusted in real-time to increase efficiency and this point was well verified.

27

(a)

(b) Figure 6.3: PWM Output at (a) 5% and (b) 110%

Overall Timing
For a single cycle through the polling algorithm the following times have been estimated according to their spec sheets and code length. Code length calculations are estimated by the following: (1) Each C code line takes five assembly instructions, (2) each assembly instruction takes two clock cycles, and (3) each clock cycle takes 20ns. The A/D conversion time covers two sampled sensors and the memory write time is based on four writes two for each sensor data sample and two for their corresponding time stamp. With these measurements the lower and upper timing bounds, including sampling every sensor, can be extrapolated.

28

The PWM ISR contains as estimated 20 lines of code. Therefore, the PWM ISR will take: (20 lines) * (5 insn/line) * (2 cycle/insn) * (20 ns/cycle) = 6us Like wise, the remainder of the polling loop contains an estimated 15 lines of code, not including verification tests such as LCD writes and memory reads. The code is comprismised of data processing and emergency tests. The approximated elapsed time is: (15 lines) * (5 insn/line) * (2 cycle/insn) * (20 ns/cycle) = 3us As stated before, the ADC sample period is estimated at 10.25us and a memory write is estimated at .2us per write. Table 6.2 is a summation of the software polling loop.

Time (us)

A/D Conversion 10.25

Memory Writes (X4) 0.8

Other Code 3

Polling Cycle Time 14.5

Table 6.2: Elapsed Time for a Single Poll The lower bound, i.e. the quickest the system could sample of the sensors, can be calculated by taking the single polling duty cycle time and multiplying it by the number of iterations to sample the remaining sensors: (14.5 us/sample) * (16 samples) = .232 ms During the above elapsed time, the PWM ISR will be called every 40us, thereby being executed: (.232ms) / (40us) = 5.8 times, totaling a time of: 5.8 * 6us = 34.8us

29

Table 6.3 is a summation of lowest possible limit the system can operate approprieately.
Polling Cycle Time 14.5us Total Sampling Time ISR Time 0.234ms 3.48us Lower Bound .267ms

Time

Table 6.3: Lower Time Bound of System Therefore, the system could theoretically process all of the information and control signals in .267ms, which is well below this projects timing requirements of 1/10 of second. On the other end of the spectrum, if the design sticks with the proposed system duty cycle time of 1/10 of a second, the design team could take multiple samples of each sensor and only store the average value. This idea has merit because it would store a more accurate reading of the sensors actual value. By taking an averaging, each sensors data is effectively smoothed out from any discrepancies or spikes that might appear in the signals. Therefore, each sensor can be sampled approximately: 100ms/.234ms = 375 times More testing would need to be made, of course, because this is only a preliminary estimation according to the data gathered as of yet. The above number will turn out to be too large for the actual system because as the complexity of the software increases, the single polling duty cycle will as well. Yet, taking multiple samples for each sensor will increase the reliability of the overall system and help ensure proper control of the external devices.

30

VII. Recommendations
Though the Spartan 3E has real potential for replacing the current laptop and other hardware, there are still a few items that need to be worked out. First, the current data logging scheme based solely on the on-board DDR SDRAM requires attention. Since the memory is static, data will be lost every time the system is shut-down, thereby losing valuable experimental data. To circumvent the static memory, it would be recommended to use an additional external non-volatile memory device that the DDR SDRAM can dump its data into after reaching capacity. The FPGA offers a few ports that could be interfaced to allow this transaction, but would come at a cost to the performance of the overall system. In order to transfer the sensor data and timing information, a new process must be implemented into software to control the operation. This would cause a momentary lapse in the system monitoring process that could allow for adverse consequences. It is possible to elegantly set up the memory dump using interrupts instead of polling to minimize the systems break from system control. Secondly, it is recommended that the software take multiple samples of the sensors and then average out their values. The upper bound of 375 samples per sensor is a little unrealistic. As mentioned before, the polling algorithm will definitely increase as the design becomes more complicated and that upper bound will shrink. This will ultimately save memory which, as already stated, will be an issue. Thirdly, as stated by Mariano and Estrada [2], adding a monitor and keyboard would offer a much better user interface. While the LCD allows for some data verification, the size and real-time configurability can be vastly improved. In order to look at different data, the entire project must be programmed, complied, and downloaded

31

to see the results. Adding an OS will give the user much more control via a monitor and keyboard to actively access control algorithms and make changes without rebooting the system, thereby losing memory data. The Spartan 3E has a PS2 and COM port already built on, so some additional hardware would not be needed. The EDK design would need to add a few modules, possible a UART or other communication core to interface to these components, but overall would not affect the size or speed too much if interrupts are used. Lastly, the Spartan 3E has an output logic high voltage of 3.3V, which is not high enough to drive the MOSFETS or DC-DC converter. Additional circuitry will be required to boost the output signals to their required level by use of buffers. On the other side, step down voltage circuits must also be made to ensure all sensor voltage levels are within the required range of .7V-2.9V. New software must be implemented to make sure voltage conversions are accurately calculated in reference to the MPPT algorithm and emergency shut-off thresholds.

32

VIII. Conclusions
It was found that Spartan 3E Development Kit board is strongly suited for reproducing the capabilities of the current laptop controlling the SuPER system. The cost alone is a great reason to continue on with an FPGA centralized design. The Spartan 3E evaluation board retails for around $150, compared to $600 laptop. This will bring the price down much closer to the target price of $500. The other major system requirements reliability and lower power consumption are satisfied. The fewer number of parts used, the less the chance of something breaking. Reducing the number of components is directly correlated to reducing failure. The FPGA industry has proven to produce reliable and low power devices, and continue to improve upon the design. The next step is to get the OS onto the FPGA. More work has been done this quarter, but there are still many hurdles to overcome due to the lack of documentation and experimental research. Once the FPGA has an OS, it can better emulate the laptops functionality within the system. As for now, it has been shown that the I/O abilities of the Spartan 3E are capable of controlling all of the external components within the system. The research and data gathered from this project will give the next generation of SuPER students a strong base to build upon. The major requirements are now known to be satisfied, but some need adjustment and further investigation in regards to the performance limits and user interface. None the less, the vision of low-cost, sustainable energy is moving closer to reality and hopefully this, along with other SuPER research projects can help pave the way.

33

Appendix A
Bibliography [1] Harris, James G. White Paper for Sustainable Power for Electrical Resources SuPER [http://courseware.ee.calpoly.edu/~jharris/research/super_project/white_paper_ super.pdf] [2] Estrada, Brain and Mariano, Patrick Development of UCLinux Platform for Cal Poly SuPER Project [http://courseware.ee.calpoly.edu/~jharris/research/super_project/be_pm_sp.pdf] [3] Spartan-3E Board User Guide [http://www.xilinx.com/support/documentation/boards_and_kits/ug230.pdf] [4] MT46V32M16 (32M x 16) DDR SDRAM Data Sheet [http://download.micron.com/pdf/datasheets/dram/ddr/512MBDDRx4x8x16.pdf] [5] LF 13508 MUX Data Sheet [http://rbsfm.ej.am/Downloads/Datasheet/LF/LF13508.PDF] [6] LTC6912 Dual Programmable Gain Amplifiers with Serial Digital Interface [http://www.linear.com/pc/downloadDocument.do?navId=H0,C1,C1154,C1009,C 1121,P7596,D5359] [7] Sheffield, Tyler Cal Poly SuPER System Simulink Model and Status of Control System [http://courseware.ee.calpoly.edu/~jharris/research/super_project/ts_thesis.pdf] [8] Tal, Eran SuPER System Prototype Design and Implementation [http://courseware.ee.calpoly.edu/~jharris/research/super_project/et_thesis.pdf] [9] Joseph Witts Cal Poly SuPER System Photovoltaic Array Universal DC-DC Step Down Converter [http://courseware.ee.calpoly.edu/~jharris/research/super_project/jw_thesis.pdf] [10] Digilient Inc. Tech Support Email support@digilentinc.com [11] MicroBlaze OPB Double Data Rate (DDR) SDRAM Controller (v2.00b) [http://www.xilinx.com/support/documentation/ip_documentation/opb_ddr.pdf]

34

Appendix B
# UCF for SuPER Prototype Project # # # # Created by: Tony Wonsyld # ################################### NET "sys_clk" LOC = "C9" ;

# No pulldown in schematic, needed here NET "sys_reset" LOC = "K17" | PULLDOWN; #Feedback clk for DCM NET "fb_clk_pin" LOC = "B9" |IOSTANDARD = LVCMOS25; NET NET NET NET NET NET NET NET NET NET NET NET NET NET NET "led_pin<7>" "led_pin<6>" "led_pin<5>" "led_pin<4>" "led_pin<3>" "led_pin<2>" "led_pin<1>" "led_pin<0>" "lcd_pin<6>" "lcd_pin<5>" "lcd_pin<4>" "lcd_pin<3>" "lcd_pin<2>" "lcd_pin<1>" "lcd_pin<0>" LOC LOC LOC LOC LOC LOC LOC LOC LOC LOC LOC LOC LOC LOC LOC = = = = = = = = = = = = = = = "F12" ; "E12" ; "E11" ; "F11" ; "C11" ; "D11" ; "E9" ; "F9" ; "R15" "R16" "P17" "M15" "M18" "L18" "L17" ; ; ; ; ; ; ; # # # # # # # # # # # # # # # LED LED LED LED LED LED LED LED LCD LCD LCD LCD LCD LCD LCD 0 1 2 3 4 5 6 7 Data Data Data Data E RS RW 0 1 2 3

NET "spi_SCK_pin" NET "spi_MOSI_pin" NET "spi_MISO_pin" NET NET NET NET NET "spi_SS_pin<0>" "spi_SS_pin<1>" "spi_SS_pin<2>" "spi_SS_pin<3>" "spi_SS_pin<4>"

LOC = "U16" ; LOC = "T4" ; LOC = "N10" ; LOC LOC LOC LOC LOC = = = = = "P11" ; "N7" ; "N8" ; "U3" ; "C18" ;

#SPI clock #SPI Write pin #SPI Read pin # # # # # AD_CONV for ADC Preamp Chip Select DAC Serial Flash

NET "pwm_pin" NET NET NET NET NET NET NET NET NET "buttons_pin<4>" "buttons_pin<3>" "buttons_pin<2>" "buttons_pin<1>" "buttons_pin<0>"

LOC = "D7" ; LOC LOC LOC LOC LOC LOC LOC LOC LOC = = = = = = = = = "V16" "K18" "G18" "D18" "H13" "L13" "L14" "H18" "N17" | | | | | | | | |

#PWM out signal PULLDOWN ; PULLUP ; PULLUP ; PULLDOWN ; PULLDOWN ; PULLUP PULLUP PULLUP PULLUP ; ; ; ; # # # # # ROT_CENTER ROT_A ROT_B BTN_WEST BTN_EAST 0 1 2 3

"switches_pin<3>" "switches_pin<2>" "switches_pin<1>" "switches_pin<0>"

#Switch #Switch #Switch #Switch

35

NET "mux_pin<2>" LOC = "A6" ; #MUX controll line 0 NET "mux_pin<1>" LOC = "B6" ; #MUX controll line 1 NET "mux_pin<0>" LOC = "E7" ; #MUX controll line 2 NET NET NET NET "loads_pin<3>" "loads_pin<2>" "loads_pin<1>" "loads_pin<0>" LOC LOC LOC LOC LOC LOC LOC LOC LOC LOC LOC LOC LOC LOC LOC LOC LOC LOC LOC LOC LOC LOC LOC LOC LOC LOC LOC LOC LOC LOC LOC LOC LOC = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = "B4" "A4" "D5" "C5" "P2" "N5" "T2" "N4" "H2" "H1" "H3" "H4" "F4" "P1" "R2" "R3" "T1" ; ; ; ; | | | | | | | | | | | | | #Load #Load #Load #Load IOSTANDARD IOSTANDARD IOSTANDARD IOSTANDARD IOSTANDARD IOSTANDARD IOSTANDARD IOSTANDARD IOSTANDARD IOSTANDARD IOSTANDARD IOSTANDARD IOSTANDARD lines lines lines lines = = = = = = = = = = = = = 0 1 2 3

#SRAM Addrs pins NET "sd_a_pin<0>" NET "sd_a_pin<1>" NET "sd_a_pin<2>" NET "sd_a_pin<3>" NET "sd_a_pin<4>" NET "sd_a_pin<5>" NET "sd_a_pin<6>" NET "sd_a_pin<7>" NET "sd_a_pin<8>" NET "sd_a_pin<9>" NET "sd_a_pin<10>" NET "sd_a_pin<11>" NET "sd_a_pin<12>" #SRAM data pins NET "sd_dq_pin<0>" NET "sd_dq_pin<1>" NET "sd_dq_pin<2>" NET "sd_dq_pin<3>" NET "sd_dq_pin<4>" NET "sd_dq_pin<5>" NET "sd_dq_pin<6>" NET "sd_dq_pin<7>" NET "sd_dq_pin<8>" NET "sd_dq_pin<9>" NET "sd_dq_pin<10>" NET "sd_dq_pin<11>" NET "sd_dq_pin<12>" NET "sd_dq_pin<13>" NET "sd_dq_pin<14>" NET "sd_dq_pin<15>" #SRAM control lines NET "sd_ba_pin<1>" NET "sd_ba_pin<0>" NET "sd_cas_pin" NET "sd_clk_n_pin" NET "sd_clk_p_pin" NET "sd_cke_pin" NET "sd_cs_pin" NET "sd_ras_pin" NET "sd_we_pin" NET "sd_dqs_pin<1>" NET "sd_dqs_pin<0>"

SSTL2_I; SSTL2_I; SSTL2_I; SSTL2_I; SSTL2_I; SSTL2_I; SSTL2_I; SSTL2_I; SSTL2_I; SSTL2_I; SSTL2_I; SSTL2_I; SSTL2_I; SSTL2_I; SSTL2_I; SSTL2_I; SSTL2_I; SSTL2_I; SSTL2_I; SSTL2_I; SSTL2_I; SSTL2_I; SSTL2_I; SSTL2_I; SSTL2_I; SSTL2_I; SSTL2_I; SSTL2_I; SSTL2_I;

"H5" "H6" "G5" "G6" "F2" "F1" "E1" "E2" "M6" "M5" "M4" "M3" "L4" "L3" "L1" "L2"

| | | | | | | | | | | | | | | |

IOSTANDARD IOSTANDARD IOSTANDARD IOSTANDARD IOSTANDARD IOSTANDARD IOSTANDARD IOSTANDARD IOSTANDARD IOSTANDARD IOSTANDARD IOSTANDARD IOSTANDARD IOSTANDARD IOSTANDARD IOSTANDARD

= = = = = = = = = = = = = = = =

LOC LOC LOC LOC LOC LOC LOC LOC LOC

= = = = = = = = =

"K5" "K6" "C2" "J4" "J5" "K3" "K4" "C1" "D1"

| | | | | | | | |

IOSTANDARD IOSTANDARD IOSTANDARD IOSTANDARD IOSTANDARD IOSTANDARD IOSTANDARD IOSTANDARD IOSTANDARD

= = = = = = = = =

SSTL2_I; SSTL2_I; SSTL2_I; SSTL2_I; SSTL2_I; SSTL2_I; SSTL2_I; SSTL2_I; SSTL2_I;

LOC = "L6" | IOSTANDARD = SSTL2_I; LOC = "G3" | IOSTANDARD = SSTL2_I;

36

NET "sd_dm_pin<1>" NET "sd_dm_pin<0>" #prohibited IO's CONFIG PROHIBIT CONFIG PROHIBIT CONFIG PROHIBIT CONFIG PROHIBIT = = = = D2; G4; J6; L5;

LOC = "J2" | IOSTANDARD = SSTL2_I; LOC = "J1" | IOSTANDARD = SSTL2_I;

CONFIG PROHIBIT

= R4;

37

Appendix C
/***************************************** * main.c * * Core program for the SuPER FPGA prototype * * By: Tony Wonsyld * * * Purpose: Declares global variables, calls all initialization * functions, sets up ISR, and contains polling loop * to gather and store data. * *****************************************/ #include #include #include #include #include #include #include #include <xio.h> <xparameters.h> "lcd.h" "outputs.h" "intc.h" "timer.h" "spi.h" "inputs.h"

unsigned int frequency = 25000; // 25kHz unsigned int clock_freq = 50000000; // 50 MHz clock volatile volatile volatile volatile volatile volatile volatile volatile unsigned unsigned unsigned unsigned unsigned unsigned unsigned unsigned int int int int int int int int duty_cycle = 0x62; // %5 intitial duty cycle duty_step_start = 0x62; // %5 step size duty_step_normal = 0x04; //~.25% step size milli_count = 0; milli_sec = 0; ch_1 = 0; ch_0 = 0; count=0;

#define SDRAM ((volatile unsigned int *)(XPAR_DDR_MEM0_BASEADDR)) unsigned int button_array[5]; unsigned int switch_array[3]; unsigned int slow_down = 0; /* Function prototype for ISR */ void mainISR() __attribute__((interrupt_handler)); /* mainISR: main interrupt service routine * for the interrupt controller */ void mainISR() { /* If a timer interrupt is pending, run * the timer ISR */ if(pendingIntc(XPAR_TIMER_INTERRUPT_MASK)) { timerISR();

38

IAR = 0x03; if (milli_count == 2500) { milli_sec++; milli_count=0; } milli_count++; } } /* main: core function to run the S3E demo */ int main(void) { int i=0, j=0, k=0; unsigned char adc[5]; unsigned int status, a, b; unsigned int button_pushed; unsigned int fail = 0; /* Initialize the various interfaces * and components */ initLcd(); // Setup LCD for 4-bit communication initSwitches(); // Set SWITCHES's to output initLoads(); // Set LOAD lines to output's initMux(); // Set MUX selector lines to output initLeds(); // Set LEDs to outputs initButtons(); // Set Buttons to inputs initSPI(); // Setup SPI module initIntc(); // Enable Interrupt Controller initTimer((clock_freq / frequency) - 2, 1); // Enable Timer. Generate interrupt /* Turn on alternate LEDs as * part of the S3E demo */ LEDS = 0x00; /* Enable interrupts */ microblaze_enable_interrupts(); sendAmp(0x01, 0x01); //Set the Pre-Amp gain to -1 writeLcd(LCD_CMD, 0x02); //return home on LCD MUX = 0x00; //Set initial MUX address to "000" //Memory test for (a = 0; a < 0x3FFFFFF; a++){ SDRAM[a] = a & 0xFFFF; //stores value address if ((a&0xFFFF) !=SDRAM[a]) //checks each address for fail = 1; // correct value } while(fail) display_num(-1); //if fails; displays -1 via LCD write func. //End Memory Test

39

readSPI(SPI_ADC, adc, 5); //dummy sample to align MEM and ADDR for(;;) // Infinite loop { //microblaze_disable_interrupts(); //writeLcd(LCD_CMD, 0x02); //Move cursor to begginning readSPI(SPI_ADC, adc, 5); ch_0 = ((adc[0]<<8)&0x3F00) | (adc[1]&0x00FF); if(a&0x2000) // Check sign bit ch_0|=~0x1FFF; // Sign extend ch_1 = ((adc[2]<<8)&0x3F00) | (adc[3]&0x00FF); if(b&0x2000) // Check sign bit ch_1|=~0x1FFF; // Sign extend //Conversion ch_0 = ch_0 = ch_1 = ch_1 = to eliminate gain, offset and multiplier (((-ch_0)-1)+0x2000)&0x3FFF; ((ch_0)*250)/(0x3FFF)+43; //convert to mV's (((-ch_1)-1)+0x2000)&0x3FFF; ((ch_1)*250)/(0x3FFF)+43; //convert to mV's

//Write vaules and time stamp to SRAM SDRAM[a] = ch_0&0xFFFF; SDRAM[a+1] = milli_sec&0xFFFF; SDRAM[a+2] = ch_1&0xFFFF; SDRAM[a+3] = milli_sec&0xFFFF; // Only display to the two channels that are applied voltages. if(MUX == 0x00) { writeLcd(LCD_CMD, 0x80); //display channel 0 value on top line of LCD display_hex(ch_0); for(i=0; i<5; ++i) writeLcd(LCD_CHAR,' '); //Move cursor over to display channel 1 display_num(ch_1); //Display channel 1 writeLcd(LCD_CMD, 0xC0); //Move Cursor to bottom line of LCD //Disaplay ADC value and time stamp from SRAM display_hex(SDRAM[a]); for(i=0; i<5; ++i) writeLcd(LCD_CHAR,' '); display_num(SDRAM[a+1]); //increase address pointer and mask a=(a+4)&0x3FFFFFF; writeLcd(LCD_CMD, 0x02);

40

} MUX++; //Increase MUX address //Emergency shut-off check and Load/LED status update if(ch_0<250) { LEDS=SWITCHES; LOADS=LEDS; } else { LEDS=SWITCHES&0x0E; LOADS=LEDS; } } return 0; } /***************************************** * lcd.c * * LCD Main Functions * * By: Tony Wonsyld * * * Purpose: Handles all the functions to initialize, display, and * convert data. * *****************************************/ #include <xparameters.h> #include "lcd.h" /* readLcdStatus: gets the status from the LCD */ int readLcdStatus() { int i, r; LCD_DD=LCD_DATA; LCD=LCD_RW; LCD=LCD_RW|LCD_E; r=(LCD&LCD_DATA); for(i=0; i<5; ++i) LCD=LCD_RW; // Set data lines to inputs // First read cycle (first 4 bits) // ~125ns // ~125ns (E high for ~250ns) // Wait ~750ns

// Second read cycle (second 4 bits) r<<=4; LCD=LCD_RW|LCD_E; r|=(LCD&LCD_DATA); for(i=0; i<5; ++i) LCD=LCD_RW; LCD_DD=0; return r&0xFF; } // ~125ns // ~125ns (E high for ~250ns) // Wait ~750ns // Set data direction back to outputs

41

/* sendLcd: send the given int as an * instruction or data (depnds on RS) * to the LCD */ void sendLcd(int rs, int d) { int i; LCD=rs; // First write cycle LCD=rs|LCD_E|d; LCD=rs|LCD_E|d; LCD=rs|d; for(i=0; i<5; ++i) LCD=rs; } /* Writes the given int to the LCD for * both instructions and data (depends * on RS) */ void writeLcd(int rs, int value) { int i, d; /* RS is set */ if(rs) rs=LCD_RS; while(readLcdStatus()&LCD_BUSY); // Wait for LCD to not be busy sendLcd(rs, (value>>4)&LCD_DATA); sendLcd(rs, value&LCD_DATA); for(i=0; i<10; ++i) LCD=0; } /* initLcd: Performs the power initialization * and entry for the LCD to read/write 8 bits */ void initLcd() { int i; /* Power initialization to prepare LCD * to read/write 8 bits as 2 4-bit nibbles */ LCD_DD=0; for(i=0; i<20*5500; ++i) LCD=0; sendLcd(LCD_CMD, 0x03); for(i=0; i<500; ++i) LCD=0; sendLcd(LCD_CMD, 0x03); for(i=0; i<500; ++i) LCD=0; sendLcd(LCD_CMD, 0x03); // Set to outputs // ~20ms delay // Set to 8-bit Operation // ~91us delay // Set to 8-bit Operation // ~91us delay // Set to 8-bit Operation // Send High nibble // Send Low nibble // Wait ~1000ns

// // // //

~125ns ~125ns total E high for ~250ns ~125ns Hold time Wait ~750ns

42

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

LCD=0;

// ~91us delay // Set to 4-bit Operation // ~91us delay // // // // Function Set Display On Clear Screen Set Entry Mode

sendLcd(LCD_CMD, 0x02); for(i=0; i<500; ++i) LCD=0; writeLcd(LCD_CMD, writeLcd(LCD_CMD, writeLcd(LCD_CMD, writeLcd(LCD_CMD, } 0x28); 0x0C); 0x01); 0x06);

/* printLcd: Prints out the given string to * the LCD */ void printLcd(char *msg) { while(*msg) writeLcd(LCD_CHAR, *(msg++)); } /* display_num: displays the given 4 digit number to the LCD */ void display_num(int n) { int i; if(n<0) { writeLcd(LCD_CHAR, '-'); n=-n; } for(i=10000; i; i/=10) writeLcd(LCD_CHAR, (n/i)%10 + '0'); } #define NUMDIGITS 4 void display_hex(int n) { int i, v; for(i=0; i<NUMDIGITS; ++i) { v=(n>>(4*((NUMDIGITS-1)-i)))&0x0F; if(v<10) writeLcd(LCD_CHAR, '0'+v); else writeLcd(LCD_CHAR, 'A'+v-10); } } /*************************************** * lcd.h * * LCD Header File * * By: Tony Wonsyld *

43

* * Purpose: Defines registers, commands, and prototypes * for use of the LCD ***************************************/ #ifndef LCD_H #define LCD_H /* Register defitions */ #define LCD (*(volatile unsigned long *)(XPAR_LCD_BASEADDR+0x00)) // Data register #define LCD_DD (*(volatile unsigned long *)(XPAR_LCD_BASEADDR+0x04)) // Data direction register /* LCD instruction and data commands */ #define LCD_DATA 0x0F #define LCD_E 0x10 #define LCD_RS 0x20 #define LCD_RW 0x40 #define LCD_BUSY 0x80 #define LCD_CMD 0x00 #define LCD_CHAR LCD_RS /* Function prototypes */ void initLcd(); void writeLcd(int rs, int value); void printLcd(char *msg); void display_num(int n); void display_hex(int n); #endif

44

Appendix D 1. The system clock net connections 2. ADC sample valued takes an entire sampling period before data is valid

45

You might also like