The Design of a LED Blinker

David Baird Hector Malagon Miguel Sanchez December 17, 2004

1

Contents
1 Introduction 2 The Original Plan: Digital Oscilloscope 2.1 Theory of Operation . . . . . . . . . . . . . . . . . . . . . . . . . 2.2 Conclusions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 The 3.1 3.2 3.3 3.4 Modified Plan: LED Blinker Theory of Operation . . . . . . . . . Connecting the LED to the Internet Online GUI . . . . . . . . . . . . . . Testing Procedures . . . . . . . . . . 4 5 5 6 6 6 6 7 8 9 9 10 11 11 11 12 12 13 16 16 17 18 18 18

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

4 Future Improvements 4.1 Project Management . . . . . . . . . . . . . . . . . . . . . . . . . 4.2 Design Practices . . . . . . . . . . . . . . . . . . . . . . . . . . . A Altera MAX7064 Code A.1 Final.gdf . . . . . . . . A.2 DataBus.vhd . . . . . A.3 Decoder.vhd . . . . . . A.4 Encoder.vhd . . . . . . A.5 Register8.vhd . . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

B Printed Circuit Board B.1 Front Silk . . . . . . . . . . . B.2 Front Copper . . . . . . . . . B.3 Back Copper . . . . . . . . . B.4 Back Silk . . . . . . . . . . . B.5 ISA Bus to MAX7064 Wiring

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

C Linux 2.4 Drivers 22 C.1 Makefile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 C.2 blinker.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 C.3 test.sh . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 D Online User Interface D.1 form.py . . . . . . D.2 data.txt . . . . . . D.3 form.txt . . . . . . D.4 header.txt . . . . . D.5 main.css . . . . . . 26 26 27 28 28 29

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

2

List of Tables
1 2 3 4 Specifications . . . . . . . . Deliverables . . . . . . . . . Old Specifications . . . . . Voltage Levels of Interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 4 4 5

List of Figures

3

Acknowledgment
Dr. William Rison Project mentor Dr. Robert Bond Advice concerning project management and advice concerning design for testability John Battles Advice concerning design of programmable logic programs for easier in-circuit testing

4

1. LED blinker must connect to a PC/XT or PC/AT ISA bus 2. Drivers must be provided for Linux 2.4 or for RTLinux 3. A convenient user interface must be wrapped around the drivers 4. Costs should remain under $200 Table 1: Specifications 1. A report discussing the implementation of a complete blinking LED system 2. Printed circuit board drawings for the system 3. All source code for drivers, user interface, and programmable logic devices Table 2: Deliverables

1

Introduction

The original goal of this project was to create a multi-channel digital oscilloscope, as described in §2. Due to many constraints, the project was trimmed down to an LED blinker described in §3. The specifications for the LED blinker are presented in Table 1. The deliverables for this project are presented in Table 2. The specifications for the digital oscilloscope are presented in Table 3. 1. Oscilloscope will provide 16 input channels. Two channels will be reserved for self calibration purposes. 2. Oscilloscope will sample up to 10 MSPS. 3. Oscilloscope inputs can vary across ±10 V. 4. Linux drivers must be provided. Table 3: Old Specifications

5

Component ISA Bus MAX7000SLC ACEX 1K 74ACT541 AD9240 A/D converter AD408 Mux

min VIH 2.0 V 2.0 V 1.7 V 2.0 V 3.5 V 2.4 V

min VOH 2.4 V 2.4 V 2.4 V 3.8 V 2.4 V (@500 µA) 4.5 V (@50 µA) n/a

Table 4: Voltage Levels of Interfaces

2
2.1

The Original Plan: Digital Oscilloscope
Theory of Operation

The digital oscilloscope provides 16 analog inputs. Each input has protection circuitry to prevent problems with input voltages that go outside the specs mention in Table 3. The signals are then fed to analog muxes. The output of the muxes are fed to a differential amplifier. The output of the differential amplifier is fed to a 10 MSPS A/D converter. An ACEX 1K FPGA from Altera is used to coordinate all the digital electronics. Some of the functions performed by the FPGA are selecting of mux channels, sending a clock to the A/D converter, reading data from the A/D converter into RAM, accepting programmed I/O commands from the ISA bus, and dumping on-board RAM via DMA. The ACEX 1K is RAM based, and thus needs to be programmed every time it is powered on. A small PLD, an Altera MAX7032, is used to allow the ISA bus to control the JTAG pins on the ACEX. The MAX7032 is based on non-volatile memory, so it only needs to be programmed once. The memory blocks of the ACEX 1k is used as on-board RAM used to stored samples from the A/D converter. This memory is very limited however, and so it cannot store a complete waveform. To solve this problem, a program was written that takes pieces of a complete waveform and figures out how to connect the pieces to reconstruct the complete waveform. This technique only works when the signal being sampled is periodic. A lot of care was put into the printed circuit layout. The PCB features a fairly solid ground plane. Any breaks in the ground plane are kept fairly short, especially when those breaks cut underneath signal wires on the top layer. This is important because it minimizes the size of inductive loops formed by signal paths and the signal return paths. The signal return paths are free to flow in the ground plane directly beneath the signal path, except when the ground plane is broken underneath a signal path. Numerous test points are located on the PCB to allow convenient testing and rewiring. Every integrated circuit was surrounded by vias that could fit

6

.100” headers. If necessary, it is possible to cut traces on the PCB and then place populate the holes with headers and do wirewrapping to rewire the cut traces. The printed circuit is organized into functional blocks. There are blocks for the power supply, input muxes, differential amplifier, A/D converter, and programmable logic chips. It is easy to comprehend, by visual inspection, the general flow of signals through the circuit board. The is one shortcoming with the printed circuit board drawing: there were too few labels. Additional labels could indicate the pin numberings on chips. Because these labels were missing, it is necessary to count pins by hand when debugging the board. The PCB does not have a card edge connector to plug directly into the ISA bus. A separate prototype perf board with a card edge connector is used. These two boards are connected using ribbon cable and a 64 pin IDC receptacle.

2.2

Conclusions

The original plan was zealous. The plan was not fulfilled in part due to poor project management, described in §4.1, and also in part due to inexperience of the team members involved. This was not a failure though: we all tested our limits and gained more experience and knowledge.

3
3.1

The Modified Plan: LED Blinker
Theory of Operation

The LED blinkers is an ISA card that provides an addressable register. The output of this register is connected to a single LED. By writing a value, using Intel x86 inb and outb instructions, the LED can be switched on or off. The code for Altera chip is provided in Appendix A. The wiring information and PCB layout was borrowed from the oscilloscope project and can be viewed in Appendix B. The Linux driver (see Appendix C) makes this I/O port appear as a character device file. User space programs can open this device file and write ‘1’ or ‘0’ characters into it to turn the LED on and off. A Makefile file is provided in the Appendix. To build the drivers, type ‘make’. To load the device driver, type ‘make reload’. To create the device file, type ‘make mknod’. The device file will be /dev/blinker. To run a simple test, run ‘make runtest’, which will execute test.sh. User interface possibilities are explored by putting this device on the internet, as described in the next section.

3.2

Connecting the LED to the Internet

TCP port 5555 is setup in listen mode. Any data written to this port is piped data directly to /dev/blinker. A web CGI application accepts user input 7

through an HTML form. When the user submits a form, the CGI script connects to port 5555 to control the LED. Since the computer running the LED blinker is different from the computer running the web server, OpenSSH is used for port tunneling. To setup the TCP port, a prepackaged system called pipes is used. This package can be obtained from http://bisqwit.iki.fi/source/pipes.html. To create the TCP port, type ‘plis 5555 -i ’cat > /dev/blinker’’. The TCP port can be quickly tested using a telnet client: telnet localhost 5555 Trying 127.0.0.1... Connected to localhost. Escape character is ’^]’. 0 1 0 1 OpenSSH can be used to tunnel data by typing a command such as ‘ssh -R 5555:localhost:5555 infohost.nmt.edu’. This will forward all data from port 5555 on infohost.nmt.edu to port 5555 on the local machine.

3.3

Online GUI

The purpose of the Online Graphical User Interface proposal is to allow for easily configurable GUI using the well-documented, established web-standard format, xhtml. The user interface is an xhtml web form generated using a single python script. The page can be broken into three distinct sections: the header, the form, and the response. User interface is divided into two components: user-interface communication (the web form) and the interface-device communication system. The code for all of this can be found in Appendix D. The OGUI is a dynamically created web page, which takes advantage of the CGI capabilities of Python. The Python script used to write the different sections of web page are predefined in separate plain-text files. The different files each contain portions of w3c-compliant xhtml. However, because the files are not truly xhtml files, in-and-of themselves, they have been appended with the .txt file-type designator. The three different sections of xhtml code are described below. The file header.txt is a generic heading file for the webpage. It contains no real special information. It requires no special encoding. The data for the header is contained in the plain-text file, ”header.txt”. The header is a section of generic, preformatted xhtml, with simple arguments added for ease of customizability. The file form.txt is the most important part of the user interface. Like the header, it is a predefined selection of xhtml with %s arguments added to

8

allow customizability. In the case of the form, the default values of the form are returned from the cgi script to reflect the previous selection. The intent of data.txt is to expose the current status of the device. However, the ISA device was not designed to allow reading of its current state. Therefore, the information is simulated, using the previous input data. If communication with the actual device is correct, the board response should be identical to the last submitted values. Aside from writing the xhtml code, the purpose of form.py is to act as the communication link between the user and the device. Both the web form and the communication system are designed for simplicity and general understandability. Two methods were attempted for communication with the device. The first plan, telnet communication, failed because of the nature of the telnet program. The second attempt was to communicate directly with the device, using Sockets. The telnet communication system (the SendDataTelnet function in form.py) is quite self-explanatory. Telnet is opened and pointed to port 5555 (the arbitrarily chosen TCP port of the ssh tunnel between the webserver and the computer with the actual device). Depending on the user-requested duty cycle, either a ‘0’ or a ‘1’ is written to the telnet terminal. Unfortunately, telnet, which is designed for interactive use, does not handle communication through pipes (i.e. popen). Thus, the telnet method of communication had to be abandoned in favor of a more script-friendly communication method. The sockets communication system (the SendDataSocket function in form.py) was very straight forward. Python includes ‘socket’ as a standard library module. This reduced communication to opening a socket and sending a message (either a ‘1’ or a ‘0’) to the device. The result is a rather robust communication system that is as simple as it is effective. The Online Graphic User Interface, although quite simplistic and lacking in functionality, is a very nice example of creating a multi-level interface. Each component may be readily modified without much affecting the rest of the interface. Also, given the use of Python and xhtml, the interface can be easily expanded if needed. This system will definitely be used as the basis for the Oscilloscope UI, when that project is resumed.

3.4

Testing Procedures

1. Plug ISA card into ISA bus, without jumper to our main board. Does computer boot? If not, then there is a defect in the ISA card. 2. Before populating main board, attach it to ISA card plugged in to ISA bus? If not, then there is a defect in the PCB design or the manufacturer did not meet spec. 3. Load program into Altera 7064 chip. Have testing station apply input stimulus. Does Altera chip pass test? If not, then the chip is either fried or the firmware loaded into the chip does not provide a reset function. A reset function is imperative for testing and it must put every state element into a known state. 9

4. Insert Altera 7064 chip. Does computer boot? 5. Read/write I/O ports on the Altera chip. Does the system respond as expected? Write multiple Altera programs to assist with testing: 1. Set all I/O to high impedance. 2. Turn an LED on when reset is applied. 3. Turn an LED off when reset is applied. 4. Allow read/write of a register mapped to some I/O address.

4

Future Improvements

Some of the guidelines were written when we discovered problems as we were putting the system together. Good project management should be very helpful in future projects.

4.1

Project Management

If it isn’t written down, it didn’t happen. When managing projects in the future, this guidelines should be followed: team members need to sign statements of work. The statement of work signed by individual team members should consist of the following: 1. Statement of what work will be done 2. Date by which the work will be completed 3. Any risks that the signer is concerned about that may cause the work to be unfulfilled 4. A signature from the person doing the work Anyone assuming leadership among the team cannot tell team members what to do and how long it will take. The team members must tell the leader how much time they need in order to complete certain tasks. For example, if someone is going to draw a printed circuit board, then they must give specify a time when they will be finished. A written statement of work must then be drawn up for the printed circuit board drawing, as described above. Time management can also be improved. Here are some guidelines for planning time: 1. Be prepared for more than one iteration of a design. Plan for at least two printed circuit boards revisions. This provides time to become acquainted with the PCB vendor’s manufacturing capabilities. It also provides a chance to iron out many mistakes in the design, such as wrong footprints or incorrect hole sizes. 10

4.2

Design Practices

For the Altera code, the following requirements must be met: 1. Provide a reset. All state elements must enter a known state when reset is applied. This is necessary for testing. It is very hard to test a programmable logic device if you cannot force it into a known state and then apply stimulus to progress through other states. 2. Make it possible to route all state machine bits to pins on the chip. This is more beneficial to complex designs than it is to simple designs. Circuit design practices: 1. Connect VCC through a resistor. Thus shorts in the circuit can be detected by measuring the voltage drop across this resistor. 2. Connect control signals such as tristate enables or reset signals through resistors. This permits these signals to be manually controlled for purposes of test. PCB design practices: 1. Double check all footprints with datasheets directly from the manufacturer. 2. Ensure all hole diameters will allow easy and secure fitting of through hole components. 3. Use DRC to ensure you meet manufacturing specifications. 4. Use netlists to help ensure correct wiring of the board. 5. When routing, simplify routing by taking advantage of the generic-ness of programmable logic I/O pins and any other generic circuit blocks. Reassign pins as necessary to mitigate tracks crossing each. 6. Wire all integrated circuits (and other high pin density parts, such as connectors) to vias that can hold dual row .100” headers. This permits easier testing and rewiring of the board. 7. Provide a solid ground plane. Keep breaks short, especially when the breaks run perpendicularly beneath other signals. This minimizes inductive loops. Inductive loops increase interference and susceptibility to interference as well as increase the rise times of signals. 8. Put tick marks and/or labels next to pins and pads. This makes it easier to count them and easier to debug. 9. Place bypass capacitors near chips that require transient current supplies. Connections to bypass capacitors should be provided through short wiring.

11

A
A.1

Altera MAX7064 Code
Final.gdf

A.2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28

DataBus.vhd

LIBRARY ieee; USE ieee.std_logic_1164.all; ENTITY DataBus IS PORT ( databus dataIn ie dataOut END DataBus;

:INOUT std_logic_vector(7 DOWNTO 0); :IN std_logic_vector(7 DOWNTO 0); :IN std_logic; :OUT std_logic_vector(7 DOWNTO 0));

ARCHITECTURE dataBus OF DataBus IS BEGIN iep:

PROCESS ( databus, dataIn, ie ) BEGIN IF ie = ’0’ THEN databus <= (OTHERS => ’Z’); dataOut <= databus; ELSE databus <= dataIn; dataOut <= (OTHERS => ’Z’); END IF; END PROCESS iep; END databus;

12

A.3
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33

Decoder.vhd

LIBRARY ieee; USE ieee.std_logic_1164.all; ENTITY Decoder IS PORT ( address aen, iow, ior clk_counter, w, r data

:IN std_logic_vector(9 DOWNTO 0); :IN std_logic; :OUT std_logic; :OUT std_logic_vector(7 DOWNTO 0));

END Decoder; ARCHITECTURE decoder OF Decoder IS BEGIN PROCESS ( aen, address ) BEGIN w <= NOT iow; r <= NOT ior; data <= (OTHERS => ’Z’); IF aen = ’1’ THEN IF address = b"1001000000" THEN clk_counter <= ’1’; ELSE clk_counter <= ’0’; END IF; END IF; END PROCESS; END decoder;

A.4
1 2 3 4 5 6 7 8

Encoder.vhd

LIBRARY ieee; USE ieee.std_logic_1164.all; ENTITY Encoder IS PORT ( input

:IN std_logic_vector(7 DOWNTO 0);

13

9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24

output END Encoder;

:OUT std_logic);

ARCHITECTURE encoder OF Encoder IS BEGIN PROCESS ( input ) BEGIN IF input >= x"00" AND input < x"F0" THEN output <= ’0’; ELSIF input >= x"F0" THEN output <= ’1’; END IF; END PROCESS; END encoder;

A.5
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27

Register8.vhd

LIBRARY ieee; USE ieee.std_logic_1164.all; ENTITY Register8 IS PORT ( d clk, en reset r END Register8;

:IN std_logic_vector(7 DOWNTO 0); :IN std_logic; :IN std_logic; :OUT std_logic);

ARCHITECTURE register8 OF Register8 IS BEGIN PROCESS ( clk, en, d, reset ) BEGIN IF reset = ’1’ THEN r <= ’1’; ELSIF clk ’EVENT AND clk = ’0’ THEN IF en = ’1’ THEN IF d >= x"00" AND d < x"C3" THEN r <= ’0’; ELSE r <= ’1’; 14

28 29 30 31 32

END IF; END IF; END IF; END PROCESS; END register8;

15

16

B
B.1

Printed Circuit Board
Front Silk

17

B.2

Front Copper

18

B.3

Back Copper

B.4

Back Silk

B.5
1 2 3 4 5 6

ISA Bus to MAX7064 Wiring

JISA v. U320 ============ JISA JISA JISA 2 3 4 A2 A3 A4 19 U320 U320 U320 25 26 27

7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52

JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA

5 6 7 8 9 11 22 23 24 25 26 27 28 29 30 31 32 32 32 32 32 32 32 32 34 34 34 34 41 41 41 41 41 41 41 41 44 45 60 60 60 60 62 62 62 62

A5 A6 A7 A8 A9 A11 A22 A23 A24 A25 A26 A27 A28 A29 A30 A31 B1 B1 B1 B1 B1 B1 B1 B1 B3 B3 B3 B3 B10 B10 B10 B10 B10 B10 B10 B10 B13 B14 B29 B29 B29 B29 B31 B31 B31 B31 20

U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320

28 29 31 33 34 36 8 9 11 12 14 16 17 18 19 20 1 2 10 22 30 42 43 44 3 15 23 35 1 2 10 22 30 42 43 44 21 24 3 15 23 35 1 2 10 22

53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98

JISA JISA JISA JISA U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320

62 62 62 62 1 1 1 2 2 2 3 3 8 9 10 10 10 11 12 14 15 15 16 17 18 19 20 21 22 22 22 23 23 24 25 26 27 28 29 30 30 30 31 33 34

B31 B31 B31 B31

U320 U320 U320 U320 JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA 21

30 42 43 44 32 41 62 32 41 62 34 60 22 23 32 41 62 24 25 26 34 60 27 28 29 30 31 44 32 41 62 34 60 45 2 3 4 5 6 32 41 62 7 8 9 B1 B10 B31 B1 B10 B31 B3 B29 A22 A23 B1 B10 B31 A24 A25 A26 B3 B29 A27 A28 A29 A30 A31 B13 B1 B10 B31 B3 B29 B14 A2 A3 A4 A5 A6 B1 B10 B31 A7 A8 A9

99 100 101 102 103 104 105 106 107 108 109 110

U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320 U320

35 35 36 42 42 42 43 43 43 44 44 44

JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA JISA

34 60 11 32 41 62 32 41 62 32 41 62

B3 B29 A11 B1 B10 B31 B1 B10 B31 B1 B10 B31

22

C
C.1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

Linux 2.4 Drivers
Makefile
KERNELDIR = /usr/src/linux-2.4.22 include $(KERNELDIR)/.config CFLAGS = -D__KERNEL__ -DMODULE -I$(KERNELDIR)/include -O -Wall .PHONY: mknod reload testdev all: blinker.o reload: blinker.o -rmmod blinker insmod blinker.o mknod: -rm /dev/blinker mknod /dev/blinker c $(shell grep blinker /proc/devices | cut -f1 -d\ ) 0 runtest: reload mknod -./test.sh test: test.c gcc -O2 $< -o $@

C.2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

blinker.c

#ifndef __KERNEL__ # define __KERNEL__ #endif #ifndef MODULE # define MODULE #endif #include <linux/config.h> #include <linux/module.h> #include #include #include #include #include #include #include #include #include <linux/sched.h> <linux/kernel.h> <linux/fs.h> <linux/errno.h> <linux/delay.h> <linux/slab.h> <linux/mm.h> <linux/ioport.h> <linux/interrupt.h>

23

21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66

#include #include #include #include

<asm/io.h> <linux/poll.h> <linux/interrupt.h> <linux/slab.h>

static int major = 0; /* dynamic */ static unsigned long base = 0x240; MODULE_PARM(base, "l"); MODULE_AUTHOR("Some Loser"); #define MY_MODULE_NAME "blinker" ssize_t blinker_read(struct file *filp, char *buf, size_t count, loff_t *f_pos); ssize_t blinker_write(struct file *filp, const char *buf, size_t count, loff_t *f_pos); ssize_t blinker_open(struct inode *inode, struct file *filp); ssize_t blinker_release(struct inode *inode, struct file *filp); int blinker_init(); void blinker_cleanup(); struct file_operations blinker_fops = { read: blinker_read, write: blinker_write, open: blinker_open, release: blinker_release }; ssize_t blinker_read(struct file *filp, char *buf, size_t count, loff_t *f_pos) { char my_buf[1]; my_buf[0] = ’0’; if(count > 0) { count = 1; inb(base); copy_to_user(buf, my_buf, count); } return count; } ssize_t blinker_write(struct file *filp, const char *buf, size_t count, loff_t *f_pos) { 24

67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112

char my_buf[1]; if(count > 0) { count = 1; copy_from_user(my_buf, buf, count); if(*my_buf == ’1’) { outb(0xff, base); } else if(*my_buf == ’0’) { outb(0x00, base); } } return count; } ssize_t blinker_open(struct inode *inode, struct file *filp) { MOD_INC_USE_COUNT; return 0; } ssize_t blinker_release(struct inode *inode, struct file *filp) { MOD_DEC_USE_COUNT; return 0; } int blinker_init() { int result; result = check_region(base, 1); if (result) { printk(KERN_INFO MY_MODULE_NAME "_init: can’t get I/O port address 0x%lx\n", base); return result; } request_region(base, 1, MY_MODULE_NAME); result = register_chrdev(major, MY_MODULE_NAME, &blinker_fops); if (result < 0) { printk(KERN_INFO MY_MODULE_NAME "_init: can’t get major number\n"); release_region(base, 1); return result; } if (major == 0) major = result; printk(KERN_INFO MY_MODULE_NAME "_init: major number is %d\n", major); return 0; 25

113 114 115 116 117 118 119 120 121 122 123

} void blinker_cleanup() { unregister_chrdev(major, MY_MODULE_NAME); release_region(base, 1); } module_init(blinker_init); module_exit(blinker_cleanup);

C.3
1 2 3 4 5 6 7 8

test.sh

#!/bin/bash while true; do date echo 1 > /dev/blinker sleep .5 echo 0 > /dev/blinker sleep .5 done;

26

D
D.1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42

Online User Interface
form.py
#!/usr/local/bin/python import import import import cgi cgitb; cgitb.enable() socket os

from time import gmtime, strftime #Header def PrintHead(): head = "Microcomputer Interfacing - Oscilloscope" desc = "Welcome to the Graphical User Interface for EE352: " + \ "micro_intf, version 1.00.00&gamma;" date = strftime("%d %b %Y",gmtime()) file = open("./header.txt", ’r’) HEAD = file.read() print HEAD%{’title’:head, ’description’:desc, ’date’:date} file.close() #Form def PrintForm(freq, dty): file = open("./form.txt", ’r’) FORM = file.read() if int(dty) == 100: ch000 = ’’ ch100 = ’checked="checked"’ else: ch000 = ’checked="checked"’ ch100 = ’’ print FORM%(freq, ch000, ch100) file.close() #Data def PrintData(freq, dty): file = open("./data.txt", ’r’) DATA = file.read() print DATA%(freq, dty) file.close() #Send Data using Sockets (should work) def SendDataSocket(dty):

27

43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) if dty == ’100’: msg = ’1\n’ else: msg = ’0\n’ s.connect(("localhost", 5555)) s.send(msg) #Send Data using Telnet (does not work) def SendDataTelnet(dty): p = os.popen(’telnet localhost 5555 > ./telnet.log’, ’w’) if dty == ’100’: print >>p, ’1’ else: print >>p, ’0’ p.flush() p.close() #Main def main(): form = cgi.FieldStorage(keep_blank_values=1) keys = form.keys() if ’freq’ in keys: freq = form[’freq’].value dty = form[’dty’].value else: freq = ’0’ dty = ’0’ SendDataSocket(dty) PrintHead() PrintForm(freq, dty) PrintData(freq, dty) if __name__ == "__main__": print "Content-type: text/html" # Print the required header for HTML print # Blank line to signify end of headers main()

D.2
1 2 3 4 5

data.txt

<!-- column Break --> </td><td class="main" colspan="1"> <h4>Posted Form Data</h4> <ul> 28

6 7 8

<li>Frequency = %s Hz</li> <li>Duty Cycle = %s %%</li> <ul>

D.3
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18

form.txt

<form method="get" action="form.py"> <h4>LED Cotroller</h4> <h6>PWM Frequency</h6> <input type="text" maxLength="3" size="3" value="%s" name="freq" /> <label for="freq">Hz</label> <h6>Duty Cylce</h6> <input id="PWM0" type="radio" value="0" name="dty" %s /> <label for="PWM0">0 %%</label><br /> <input id="PWM1" type="radio" value="25" name="dty" disabled="disabled" /> <label for="PWM1">25 %%</label><br /> <input id="PWM2" type="radio" value="50" name="dty" disabled="disabled" /> <label for="PWM2">50 %%</label><br /> <input id="PWM3" type="radio" value="75" name="dty" disabled="disabled" /> <label for="PWM3">75 %%</label><br /> <input id="PWM4" type="radio" value="100" name="dty" %s /> <label for="PWM4">100 %%</label><br /> <input type="submit" value="Submit Changes" /> </form>

D.4
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

header.txt

<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=windows-1252" /> <meta http-equiv="Content-Style-Type" content="text/css" /> <link type="text/css" rel="stylesheet" href="main.css" /> <meta http-equiv="Content-Language" content="en-us" /> <title>%(title)s</title> </head> <body> <table class="invisible"><tr> <td class="side" colspan="3"> <h1>%(title)s</h1> <p>%(description)s</p> </td><td class="side" rowspan="2"></td></tr> <tr><td class="side"><table class="side"> <tr><td class="side0"><h2 class="side">%(date)s</h2></td></tr> <tr><td class="side1"><h1 class="side">CONTENTS</h1> <ul> <li><a class="side" href="README">README</a></li> 29

20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53

<li><a class="side" href="http://www.nmt.edu/~dbaird/micro_intf/"> micro_intf SVN Server</a></li> </ul></td></tr> <tr><td class="side2"><h1 class="side">REFERENCE</h1> <ul> <li><a class="side" href="http://www.python.org/">Python.org</a></li> <li><a class="side" href="http://www.python.org/doc/2.3.4/lib/lib.html"> Python 2.3 Doc</a> </li> <li><a class="side" href="http://www.w3schools.com/">W3Schools</a></li> <li><a class="side" href="http://www.algonet.se/~ug/"> Ug’s Other Homepage</a> </li> <li><a class="side" href="http://gnosis.cx/publish/tech_index.html"> Gnosis Project</a> </li> </ul></td></tr> <tr><td class="side1"><h1 class="side">LINKS</h1> <ul> <li><a class="side" href="http://www.nmt.edu/">NMT Homepage</a></li> <li><a class="side" href="http://www.ee.nmt.edu/">EE Homepage</a></li> <li><a class="side" href="http://www.ee.nmt.edu/~rison/"> Dr. Rison’s Homepage</a> </li> <li><a class="side" href="http://www.ee.nmt.edu/~rison/ee352_fall04/homepage.html"> EE352 Homepage</a> </li> <li><a class="side" href="http://www.nmt.edu/~dbaird/"> David Baird’s Homepage</a> </li> </ul></td></tr></table></td> <td class="main" colspan="1"> <!-- End of Header -->

D.5
1 2 3 4 5 6 7 8 9

main.css

a:link { margin: 0px; padding: 0px; text-decoration: none; color: #5a5a50; } a:visited { text-decoration: none; color: #5a5a50; 30

10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55

} a:hover { background-color: #f0f0f0; color: #333333; text-decoration: underline; } a:active { text-decoration: overline; color: #012050; } a:link.side { font-family: arial, sans-serif; font-size: 0.75em; font-weight: bold; text-decoration: none; color: #666666; clear: both; letter-spacing: 0.033em } a:visited.side { font-family: arial, sans-serif; font-size: 0.75em; font-weight: bold; text-decoration: none; color: #666666; clear: both; letter-spacing: 0.033em } a:hover.side { background-color: #d9c060; clear: both; color: #333333; font-family: arial, sans-serif; font-size: 0.75em; font-weight: bolder; text-decoration: none; letter-spacing: 0.037em } a:active.side { background-color: #aaaaaa; color: #333333; font-size: 0.75em; } address { color: #c9b040; font-family: sans-serif; 31

56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101

font-size: 0.75em; margin: 0px; padding: 5px; text-align: right; } b { font-family: sans-serif; font-size: 0.85em; font-weight: bold; color: #0a0a0a; background-color: #fefeff; } big { font-family: serif; font-size: 1.1em; color: #060045; } body { margin: 0px; padding: 2px; color: #0e0706; background-color: #848484; font-family: sans-serif; } em { background-color: #fff5f5; color: #250505; font-family: sans-serif; font-size: 0.825em; font-style: oblique; text-decoration: underline; } h1 { margin: 0.075em 0.0em 0.075em 0.20em; padding: 0.10em 0.05em; font-weight: bold; font-size: 3.25em; font-style: oblique; text-align: left; color: #001100; } h1.side { background-color: #959595; color: #d9c060; font-size: 0.95em; font-style: normal; 32

102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147

font-weight: bold; margin: 0px; padding: 0px 0.05em 0px 0.25em; } h2 { margin: 0.2em; padding: 0.3em 0.125em 0px 0.125em; font-size: 2.5em; font-family: sans-serif; text-align: left; color: #d9c060; } h2.side { color: #f9f060; font-family: "Courier New", serif; font-size: 1.5em; font-style: normal; font-weight: boldest; margin: 0px; padding: 0px; text-align: center; } h3 { margin: 0px 0.75em; padding: 0.3em; font-weight: bold; font-size: 1.2em; text-align: left; color: #686664; } h4 { margin: 0.5em; padding: 0.15em 2px; font-family: arial, sans-serif font-weight: bold; font-size: 1.0em; text-align: left; color: #484644; background-color: #f6f6f6; border: thin double #a0a0a0; } h5 { margin: 0.75em; padding: 0.15em 10px; font-family: arial, sans-serif font-weight: bold; 33

148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193

font-size: 0.8em; text-align: left; color: #484644; background-color: #f8f8f8; border: thin solid #b5b5b5; } h6 { margin: 1.0em; padding: 0.15em 20px; font-family: arial, sans-serif font-weight: bold; font-size: 0.6em; text-align: left; color: #484644; background-color: #fafafa; border: thin solid #eeeeee; } hr { margin: 0px 18% 1.0em; padding: 2px; width: 66%; color: #0d0d0d; background-color: #e6e6e5; } i { color: #101010; background-color: #f9f9f9; } img { border: 0px solid #000000; vertical-align: middle; } input { color: #5a5a50; font-family: serif; font-size: 0.75em; font-weight: normal; } label { color: #5a5a50; font-family: serif; font-size: 1.0em; font-weight: normal; } li { color: #070a15; 34

194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239

font-family: serif; font-size: 1.0em; font-weight: normal; margin: 0px 2px; padding: 0px; } ol { margin: 0px 10px; padding: 0px 25px 10px 40px; color: #39597c; } p { color: #070a15; font-family: serif; font-size: 1.0em; font-weight: normal; margin: 0px 0.2em 0px 0.5em; padding: 0.2em 0.2em; } table { margin: 5px 5%; padding: 2px; width: 90%; border: 0.2em double #a1a1a1; background-color: #a1a1a1; } table.invisible { background-color: #ffffff; border: 0px solid #000000; margin: 0px; padding: 0px; width: 100%; } table.side { background-color: #eeeeee; border: 2px double #505050; margin: 0px; padding: 0px; width: 95%; } td { margin: 0px; padding: 2px; vertical-align: middle; text-align: center; color: #050509; 35

240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285

background-color: #f0f0f0; clear: both; } td.main { background-color: #fefefe; border-color: #f9f9f9; border-style: none solid; border-width: medium; color: #001509; margin: 0px; padding: 5px; text-align: left; vertical-align: top; width: 35%; } td.side { background-color: #ffffff; border: 0px none #000000; color: #000000; margin: 0px; padding: 0px; vertical-align: top; text-align: left; width: 10%; } td.side0 { background-color: #ababab; border: 0px none #000000; color: #000000; margin: 0px; padding: 0px; text-align: left; vertical-align: middle; } td.side1 { background-color: #a5a5a5; border: 0px none #000000; margin: 0px; padding: 0px; text-align: left; vertical-align: middle; } td.side2 { background-color: #b0b0b0; border: 0px none #000000; margin: 0px; 36

286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320

padding: 0px; text-align: left; vertical-align: middle; } tr { height: 4.0em; } ul { font-family: sans-serif; font-size: 1.0em; list-style: none outside; margin: 0px 0px 0px 3px; padding: 1px; } ul.level0 { font-family: sans-serif; font-size: 1.0em; list-style: disc inside; margin: 1px 5px; padding: 2px 0px; } ul.level1 { font-family: sans-serif; font-size: 1.0em; list-style: circle inside; margin: 1px 10px; padding: 2px 5px; } ul.level2 { font-family: sans-serif; font-size: 1.0em; list-style: disc inside; margin: 1px 15px; padding: 2px 10px; }

37