Back to the README Previous step : Installation of Amaranth and cie
This section details how to flash the gateware and how to configure the FPGA via UART serial.
usage: flashZedBoard.py [-h] [--platform PLATFORM] [--bitlen BITLEN] [--noiselen NOISELEN] [-m MODFREQ] [-p] [-v]
[--no-build] [--no-load] [--flash] [--build-dir BUILD_DIR] [--conv-to-bin]
[--toolchain TOOLCHAIN]
options:
-h, --help show this help message and exit
--platform PLATFORM Target Platform (CMOD A7 only for now)
--bitlen BITLEN number of bits of the LFSR
--noiselen NOISELEN length of the PRN sequence
-m MODFREQ, --modfreq MODFREQ
frequency of the PSK modulation (Hertz) (default :2.5e6)
-v, --verbose prints all the parameters used for this instance of the program
--no-build sources generate only
--no-load don't load bitstream
--flash write bitstream into SPI flash (CMOD A7 only)
--build-dir BUILD_DIR
build directory
--conv-to-bin convert .bit file to .bit.bin
--toolchain TOOLCHAIN
toolchain to use (Vivado or Symbiflow) (CMOD A7 only) (default: Vivado)
Required options:
BITLENis the PRN shift register size (Pseudo-Random Noise generation) (default: 17)NOISELENis the number of bits produces before reseting the PRN shift register (default: 100000)
Optional options:
--no-buildlimit to amaranth -> Verilog convert--no-loadbypass load step after bitstream--flashwrite the bitstream in non-volatile memory, by default, the bitstream is written to volatile memory.
for example:
./amaranth_twstft/flashZedBoard.py --bitlen 17 --noiselen 100000
CMOD A7 only: by default Vivado is used to produces the bitstream, but it's also possible to use the f4pga Open-Source toolchain.
For testing if the FPGA configuration was successful, the output must be enabled, e.g. with
python3 amaranth_twstft/twstft_config.py -d /dev/ttyUSB1 -l 17 -ta 9 -C OFF -M BPSK
leading to the following output if the input 10 MHz and 1 PPS are well connected:
At runtime, the FPGA can be configured with the twstft_config.py script.
usage: twstft_config.py [-h] [-d DEVICE] [-b BAUDRATE] [-l BITLEN] [-m] [--list] [-p] [-ta TAPS_A] [-tb TAPS_B] [--prn NOISELEN] [-t] [-M {OFF,CARRIER,BPSK,QPSK}] [-T {OFF,INVERT_FIRST_CODE,TIMECODE}]
[-C {AUTO,CLK,PPS,OFF}] [-c] [-R]
options:
-h, --help show this help message and exit
-d, --device DEVICE
-b, --baudrate BAUDRATE
serial baudrate
-l, --bitlen BITLEN the bitlen of the fpga's LFSR. Hardwired in FPGA's gateware, this option doesn't modify it's config but is requiered to communicate properly the taps settings
-m, --monitor keep listning and print debug signals to stdout
--list list available devices
-p, --pps when monitoring, also print debug signal for valid and expected PPS
-ta, --taps-a TAPS_A set taps for LFSR A (BPSK & QPSK)
-tb, --taps-b TAPS_B set taps for LFSR B (QPSK only)
--prn NOISELEN save a PRN of N bits generated by given taps
-t, --set-time set FPGA's time to computer's time
-M, --mode {OFF,CARRIER,BPSK,QPSK}
turn OFF / set modulation mode
-T, --time-mode {OFF,INVERT_FIRST_CODE,TIMECODE}
set timecode mode
-C, --calib-mode {AUTO,CLK,PPS,OFF}
set calibration mode
-c, --ask-calib (re)calibbrate if not already done and return pps phase
-R, --reset reset FPGA and config to default
./twstft_config.py --list will list available serial ports.
DEVICE must be set to the one connected to the FPGA.
The taps of both LFSR can be set independently with:
./twstft_config.py -d DEVICE -l BITLEN -t{a|b} TAPS
Where BITLEN is the size of the LFSR, and the same as the BITLEN specified at bitstream generation.
To save the generated PRN to disk:
./twstft_config --prn NOISELEN -l BITLEN -ta TAPS_A [-tb TAPS_B]
If both taps are specified, the two prn are interlaced bit by bit.
Options are fully compatible, and can be passed in one command :
./twstft_config.py -d /dev/ttyUSB1 -l 17 -ta 9 -tb 15 --prn 100000
Will set the LFSR taps on the FPGA to 9 and 15, and save both 100000 bits PRN interlaced in a 200K file (1 bit per byte).
Note: setting LFSR's taps to zero disable it. At reset, both taps are set to zero.
The modulation scheme can be set with:
./twstft_config.py -d DEVICE -M MODE
Where MODE can be:
OFFdisable antenna output and output a constant low signal.CARRIERoutput clean 70MHz carrier.BPSKoutput BPSK modulated by LFSR AQPSKoutput QPSK modulated orthogonally by LFSRs A and B
Note: At reset, mode is set to OFF.
This option allows to encode the second start or even the seconds of the minute in the phases of PRNs. It is set with:
./twstft_config.py -d DEVICE -T MODE
Where MODE can be:
OFFdisable time encodingINVERT_FIRST_CODEat each PPS, the phase of the first PRN is flipped, allowing time comparison between clocks with more than a PRN's length in offset, as long as the offset is less than half a second.TIMECODEat each PPS, the phase of the first PRN is flipped, and the phases of the 6 following PRNs encode the seconds of the minute from 0 to 59. Allowing time comparison between clocks with as much as 30 seconds offset.
Note: At reset, timecode is disabled.
When using TIMECODE, to set the FPGA's seconds counter, use --set-time to set the FPGA's time to computer's time.
Option -C sets the output off the calibration pin. It's usage is described in the next section. During normal use, this setting should be set to OFF or AUTO.
Note: At reset, this is set to AUTO.
When receiving a PPS, the FPGA starts a timer that takes one second to finish. When an unexpected PPS is received, a warning is send via UART to the computer.
To monitor these warnings, use option -m. To also get messages when the PPS arrives at the right time, add --pps.
All option, are compatibles, when using -m, all config modifications are performed before the monitoring begins.
It is also possible to modify config while another instance of the script is monitoring, but beware that the monitoring will crash if another instance tries to read from the serial port.
On certain phase conditions between the input PPS and the input 10MHz clock, the detection system can enter a metastable state, causing the PPS to be detected in one tick or the next in the 280Hz clock domain. In order to avoid these conditions, it may be necessary to delay the input PPS to ensure that it will always be detected during the same tick.
This shoud be the prefered method of calibration and is enabled by default.
During the calibration sequence, the fpga tries to delay the PPS by increments of around 80 ps until the PPS is detected in another tick, then the delay element is set as far as possible from the metastable timing. This process can take from 1 to 30 seconds since we have to wait for a PPS at each iteration. Once the calibration is done, the fpga sends the CALBRATION_DONE code followed by one octet ranging from 0 to 27. This number represent in which tick of the 280 MHz clock the PPS is detected, relatively to the 10 MHz reference clock. For example, if the calibration in station A yields 3 and yields 5 in station B, the latency between the begining of the second and the sending of the PRN will be ~7.2 ns longer in station B. So for absolute time comparison, this offset needs to be accounted for.
By default, the calibration sequence is launched at reset and when a bad PPS is detected. To ask the phase number of the calibration (and do the calibration if not already done) :
./twstft_config.py -d DEVICE -c
To turn off the automatic calibration when a bad PPS is detected:
./twstft_config.py -d DEVICE -C OFF
To find the safe phase conditions, we need a way to phase shift the PPS signal by a whole 280MHz period (~3.6ns) and an oscilloscope to monitor the effect of the phase shift.
To automate the search for a safe phase span, we used an Agilent 33220A arbitrary waveform generator to phase shift the 10MHz clock ticking the PPS generator, and a Rohde & Schwarz RTO2034 oscilloscope triggered at the rising edge of the input PPS looking for the rising edge of the detected PPS. To output the detected PPS on the FPGA's calibration pin, use the command :
./twstft_config.py -d DEVICE -C PPS
For the CMOD A7 board, we performed 3 phase-sweeps, each with a 36ps step and 200 acquisitions per step, once without emitting on the antenna pin, once emitting a clean carrier and once emitting a BPSK modulated signal. These two acquisitions are to ensure that cross-wire interference from the antenna pin doesn't affect PPS detection.
Results with antenna output off:

Results with antenna output emitting a clean carrier:

Results with antenna output emitting a BPSK modulated signal:

For the CMOD A7 board, we find that a 12ns delay between the rising edges at a 1V threshold, is safe.
Note: the calibration pin has a notch filter set at 70MHz in order to cancel cross-wire interference from the antenna.
Note: when setting up a TWSTFT station with a CMOD A7 board, it is not necessary to replicate these acquisitions. Only to ensure that the measured delay between the rising edges at a 1V threshold is in the green span of the above diagrams. When we will support other FPGA boards, we will add the safe spans for each of them.
| function | dir | CMOD A7 |
|---|---|---|
| 10MHz in | in | GPIO46 |
| PPS in | in | GPIO42 |
| calibration | out | GPIO36 |
| output | out | GPIO31 |
| UART-i | in | micro-USB |
| UART-o | out | micro-USB |
Next step : Pseudo-Random Noise generation

