Introduction
Professor Potter in ECE 582/682 has proposed the need for a wireless data
acquisition device (DAQ) that is able to process audio signals from an array of wired
microphones. The main application of this device is determining relative position
information of objects located within the array. There is high interest in both military and
academic research areas. Thus, the task at hand is to design and implement a prototype
data acquisition device capable of recording multiple audio channels to a StarGate sensor
node.
Brief Overview
A block diagram of the proposed design is show in Figure 1. Eight microphones
will be biased and amplified. The gain for the amplifier will be user selectable. Each
respective signal will be multiplexed to repeatedly sequentially select each of the eight
signals. This form of multiplexing is time domain multiplexing (TDM). This means that
eight signals are concentrated onto one line by alternating time slots. The single line out
from the multiplexer will be low-pass filtered to prepare for analog to digital conversion
(ADC). The ADC will convert the analog signals to digital format. The USB controller
will read the value of the ADC and buffer it in memory. When the buffer is full, the USB
controller will send packets of data to the StarGate node. Once the sampled data is in the
StarGate node it may be decimated in order to match a user selectable sampling rate.
Requirements Specifications
The minimum requirements for the proposed data acquisition device as agreed
upon by Team Yellow and Professor Potter are as follows:
six channels
8000 Hz sampling rate on each channel
Frequency response 20–4000 Hz using electret microphones
10 bit resolution on each channel
pre-amplifiers with two or more selectable gains
anti-aliasing filters
powered from StarGate I/O interface (e.g., RS-232, USB, etc.)
low-power “sleep” mode
Reliable operation -10 to 40 degrees Celsius
Design concept for weather-resistant package (for reporting only; construction
not required for prototype)
Further, the output must be compatible with one or more of the standards
supported by Stargate: e.g., USB, RS-232, PCMCIA, compact flash, JTAG.
Development costs may not exceed $100. (Product costs, per unit, for building multiple
units are computed separately.)
2
Figure 1 - Bock Diagram
Detailed Component Overview
Microphones
1
The electret condenser microphone (ECM) has two connecting wires. One is a
ground and the other is the analog output voltage. The packaging can be seen in Figure
2. The ECM is connected to other devices in a fashion called
“phantom biasing”, which can be seen in Figure 3. In this
process, a capacitor and resistor are placed in parallel to each
other between the ECM and the operational amplifier. The
Figure 2 - ECM package
resistor is usually on the order of a few thousand ohms.
This is connected to the voltage course for the circuit. On the other end of the resistor is
the output of the analog signal coming from the ECM. At this junction, the capacitor is
1
http://dkc3.digikey.com/PDF/T042/1115.pdf
3
connected and leads away from the microphone as the overall system output voltage.
This wire carries the signal representing the sound waves being measured. It is
connected into the respective anti-aliasing filter. The end result of these resistors and
capacitors is a small gain of roughly -3dBV and also a Total Harmonic Distortion (THD)
of somewhere in the range of 1-10%. The ECM used in this project is the Panasonic
P11969-ND. While maintaining a small package, the frequency range remains very wide
at 20-16000 Hz. The typical operation voltage is
2
3V, with a maximum input voltage of 9V. The
features of this microphone include a highly
efficient electrical specification pressure type
operating principal, low impedance (2.2KΩ),
Figure 3 - Biasing Circuit
omni-directional back directivity, and high degree of reliability under adverse shock,
vibration, and environmental tests. Also, the unit does not need a high voltage bias from
the outside like ordinary condenser microphones.
Anti-Aliasing Filter
The output of the ECM is connected to an anti-aliasing filter. The purpose of the
filter is to low pass filter the signal before sampling. This makes sure that there are no
frequency components in the signal that are greater than 4000 Hz. This is the Nyquist
frequency and will be the cutoff frequency of the filter. Analog filters will be used to
keep cost down and because linear phase is not a requirement. An 8th-order elliptic filter
was chosen because it is commonly used in anti-aliasing applications and it provides a
sharp roll off of 82dB/dec. The elliptic filter properties include having the sharpest
2
http://dkc3.digikey.com/PDF/T042/1115.pdf
4
transition band and it is equiripple in both the passband and stopband. The Maxim MAX
7404 is an 8th-order lowpass elliptic filter. The cutoff frequency range for this chip is 110kHz, which is well within the required 4kHz. Power consumption is low; at 3V the
filter draws 2mA.
Multiplexer
The multiplexer (MUX) that was used is a high-speed 8:1 analog multiplexer
(MUX). The input of the multiplexer comes from the MAX 7404 anti-aliasing filter.
The output of the multiplexer goes to the selectable gain. A 3-bit counter was used to
systematically cycle through the eight channels. The 3-bit counter to the MUX will
enable the signals to be TDM. Thus, the eight signals will be concatenated onto the same
line using small time slots. The device chosen for this application is the Maxim MAX
4617. The reasons for selection are a high speed switching rate and the low price
associated with it.
Selectable Gain
A requirement of the data acquisition device is to provide a user selectable gain
for the microphones. After the signal is filtered, it is then amplified using an operational
amplifier. This will be accomplished using the Analog Devices AD8330 operational
amplifier. This amplifier has the ability to change gains based on the voltage level
applied to one of its pins. This particular amplifier was selected mainly due to its ease of
use. Unlike other similar devices it does not use a serial interface in order to set the gain
and other options. Instead, it relies on using the voltage on two pins in order to determine
5
the amount of gain to be used on the signal. The two pins provide the selectable gain.
The first pin determines the base gain added (0-50 dB), and the second provides a
multiplier ranging from 0 to 8. The design uses two dipswitches and two voltage ladders
in order to deliver defined voltage levels to the device, thus giving the user easily
selectable gain levels by setting the switches directly on the board. At some point later it
may be possible to eliminate this part by adding some more circuitry to the USB
microcontroller to set the gain. This would be accomplished by using flip-flops to
provide different states for each respective switch position. However, it was determined
that this would be too complex to fit in the proposed timeline. The team felt that
dipswitches would be suitable as a proof of concept.
Analog to Digital Converter (ADC)
A successive approximation converter uses comparator and counting logic to
perform the needed conversion. The advantage of using this type of ADC is it
incorporates a fast sampling rate with the potential of having a high resolution. The
resolution range of the successive approximation ADC is from 8 bits to 16 bits. The
more bits used in the system, the slower the sampling rate. Specifically, the Analog
Devices 1165 will be used. This ADC provides a resolution of 16 bits and up to
100kSps. Additionally, the AD1165 has a very low power consumption using only 400
microamperes. The chip provides 16-bit parallel output; this is convenient for connecting
to the USB controller.
USB Controller
6
The USB Controller is a microprocessor that is used to convert the ADC output to
USB packets that can be sent to the StarGate node. The selected controller is the Cypress
AN2131Q. This controller was selected based on the recommendation of Dr. Ertin and
because of the wealth of documentation associated with it. The USB endpoint type used
to send the data will be bulk transfer. This is because the data does not need to be
streamed in real time as long as a fixed delay is provided. The bulk transfer mode
guarantees that each packet will be transmitted error free. The bulk transfer was chosen
over the isochronous transfer because isochronous does not guarantee packet delivery and
bulk transfer it is much easier and more commonly implemented. The controller was
purchased as a surface mount chip with 80 pins. The team has found that by bending
every other pin up, it is possible to solder wires to each pin and connect it to a
breadboard.
The USB controller will provide many functions. First, it will stream audio
packets to the StarGate node. This was accomplished by attaching the 16 bits of the
ADC output to ports B and C of the controller. Ports B and C are each 8 bits. Thus, port
B contains the high order byte and port C contains the low order byte of the ADC sample.
The controller was programmed in 8051 assembly code to buffer 64 bytes of data, or 32
samples. Once the buffer is full, the controller sends a data packet to the StarGate node.
The second function of the controller will be to provide an 8kHz clock to the MUX and
the counter. This is possible because the controller’s internal clock runs at 24Mhz. Thus,
it can execute many clock cycles and still toggle an output bit on port A at 8kHz by using
timer 0, an internal timer on the controller.
7
Voltage Regulation
The components of the design require both a 5V and a 3.3V reference voltage.
The Cypress USB controller and the filter both require 3.3V reference while the rest of
the components require the 5V reference. The 5V voltage source comes from the USB
cable; however, the LM2931 voltage regulator is used to ensure that the 5V is stable. The
5V will remain stable with input voltages as high as 14 volts and as low as 3.3 volts. The
LM3940 was used for the 5V to 3.3V conversion.
StarGate
The StarGate node will be provided. The system specifications are available on
Crossbow’s website. The input will come from the USB Controller. The StarGate will
store the processed data in memory and able to wirelessly interface with other StarGate
nodes using a PCMCIA network interface card. The user will be able to connect to the
StarGate device via a RS-232 connection. Linux is the operating system on the StarGate.
Software is required to allow the hardware we have built to interface with the
StarGate. There were three solutions to this problem. The first was to write a standard
system driver. The second solution was to write an application based on the libusb
Application Programmer’s Interface (API). The third option is to morph the first and
second solutions to form a driver written with libusb. Libusb could be used in two
options because the API is merely a specification on how to make calls directly to the
kernel. It was determined that the best solution was to follow the first solution. Two
arguments were made for choosing this option. The first argument was that a driver
would provide a truly seamless solution to the end user. The second argument is that the
8
driver would provide a high level of performance. Research showed that there was no
strong support for simple Linux drivers that could interface with a Cypress chip. There
were two options to overcome this hurdle. One was to design a driver from scratch,
while option two was to search for available driver code that is used for other devices that
could be re-engineered to interface with our Cypress chip. The fastest and most robust
solution was determined to be the re-engineering of a scanner driver already present in
the kernel source tree. This is permissible due to the GNU Public License (GPL), which
allows for reuse of open source code as long as it is release back to the open source
community.
There are two files associated with the scanner files, /usr/src/linux2.4/drivers/usb/scanner.c and scanner.h. The header file is less important to us since it
already provides all necessary declarations. These two files were re-written, shortening
the code drastically. There was a lot of code in place to determine what hardware was
connected and to do other tasks that make the driver much more user friendly to endusers of scanners.
Team Yellow wrote a driver that should work well with the newly developed
hardware. However, during the testing and debugging phase of the software engineering,
an error was found. The error was that our driver could not read a full 64KB block of
data at a time. It would only operate properly for 1KB blocks of data. This error was
traced through multiple files in the kernel source code without finding the cause of the
error. In the best interest of the project with the given time constraints, it was determined
other solutions should be sought after. A viable solution was using a USB Application
Programmers Interface or API. Specifically, this software package is called libusb and is
9
available for free under the GNU Lesser General Public License (LGPL). The LGPL
allows for reuse of software written as long as any modifications that are made are
returned to the open source community. The libusb software package can be downloaded
from http://libusb.sourceforge.net.
Because a good portion of time was spent on the driver, and it operates much like
libusb, it is worthwhile going over the driver’s basic functionality. In order for the data
to be accurately transferred from the Cypress chip to the operating system, certain
standards must be met within the driver. Specifically, the USB 1.1 standard for bulk
transfer must be met. The action of the DAQ driver is closely related to that of a driver
for a scanner. They both perform bulk-in transfers, from the device to the computer.
The basic algorithm for the driver as follows. The driver will be initialized in the
operating system. Next, it will open the devices for reading/writing. This is followed by
the data transfers. Lastly, the device is closed, and the driver is removed from the
operating system. It is not a very complicated process.
With this background in the first attempt in integrating the Cypress chip with
Linux, a it is easier to have a clearer understanding of the roles that libusb performs. In
order for libusb to function properly, some system settings must be made. The first is
hotplugging must be setup in Linux. Hotplugging is a service that is ran by the operating
system and is responsible for loading drivers and/or firmware to USB connected devices.
This service functions according to a file called usb.usermap located in /etc/hotplug. This
file is parsed by the hotplug scripts whenever a new USB device is connected to the host.
It looks for a hardware entry for the newly connected device, and in this project, loads the
10
firmware written for the Cypress chip. After the hotplugging service is configured,
libusb can take over.
Libusb is an API for making function calls directly to the kernel. This option is
used to make calls directly to the kernel from the application code. The application code
is what the end user typically sees on a daily basis. It provides a nearly seamless
functionality to the end user. The biggest disadvantage to the libusb solution is that the
application must be ran as root. This is not always an option for the end user, and could
cause trouble for the system administrator of the StarGate.
The application code that will be developed by our team is capable of being quite
robust. The syntax for the user is as follows:
daqdata –c ChannelNumber
In above command line, ChannelNumber specifies the channel number that can be
chosen if the user would like to only read data from one channel. If no flags are
appended to the command line, all channels will be recorded. There are many
capabilities at this point. For instance, the data could be streamed through the wireless
interface to external devices that may collect the data from multiple daqs. Another
possibility is that the data could easily be listed in any format such as hexadecimal, octal,
binary, or decimal. The data could also be written in a variety of styles such as in
columns, comma delimited format, or whatever else the user may prefer.
Component Timing
There are three main delays associated with the ADC. The first and second
delays are the acquisition and conversion times presented in Figure 3 as tACQ and tCONV.
11
The acquisition time is the amount of time the ADC will accept input data. According to
the specs of the ADC, tACQ will typically be around 1.1 micrcoseconds, but changing the
clock cycle supplied by the controller can increase the acquisition time. Once tACQ has
elapsed, the ADC pushes the data through the conversion process where the analog signal
is converted to digital. The timing of this process is tCONV on the ADC timing diagram
and is typically 4.7 microseconds. Both of these signals will be run off the same clock
cycle, so tACQ will be increased to 4.7 microseconds. The third delay that will be
encountered is the time it takes for the data to be loaded on the output bus. This is
designated on the diagram as tDO and is 40ns. This delay is independent of the clock
cycle. Thus, the total timing delay associated with the ADC (from the start of the
acquisition of data to the time data is loaded onto the bus) will be approximately 9.44
microseconds.
Figure 4 - ADC Timing Diagram
12
Other delays associated in the system include a MUX delay that occurs when the
MUX switches from one line to another. This delay is only 15ns for our MUX. The
built-in time delay for the gain controller is 1.7 microseconds, and the filter time delay is
negligible. This gives a total time delay of approximately 11.5 microseconds from when
the analog signal is detected till it is loaded onto the output bus for processing by the
USB controller.
Testing Procedures
The design will go through a vigorous set of testing phases throughout its design
and implementation. The first phase of unit testing will be concerned with testing an
individual component’s functionality. This will be performed on the Cypress controller
by programming the firmware to output the 3-bit clock and monitoring the output pins of
tan oscilloscope. Further, it will be possible to test the microphones using an
oscilloscope to see if they are getting the required poser to function.
The nest phase of testing will be to perform integration testing. This will be an
extensive phase for the interconnection of the USB Controller and a Linux computer.
The test will test the Linux application code, the driver and the assembly controller code
simultaneously. Since there are many variables that can affect the outcome of this stage,
much time will be spent testing these components. The expected results of this phase
would be to create a USB packet on the USB controller, send it to the Linux host, read
the data, and display the data. If the packet received is the same as the packet send, the
test has passed.
13
The last phase of testing will be system testing. The proposed method of system
testing is to connect a function generator and produce a known, low voltage, waveform.
This waveform will simulate a microphone pulse. The pulse will go through the
multiplexer, be converted to digital, and then sent to the Linux host. The host will output
the received packet. The data will the be examined to determine how many significant
bits are usable. The test will pass if the team can get 16 usable bits. A usable bit is
defined as a bit that matches the input waveform. Bits may be unusable due to noise and
should not be considered in the total resolution of the system. If the team cannot get 16
usable bits, further design modifications may be necessary.
Detailed Parts List
Table 1 presents a table showing both the projected development costs and the
projected product cost. The only difference between the two figures lies with the USB
Controller. The team felt it necessary to purchase two controllers in development
because of the complex task of soldering the 80-pin surface mount device. Additionally,
a development version of the chip, which costs $80, might be required for the design.
This will not be included in the costs at this point.
Part No
Development
Production
P11969-ND
21.92
21.92
MAX7404
1.98
1.98
MAX4617
1.20
1.20
AD8330
9.34
9.34
MAX1165
8.00
8.00
14
LM2931
1.08
1.08
LM3940
2.17
2.17
AN2131Q
10.53
5.26
MISC
5
5
Total
75.08
69.82
Table 1 - Total Costs
Experimental Results
Talk about how each component work on its own. I want numbers and what you
actually did for EACH unit test. Everything was supposed to be unit tested.
Here’s my section for example:
In regards to the application experimental results, all tests passed. The command
‘daqdata –c 1’ could be executed, delivery a sequence of packets to the operating system.
This sequence of packets was received in order, and could then be written to a file.
Quantitative Results
Talk about the cost and performance score. Put your feelings on the hardware and
solution to say that our design was the coolest.
Here’s my section for example:
The application was able to quickly and efficiently process incoming data and
place it in a file. There is no requirement that the packets arrive in order; however Team
Yellow feels that the fact that the packets did arrive in order shows that application code
using libusb is a good solution for interfacing the Cypress chip to the operating system.
15
Verification of Results to Requirements
Teamwork
Team Yellow was fortunate to have a strong understanding of digital circuitry,
software, and power systems. This enabled us to tackle the large task of interfacing the
Cypress chip to the StarGate. This was done by our own accomplishments, and not by
installing a driver that was supplied with the chip. The analog portion of our design
lacked full understanding and integration because of the team’s inexperience in analog
system design. Communication skills were adequate, which made working together easy
to schedule, and easy to collaborate after individual tasks were fulfilled. Overall, Team
Yellow was highly functional and successful in regards to group dynamics.
Comments on Suggested Changes
This is the section where we admit parts suck, and other sections are the coolest.
It will be used for the next generation of this project. SHOULD BE WRITTEN WITH
CONCLUSION
Conclusion
This report has presented Team Yellow’s design in detail. Each component was
carefully selected to meet or exceed the minimum specifications anticipated by Professor
Potter. The proposed design was analyzed to determine how it would be affected if the
requirements were to change due to design improvements.
16
NEED TO TALK ABOUT THE END STATUS HERE
Finally, the timeline and cost analysis were provided to depict the status of the project.
17
18
References
“Filter Basics: Anti-Aliasing.” Internet: http://www.maximic.com/appnotes.cfm/appnote_number/928/ln/en, March 9, 2004.
“MAX7404.” Internet: http://www.maxim-ic.com/quick_view2.cfm/qv_pk/1899/ln/en, March 9, 2004.
“Electret Condenser Microphones.” Internet: http://www.addaxsound.com/electret.htm, March 9, 2004.
“DM9312 Product Folder.” Internet: http://www.national.com/pf/DM/DM9312.html, March 9, 2004.
“AD8330 Device.” Internet:
http://www.analog.com/UploadedFiles/Data_Sheets/592989715AD8330_a.pdf, April 14, 2004.
“MAX1165 Device.” Internet:
http://www.analog.com/UploadedFiles/Data_Sheets/592989715AD8330_a.pdf, April 14, 2004
“EZ-USB Technical Reference Manual.” Internet:
http://www.cypress.com/cfuploads/img/products/AN2131SC.pdf
19
Appendix
Daq.asm – Firmware for Cypress Controller
; This is the firmware that will control the DAQ device
; EE 682 Team Yellow,
; Written by Nick King
; Functions:
; create 8kHz 3 bit counter on PA[0..2], PA3, PA4 control ADC
; BULK IN2 Transfer to Linux
$NOMOD51
; disable predefined 8051 registers
$nolist
$include (ezregs.inc)
; EZ-USB register assignments
$list
VTEMP
VINDEX
MUXCNTR
CS_CNT
VALT
VPORTA
ORG
EQU
EQU
0x20
EQU
EQU
EQU
0x24
EQU
0x21
0x22
0x23
0x25
0000h
; --MOV
MOV
MOV
MOV
Initialize Variables
VINDEX, #0x00;
MUXCNTR,
#0x00;
CS_CNT, #0x00;
VPORTA, #0x00;
LJMP
MAIN
; ==========================================================
; Timer2 interrupt TF2 => 2bh
; ==========================================================
; PA3 = RC
; PA4 = CS
ORG
002Bh
PUSH
PUSH
PUSH
PUSH
PUSH
DPL
DPH
DPS
ACC
PSW
CPL
CLR
VPORTA.4
VPORTA.3
; toggle CS every 8000*3clocks*(1up and 1down)
MOV
SUBB
JZ
A, CS_CNT
A, #3
ST3
; mux cnt set high
MOV
A, CS_CNT
20
SUBB
JZ
A, #4
ST5
MOV
SUBB
JZ
A, CS_CNT
A, #5
ST3
MOV
SUBB
JNZ
MOV
A, CS_CNT
A, #6
ST6
CS_CNT, #0
MOV
SUBB
JZ
MOV
SUBB
JZ
A, CS_CNT
A, #5
ST3
; set high
A, CS_CNT
A, #6
ST5
; read adc
ST6:
ST1:
ST2:
ST3:
SJMP ENDST;
; increment the mux
INC
MUXCNTR
MOV
A, VPORTA;
ANL
A, #1111000b
; want to replace last 3 bits
ORL
A, MUXCNTR;
MOV
VPORTA, A
SJMP ENDST
; RC high, MUX
; RC goes high
; every other time increment MUXCNTR
SETB VPORTA.3
;RC high
INC
VALT;
JB
0, ST1
; every other 4 lets toggle the mux counter
SJMP ENDST
; keep this set
SETB VPORTA.3
SJMP ENDST
ST5:
; Time to read the ADC value (Does this cause the counter to go
wacky?)
SETB VPORTA.3
LJMP READADC
ENDADC:
SJMP ENDST
ENDST:
; ok ok , now lets get VPORTA taken care of
MOV
MOV
DPTR, #OUTA
A, VPORTA
21
MOVX
INC
@DPTR, A
CS_CNT
; restore value
POP
PSW
POP
ACC
POP
DPS
POP
DPH
POP
DPL
CLR
T2CON.7
CLR
T2CON.6
; reset the count overflow flags
;
RETI
MAIN:
; --- set up timer 0 to reset at 8000hz
; 12Mhz crystal, default is every 12th = 1Mhz
; 1 Mhz / x ticks = 8000*6
MOV
RCAP2H, #0xff
MOV
RCAP2L, #0xdf
CLR
T2CON.0
CLR
T2CON.4
CLR
T2CON.5
SETB T2CON.3
SETB
IE.7
SETB IE.5
SETB T2CON.2
... X=21 ticks...
; auto reload timer2
; auto reload timer2
; T2CON.0 = 0 -> Auto Reload Timer2
; enable all interrupts
; Turn on the timer
; --- set up the IO ports
mov
A, #00000000b
mov
DPTR, #OEB
movx @DPTR,
A
mov
A, #00000000b
mov
DPTR, #OEC
movx @DPTR,
A
mov
A, #11111111b
PA[2..0] output
mov
DPTR, #OEA
movx @DPTR,
A
; PORTB is input (MSB of ADC)
; PORTC is input (LSB of ADC)
; PORTA is mixture, PA3 input,
; initialize bulk transfer count
mov
r7,#32
; fill EP2IN buffer with 64 bytes
mov
dptr,#IN2BUF
; this is the main loop of the program...
; it does NOTHING
MAINLP:
LJMP READADC
SJMP MAINLP;
RESET:
22
; read PORTB, PORTC into r6, r5... when 64k filled, bulk transfer it
READADC:
MOV
MOVX
MOV
DPTR, #PINSB
A, @DPTR ; move value of DTPR into A
r6,A
MOV
MOVX
MOV
DPTR, #PINSC
A, @DPTR
r5,A
; bring the dptr back!~
MOV
DPH, r3
MOV
DPL, r4
MOV
DPS, r2
MOV
movx
inc
A, r6
@dptr,a
dptr
MOV
movx
inc
A, r5
@dptr,a
dptr
; save the dptr away..
MOV
r3, DPH
MOV
r4, DPL
MOV
r2, DPS
djnz
r7, ENDADC
; if r7 = 0 then we need to bulk transer!
; We are ready to trasnfer!
; service the bulk transfer
mov
mov
movx
dptr,#IN2BC ; load the IN2 Byte Count register
a,#64
; 64 bytes
@dptr,a
; arm the IN transfer
; reset the values
mov
dptr,#IN2BUF
MOV
r3, DPH
MOV
r4, DPL
MOV
r2, DPS
mov
r7,#32
LJMP
LJMP ENDADC
ENDADC;
;
; fill EP2IN buffer with 64 bytes
END
23
Bulk-timing.asm
; Check the timing between the cypress and the unix. Can we get
sequential packets at 8000/64 hz?
;
status: working!
$NOMOD51
; disable predefined 8051 registers
$nolist
$include (ezregs.inc)
; EZ-USB register assignments
$list
VTEMP
VINDEX
VCNTR
VCNTR2
ORG
EQU
EQU
0x20
EQU
0x22
EQU
0x21
0x23
0000h
; --- Initialize Variables
MOV
VINDEX, #0x00;
MOV
VCNTR,
#0x00;
LJMP
MAIN
; ==========================================================
; Timer2 interrupt TF2 => 2bh
; ==========================================================
ORG
002Bh
PUSH
PUSH
PUSH
PUSH
PUSH
INC
DPL
DPH
DPS
ACC
PSW
VCNTR ;
MOV
MOV
MOVX
DPTR, #OUTB
A, VCNTR
@DPTR, A
;; service the bulk transfer at
mov
dptr,#IN2CS ; EP2IN
movx a,@dptr
jnb
acc.1,service_IN2 ;
DONEBIN:
; restore value
POP
PSW
POP
ACC
POP
DPS
POP
DPH
POP
DPL
CLR
T2CON.7
;
CLR
T2CON.6
;
8000/64 hz.
Control & Status register
check the busy bit, service if LOW
reset the count overflow flags
RETI
MAIN:
24
; --- set up timer 0 to reset at 8000hz
; 12Mhz crystal, default is every 12th = 1Mhz , so pulse 125 ticks at
1Mhz = 8000hz
; 1 Mhz / x ticks = 8000/64Hz
MOV
RCAP2H, #0xe0
MOV
RCAP2L, #0xbf
CLR
T2CON.0
CLR
T2CON.4
CLR
T2CON.5
SETB T2CON.3
SETB
IE.7
SETB IE.5
SETB T2CON.2
... X=8000 ticks...
; T2CON.0 = 0 -> Auto Reload Timer2
; enable all interrupts
; Turn on the timer
; --- set up the IO ports
mov
mov
movx
A, #11111111b
DPTR, #OEB
@DPTR,
A
mov
mov
movx
A, #0x00
; set PORTBCFG (no special lines)
DPTR, #PORTBCFG;
@DPTR, A
;start:
mov
mov
fill:
mov
movx
inc
djnz
starting w. 64
;
mov
mov
mov
mov
movx
;
; PORTB is output
mov
SP,#STACK-1 ; set stack
dptr,#IN2BUF
r7,#64
; fill EP2IN buffer with 64 bytes
a,r7
@dptr,a
dptr
r7,fill
; load decrementing counter
r1,#0
r2,#0
dptr,#IN2BC
a,#64
@dptr,a
;
;
;
;
count the IN transfers
count the OUT transfers
load the IN2 Byte Count register
64 bytes
; arm the IN transfer
; loopstart
BEGIN:
DEPT:
LJMP DEPT
service_IN2:
mov
mov
inc
r1
; IN packet countr
dptr,#IN2BUF
a,r1
; load IN packet count into first IN2BUF
byte
movx
@dptr,a
mov
dptr,#IN2BC ; load the EP2IN byte count to re-
arm IN transfer
25
mov
movx
ljmp
a,#64
@dptr,a
DONEBIN
; 64 byte payload
END
26
Daqdata.c – Libusb application program
#include <stdio.h>
#include <linux/version.h>
#include <usb.h>
#include <sys/time.h> /* struct timeval, select() */
/* ICANON, ECHO, TCSANOW, struct termios */
#include <termios.h> /* tcgetattr(), tcsetattr() */
#include <stdlib.h> /* atexit(), exit() */
#include <unistd.h> /* read() */
usb_dev_handle *locate_xsv(void);
int isEqual(unsigned char *buf1, unsigned char *buf2);
void print_buf(unsigned char *buf);
static int kbhit (void);
static void raw(void);
static void cooked(void);
static int NUMBER_OF_CHANNELS = 8;
static int DISPLAY_CHANNEL_NUM = -99;
int main (int argc,char **argv)
{
// parse the command line:
if (argc > 0)
{
int cmd_idx = 1;
while (argv[cmd_idx] != NULL)
{
if (strcmp(argv[cmd_idx], "-c") >= 0)
{
cmd_idx++;
DISPLAY_CHANNEL_NUM = atoi(argv[cmd_idx]);
cmd_idx++;
}
}
}
struct usb_dev_handle *xsv_handle;
int open_status;
unsigned char receive_data[64];
unsigned char old_receive_data[64];
usb_init();
//
usb_set_debug(2);
if ((xsv_handle = locate_xsv())==0)
{
printf("Could not open the XSV device\n");
return (-1);
}
27
// set up configuration 1, interface 0, alt setting 1
open_status += usb_set_configuration(xsv_handle,1);
//
printf("conf_stat=%d\n",open_status);
open_status += usb_claim_interface(xsv_handle,0);
//
printf("claim_stat=%d\n",open_status);
open_status += usb_set_altinterface(xsv_handle,1);
//
printf("alt_stat=%d\n",open_status);
if (open_status < 0)
{
printf("An Error occurred initializing the device");
}
// loop
//
printf("press a key to exit test\n");
while (!kbhit())
{
usb_bulk_read(xsv_handle,2,receive_data,64,5400);
if (isEqual(old_receive_data, receive_data) < 0 )
{
print_buf(receive_data);
}
//
sleep(1);
int i;
for (i=0; i<64; i++)
{
old_receive_data[i] = receive_data[i];
}
}
//
printf("Key presssed, exiting\n");
printf("\n");
usleep(10000);
usb_close(xsv_handle);
return 0;
}
int isEqual(unsigned char *buf1, unsigned char *buf2)
{
int i;
for (i=0; i<64; i++)
{
if (buf1[i] != buf2[i])
{
return -1;
}
}
return 1;
}
void print_buf(unsigned char *buf)
{
28
int i=0;
int ch_cnt = 0;
for (i =0, ch_cnt=0 ; i<32; i+=2, ch_cnt++)
{
int j = buf[i]; // going into 16 bits... (int)
j <<= 8;
// shift to 16 bits high byte
j |= buf[i+1]; // or the two bytes together
if (DISPLAY_CHANNEL_NUM > 0 && ch_cnt != DISPLAY_CHANNEL_NUM)
{}
else
{
printf(" %Xh ", j);
}
if (ch_cnt == NUMBER_OF_CHANNELS-1)
{
printf("\n");
ch_cnt = -1;
}
}
//
printf("\n\n----------------------------------------------\n");
}
/**
Locate the daq device, make sure it is the cypress chip.
*/
usb_dev_handle *locate_xsv(void)
{
unsigned char located = 0;
struct usb_bus *bus;
struct usb_device *dev;
usb_dev_handle *device_handle = 0;
usb_find_busses();
usb_find_devices();
for (bus = usb_busses; bus; bus = bus->next)
{
for (dev = bus->devices; dev; dev = dev->next)
{
if (dev->descriptor.idVendor == 0x547)
{
located++;
device_handle = usb_open(dev);
}
}
}
if (device_handle==0) return (0);
else return (device_handle);
}
29
/*
The rest of the file contains helper functions that are the work of
their respective authors. Kbhit is needed because ANSI C does not
contain conio.h. This is because of the difference between unix/windows
consols.
*/
static struct termios g_old_kbd_mode;
/*
* kbhit() -- a keyboard lookahead monitor
*
* returns the number of characters available to read.
*/
static int kbhit(void)
{
struct timeval timeout;
fd_set read_handles;
int status;
raw();
/* check stdin (fd 0) for activity */
FD_ZERO(&read_handles);
FD_SET(0, &read_handles);
timeout.tv_sec = timeout.tv_usec = 0;
status = select(0 + 1, &read_handles, NULL, NULL, &timeout);
if(status < 0)
{
printf("select() failed in kbhit()\n");
exit(1);
}
return status;
}
static void raw(void)
{
static char init;
/**/
struct termios new_kbd_mode;
if(init)
return;
/* put keyboard (stdin, actually) in raw, unbuffered mode */
tcgetattr(0, &g_old_kbd_mode);
memcpy(&new_kbd_mode, &g_old_kbd_mode, sizeof(struct termios));
new_kbd_mode.c_lflag &= ~(ICANON | ECHO);
new_kbd_mode.c_cc[VTIME] = 0;
new_kbd_mode.c_cc[VMIN] = 1;
tcsetattr(0, TCSANOW, &new_kbd_mode);
/* when we exit, go back to normal, "cooked" mode */
atexit(cooked);
init = 1;
}
30
static void cooked(void)
{
tcsetattr(0, TCSANOW, &g_old_kbd_mode);
}
31
/etc/hotplug/usb.usermap
# usb module
match_flags idVendor idProduct bcdDevice_lo
bcdDevice_hi bDeviceClass bDeviceSubClass bDeviceProtocol
bInterfaceClass bInterfaceSubClass bInterfaceProtocol driver_info
ezusb
0x00
0x0003 0x547 0x2131 0x00 0x4000 0xff 0xff 0xff 0x00 0x00 0x00
/etc/hotplug/usb/ezusb
#!/bin/sh
# Load bulk/interrupt transfer test firmware into
# various EZ-USB USB devices that will run it
#
# Assumes 2002_04_11 release of fxload (or later)
#FIRMWARE=/home/kingn/usb/test/io_test.hex
FIRMWARE=/fat/ee682/ezbulk.hex
FIRMWARE=/fat/ee682/daq.hex
FLAGS=
LOADER=/sbin/fxload
# use "-s $A3LOAD" for firmware that goes into external RAM
A3LOAD=/usr/share/usb/a3load.hex
# pre-renumeration device IDs
case $PRODUCT in
# (USB 2.0) FX2 development kit
4b4/8613/*)
FIRMWARE=usb/perf.fw/bulksrc-fx2.ihx
FLAGS="-t fx2"
;;
# (USB 1.1) Keyspan USA-19Q PDA adapter
# ... we can use any non-FX2 device with this firmware
6cd/10b/*)
FIRMWARE=usb/perf.fw/bulktest-fx.ihx
FLAGS="-t an21"
;;
# other pre-renumeration IDs could go here
# but most would fit one of the two cases above
esac
# quit unless we were called to download some firmware
if [ "$FIRMWARE" = "" ]; then
# OR: restructure to do other things for
# specific post-renumeration devices
exit 0
fi
32
# missing firmware?
if [ ! -r $FIRMWARE ]; then
if [ -x /usr/bin/logger ]; then
/usr/bin/logger -t $0 "missing $FIRMWARE for $PRODUCT ??"
fi
exit 1
fi
# missing loader?
if [ ! -x $LOADER ]; then
if [ -x /usr/bin/logger ]; then
/usr/bin/logger -t $0 "missing $LOADER ??"
fi
exit 1
fi
if [ -x /usr/bin/logger ]; then
/usr/bin/logger -t $0 "load $FIRMWARE for $PRODUCT to $DEVICE"
fi
$LOADER $FLAGS -I $FIRMWARE
33
© Copyright 2026 Paperzz