|
|
|
# MicroZed Software
|
|
|
|
|
|
|
|
The python script `tdc_demo.py` can be downloaded in the repository.
|
|
|
|
With this file should be put the [`devmem.py`
|
|
|
|
file](https://github.com/kylemanna/pydevmem/blob/master/devmem.py) .
|
|
|
|
This software is used to configure the ADC board but also to process the
|
|
|
|
delay between the pulses. The incoming pulses are first transformed into
|
|
|
|
damped sines. We then apply a fitting function on it to determine the
|
|
|
|
best suited mathematical model. Among the parameters of the mathematical
|
|
|
|
model is the phase. By determining the phase for all the incomming
|
|
|
|
pulses and by computing the difference between them, it is possible to
|
|
|
|
figure out what was the delay between them.
|
|
|
|
|
|
|
|
As a reminder, the board uses a Zynq device. On such SoC, we have both a
|
|
|
|
FPGA (Programmable Logic or PL) and a dual core ARM (Processing System
|
|
|
|
or PS). On this board are installed python3, the numpy and scipy
|
|
|
|
libraries.
|
|
|
|
|
|
|
|
## Gateware Setup
|
|
|
|
|
|
|
|
The first part of the script is used to set the gateware and reset the
|
|
|
|
ADC. First, the ADC is configured by the SPI communication. Before
|
|
|
|
taking the measurements, the ADC is reset by tuning it off and on.
|
|
|
|
Multiples parameters can be set using via this interface such as the ADC
|
|
|
|
output mode or the output phase. It is also possible to test if the
|
|
|
|
gateware is working properly by asking to the ADC to generate a bit
|
|
|
|
pattern.
|
|
|
|
|
|
|
|
The reset sequence is ordered like this :
|
|
|
|
|
|
|
|
1. SERDES clock distribution
|
|
|
|
2. SERDES itself
|
|
|
|
3. ADC core
|
|
|
|
|
|
|
|
The ADC is controled by the GPIO0 pins 5, 6, 7 respectively the chip
|
|
|
|
select, the clock and the data pins. The script is used to configure the
|
|
|
|
ADC in DDR mode.
|
|
|
|
|
|
|
|
Two LEDs are also provided on the board. They are connected on GPIO0 pin
|
|
|
|
0 and 4. In the `tdc_demo.py` they are used to tell the user if the
|
|
|
|
recording has been triggered.
|
|
|
|
|
|
|
|
The AXI bus can be accessed by the Linux running on the board by
|
|
|
|
accessing slot 0x40000000 in the memory.
|
|
|
|
|
|
|
|
## Data acquisition
|
|
|
|
|
|
|
|
The first step to acquire data is to configure the data buffer and the
|
|
|
|
trigger. A pretrigger can be set for prototyping/debugging. In our case,
|
|
|
|
it has been set to 10 samples. This allows us to see if the trigger
|
|
|
|
worked correctly by plotting the waveform. If the trigger threshold
|
|
|
|
level is not correctly set, it is possible to miss the first
|
|
|
|
alternations of our signal, this may generate errors.
|
|
|
|
|
|
|
|
Once the triggers are set and armed, we are able to catch the data. One
|
|
|
|
of the LEDs should be turned on to inform that the setup is done and the
|
|
|
|
system is waiting for data to come. For the moment, the code is poling
|
|
|
|
the triggers register in order to detect when data has been caught.
|
|
|
|
|
|
|
|
The other LED should light up when the pulse has been detected and the
|
|
|
|
data transfer form the PL to the PS can be done. Once the PS has read
|
|
|
|
the buffers, the fitting algorithm can be applied.
|
|
|
|
|
|
|
|
## fitting algorithm
|
|
|
|
|
|
|
|
The fitting algorithm is done on 110 pts. This number of points has been
|
|
|
|
experimentally determined as optimal. The 15 firsts points of the frame
|
|
|
|
are not used. On one side, this is because of the pre trigger. The 10
|
|
|
|
firsts points are just used for debugging. The 5 following points are
|
|
|
|
removed to "clean the signal", more on that later.
|
|
|
|
|
|
|
|
The fitting is done by a scipy built-in function:
|
|
|
|
`scipy.optimize.curve_fit(f, xdata, ydata)` assuming `ydata = f(xdata,
|
|
|
|
*params) + eps`. As we use a damped sine shape signal, the used
|
|
|
|
mathematical model
|
|
|
|
is
|
|
|
|
|
|
|
|
A*np.sin(2*np.pi*f/FS*xdata + 2*np.pi*f*phi/1e6)* np.exp(-tau*xdata) + offset
|
|
|
|
|
|
|
|
Our parameters are:
|
|
|
|
|
|
|
|
1. `A` : the amplitude.
|
|
|
|
2. `f` : the signal frequency. This is estimated in comparison with the
|
|
|
|
sampling frequency (FS). This constant has to be set at the
|
|
|
|
beginning of the script. Any error on this frequency will generate
|
|
|
|
errors on the measurements.
|
|
|
|
3. `phi` : the phase shift. This phase shift is here returned as a
|
|
|
|
picosecond delay.
|
|
|
|
4. `tau` : the damping factor of our function.
|
|
|
|
5. `offset` : as our signal is not perfectly centered on zero, the
|
|
|
|
offset parameters has to be computed.
|
|
|
|
|
|
|
|
The parameter `phi` returns the phase shift in picosecond. If this
|
|
|
|
fitting function is applied to the signal coming on different channels,
|
|
|
|
we can deduce their independent phase shift. The difference between
|
|
|
|
these phase shifts can be computed to determine the delay between the
|
|
|
|
pulses.
|
|
|
|
|
|
|
|
## Correction of the incoming wave form
|
|
|
|
|
|
|
|
The five first points are removed from the fitting algorithm. This is
|
|
|
|
due to the fact that the signal shapes at the beginning is distorted
|
|
|
|
(figure 1). This distortion is due to the CMOS gate slew rate (see
|
|
|
|
filter section for more explanations). The best way to avoid those
|
|
|
|
distortion to add errors on the fitting algorithm is to remove them
|
|
|
|
before applying the fitting.
|
|
|
|
|
|
|
|
/4747
|
|
|
|
*Figure 1 - Distortion at the beginning of the pulse*
|
|
|
|
|
|
|
|
## Correction of the fitting algorithm
|
|
|
|
|
|
|
|
It is possible that the signal is interpreted the wrong way by the
|
|
|
|
algorithm. For example, it is possible that the mathematical model that
|
|
|
|
fits the signal has a negative amplitude. The phase delay is then
|
|
|
|
determined with a multiple of the signal frequency of error. It is
|
|
|
|
possible to correct it by analysing both the phase and the amplitude
|
|
|
|
sign on a case by case basis. The actual solution does not work in all
|
|
|
|
the cases and a deeper analysis is required to improve it.
|
|
|
|
|
|
|
|
## Improvements
|
|
|
|
|
|
|
|
This works for delays smaller than the sampling period (10 ns). It is
|
|
|
|
possible to determine bigger delays but some steps have to be added to
|
|
|
|
the algorithm and maybe some gateware modification would be required.
|
|
|
|
For bigger delays, the trigger on the different channels has to be
|
|
|
|
independent and the time between them has to be counted. This can be
|
|
|
|
done by implementing a counter in the ADC core.
|
|
|
|
|
|
|
|
## Class descriptions
|
|
|
|
|
|
|
|
### GPIO
|
|
|
|
|
|
|
|
This class is used to handle the GPIOs.
|
|
|
|
|
|
|
|
*Functions:**
|
|
|
|
\*`__init__(self, mem, addr)`: The builder. Offset address is 0x0000.
|
|
|
|
\*`direction(self, pin, is_out)`: Set the pin direction (0 for in and 1
|
|
|
|
for out).
|
|
|
|
\*`set(self, pin, value)`: Set or clear an output value on one pin.
|
|
|
|
\*`get(self, pin)`: Return boolean input pin value.
|
|
|
|
|
|
|
|
### BitBangedSPI
|
|
|
|
|
|
|
|
Used to control the SPI communication trough the GPIOs.
|
|
|
|
|
|
|
|
*Functions:**
|
|
|
|
\*`__init__(self, gpio, cs_pin, sck_pin, data_pin)`: The builder. All
|
|
|
|
the pins are defined here.
|
|
|
|
\*`cs(self, value)`: Set the value on the chip select pin.
|
|
|
|
\*`sck(self, value)`: Set the value on the clock pin.
|
|
|
|
\*`set_sdata(self, value)`: Used to send one data bit on the data pin.
|
|
|
|
\*`get_sdata(self)`: Used to read one data bit on the data pin.
|
|
|
|
\*`txrx(self, data, n_bits)`: Transmits or reads `n_bits`. If data is
|
|
|
|
set to zero, this function just reads what is on the data line.
|
|
|
|
|
|
|
|
### Trigger
|
|
|
|
|
|
|
|
Controls the hardware trigger inside the FPGA.
|
|
|
|
|
|
|
|
*Functions:**
|
|
|
|
\*`__init__(self, mem, addr)`: The builder. The different addresses are
|
|
|
|
0x1000 for channel 0, 0x3000 for channel 1, 0x5000 for channel 2 and
|
|
|
|
0x8000 for channel 3.
|
|
|
|
\*`configure(self, edge, threshold_lo, threshold_hi, mask)`: Set the
|
|
|
|
trigger independently. Set the triggering edge (Rising edge if 0 and
|
|
|
|
Falling edge if 1). The two threshold levels are set here. Finally, the
|
|
|
|
mask is used to link the trigger to the other channels. If the trigger
|
|
|
|
mask is set to 0xF, this means that any event on any channel will
|
|
|
|
trigger the record on all the channels. Any other combination of trigger
|
|
|
|
can be configured.
|
|
|
|
|