Hardware (CPLD-based) synchronisation
======================================= This commit allows to synchronise multiple HackRFs with a synchronisation error **below 1 sampling period** > WARNING: Use this at your own risk. If you don't know what you are doing you may damage your HackRF. > The author takes no responsability for potential damages Usage example: synchronise two HackRFs ====================================== 1. Chose the master HackRF which will send the synchronisation pulse (HackRF0). HackRF1 will represent the slave hackrf. 2. Retreive the serial number of both HackRFs using `hackrf_info` 3. Use a wire to connect `SYNC_CMD` of HackRF0 to `SYNC_IN` of HackRF0 and HackRF1 4. Run `hackrf_transfer` with the argument `-H 1` to enable hardware synchronisation: ``` $ hackrf_tranfer ... -r rec1.bin -d HackRF1_serial -H 1 | hackrf_transfer ... -r rec0.bin -d HackRF0_serial -H 1 ``` rec0.bin and rec1.bin will have a time offset below 1 sampling period. The 1PPS output of GNSS receivers can be used to synchronise HackRFs even if they are far from each other. >DON'T APPLY INCOMPATIBLE VOLTAGE LEVELS TO THE CPLD PINS Signal | Header |Pin | Description -------|--------|----|------------ `SYNC_IN` | P28 | 16 | Synchronisation pulse input `SYNC_CMD` | P28 | 15 | Synchronisation pulse output Note: ===== I had to remove CPLD-based decimation to use a GPIO for enabling hardware. More info: ========== [M. Bartolucci, J. A. Del Peral-Rosado, R. Estatuet-Castillo, J. A. Garcia-Molina, M. Crisci and G. E. Corazza, "Synchronisation of low-cost open source SDRs for navigation applications," 2016 8th ESA Workshop on Satellite Navigation Technologies and European Workshop on GNSS Signals and Signal Processing (NAVITEC), Noordwijk, 2016, pp. 1-7.](http://ieeexplore.ieee.org/document/7849328/) [Alternative link](http://spcomnav.uab.es/docs/conferences/Bartolucci_NAVITEC_2016.pdf)
This commit is contained in:
@ -132,11 +132,12 @@ static struct gpio_t gpio_cpld_tms = GPIO(3, 1);
|
||||
static struct gpio_t gpio_cpld_tdi = GPIO(3, 4);
|
||||
#endif
|
||||
|
||||
static struct gpio_t gpio_rx_decimation[3] = {
|
||||
GPIO(5, 12),
|
||||
GPIO(5, 13),
|
||||
GPIO(5, 14),
|
||||
};
|
||||
//static struct gpio_t gpio_rx_decimation[3] = {
|
||||
// GPIO(5, 12),
|
||||
// GPIO(5, 13),
|
||||
// GPIO(5, 14),
|
||||
//};
|
||||
static struct gpio_t gpio_hw_sync_enable = GPIO(5,12);
|
||||
static struct gpio_t gpio_rx_q_invert = GPIO(0, 13);
|
||||
|
||||
i2c_bus_t i2c0 = {
|
||||
@ -242,11 +243,7 @@ w25q80bv_driver_t spi_flash = {
|
||||
|
||||
sgpio_config_t sgpio_config = {
|
||||
.gpio_rx_q_invert = &gpio_rx_q_invert,
|
||||
.gpio_rx_decimation = {
|
||||
&gpio_rx_decimation[0],
|
||||
&gpio_rx_decimation[1],
|
||||
&gpio_rx_decimation[2],
|
||||
},
|
||||
.gpio_hw_sync_enable = &gpio_hw_sync_enable,
|
||||
.slice_mode_multislice = true,
|
||||
};
|
||||
|
||||
@ -824,11 +821,6 @@ void pin_setup(void) {
|
||||
scu_pinmux(SCU_PINMUX_GPIO3_10, SCU_GPIO_PDN | SCU_CONF_FUNCTION0);
|
||||
scu_pinmux(SCU_PINMUX_GPIO3_11, SCU_GPIO_PDN | SCU_CONF_FUNCTION0);
|
||||
|
||||
//gpio_input(&gpio_sync_in_a);
|
||||
//gpio_input(&gpio_sync_in_b);
|
||||
|
||||
//gpio_output(&gpio_sync_out_a);
|
||||
//gpio_output(&gpio_sync_out_b);
|
||||
#endif
|
||||
|
||||
#ifdef RAD1O
|
||||
@ -841,11 +833,6 @@ void pin_setup(void) {
|
||||
scu_pinmux(SCU_PINMUX_GPIO3_10, SCU_GPIO_PDN | SCU_CONF_FUNCTION0);
|
||||
scu_pinmux(SCU_PINMUX_GPIO3_11, SCU_GPIO_PDN | SCU_CONF_FUNCTION0);
|
||||
|
||||
//gpio_input(&gpio_sync_in_a);
|
||||
//gpio_input(&gpio_sync_in_b);
|
||||
|
||||
//gpio_output(&gpio_sync_out_a);
|
||||
//gpio_output(&gpio_sync_out_b);
|
||||
#endif
|
||||
|
||||
/* enable input on SCL and SDA pins */
|
||||
@ -902,3 +889,7 @@ void led_off(const led_t led) {
|
||||
void led_toggle(const led_t led) {
|
||||
gpio_toggle(&gpio_led[led]);
|
||||
}
|
||||
|
||||
void hw_sync_enable(const hw_sync_mode_t hw_sync_mode){
|
||||
gpio_write(&gpio_hw_sync_enable, hw_sync_mode==1);
|
||||
}
|
||||
|
@ -293,11 +293,7 @@ void led_on(const led_t led);
|
||||
void led_off(const led_t led);
|
||||
void led_toggle(const led_t led);
|
||||
|
||||
void hw_sync_syn();
|
||||
void hw_sync_stop();
|
||||
void hw_sync_ack();
|
||||
bool hw_sync_ready();
|
||||
void hw_sync_copy_state();
|
||||
void hw_sync_enable(const hw_sync_mode_t hw_sync_mode);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -49,13 +49,11 @@ void sgpio_configure_pin_functions(sgpio_config_t* const config) {
|
||||
scu_pinmux(SCU_PINMUX_SGPIO14, SCU_GPIO_FAST | SCU_CONF_FUNCTION4); /* GPIO5[13] */
|
||||
scu_pinmux(SCU_PINMUX_SGPIO15, SCU_GPIO_FAST | SCU_CONF_FUNCTION4); /* GPIO5[14] */
|
||||
|
||||
sgpio_cpld_stream_rx_set_decimation(config, 1);
|
||||
sgpio_cpld_stream_rx_set_q_invert(config, 0);
|
||||
hw_sync_enable(0);
|
||||
|
||||
gpio_output(config->gpio_rx_q_invert);
|
||||
gpio_output(config->gpio_rx_decimation[0]);
|
||||
gpio_output(config->gpio_rx_decimation[1]);
|
||||
gpio_output(config->gpio_rx_decimation[2]);
|
||||
gpio_output(config->gpio_hw_sync_enable);
|
||||
}
|
||||
|
||||
void sgpio_set_slice_mode(
|
||||
@ -258,21 +256,6 @@ bool sgpio_cpld_stream_is_enabled(sgpio_config_t* const config) {
|
||||
return (SGPIO_GPIO_OUTREG & (1L << 10)) == 0; /* SGPIO10 */
|
||||
}
|
||||
|
||||
bool sgpio_cpld_stream_rx_set_decimation(sgpio_config_t* const config, const uint_fast8_t n) {
|
||||
/* CPLD interface is three bits, SGPIO[15:13]:
|
||||
* 111: decimate by 1 (skip_n=0, skip no samples)
|
||||
* 110: decimate by 2 (skip_n=1, skip every other sample)
|
||||
* 101: decimate by 3 (skip_n=2, skip two of three samples)
|
||||
* ...
|
||||
* 000: decimate by 8 (skip_n=7, skip seven of eight samples)
|
||||
*/
|
||||
const uint_fast8_t skip_n = n - 1;
|
||||
gpio_write(config->gpio_rx_decimation[0], (skip_n & 1) == 0);
|
||||
gpio_write(config->gpio_rx_decimation[1], (skip_n & 2) == 0);
|
||||
gpio_write(config->gpio_rx_decimation[2], (skip_n & 4) == 0);
|
||||
|
||||
return (skip_n < 8);
|
||||
}
|
||||
|
||||
#ifdef RAD1O
|
||||
/* The rad1o hardware has a bug which makes it
|
||||
|
@ -36,7 +36,7 @@ typedef enum {
|
||||
|
||||
typedef struct sgpio_config_t {
|
||||
gpio_t gpio_rx_q_invert;
|
||||
gpio_t gpio_rx_decimation[3];
|
||||
gpio_t gpio_hw_sync_enable;
|
||||
bool slice_mode_multislice;
|
||||
} sgpio_config_t;
|
||||
|
||||
|
@ -4,18 +4,6 @@ RF codec.
|
||||
CPLD-based triggered capture
|
||||
============================
|
||||
|
||||
Code related to the paper:
|
||||
|
||||
[M. Bartolucci, J. A. del Peral-Rosado, R. Estatuet-Castillo, J. A. Garcia-Molina, M. Crisci, G. E. Corazza, "Synchronisation of low-cost open source SDRs for navigation applications", Proc. 8th ESA Workshop on Satellite Navigation User Equipment Technologies (NAVITEC), Dec 16 2016](http://spcomnav.uab.es/docs/conferences/Bartolucci_NAVITEC_2016.pdf)
|
||||
|
||||
Please read the paper for hardware correction and additional details.
|
||||
|
||||
* If you don't want to build use `default_sync.xsvf` to flash the CPLD
|
||||
* This is still a very rough implementation. Synchronization can't be disabled!
|
||||
|
||||
Requirements
|
||||
============
|
||||
|
||||
To build this VHDL project and produce an SVF file for flashing the CPLD:
|
||||
|
||||
* Xilinx WebPACK 13.4 for Windows or Linux.
|
||||
|
BIN
firmware/cpld/sgpio_if/default.xsvf
Normal file → Executable file
BIN
firmware/cpld/sgpio_if/default.xsvf
Normal file → Executable file
Binary file not shown.
Binary file not shown.
@ -1,5 +1,5 @@
|
||||
Programmer Jedec Bit Map
|
||||
Date Extracted: Mon May 15 12:52:29 2017
|
||||
Date Extracted: Mon May 15 14:19:25 2017
|
||||
|
||||
QF25812*
|
||||
QP100*
|
||||
@ -368,7 +368,7 @@ L012869 000101111001111101000000011*
|
||||
|
||||
Note Block 2 *
|
||||
Note Block 2 ZIA *
|
||||
L012896 1111111111111111*
|
||||
L012896 1111111011100111*
|
||||
L012912 1111111111111111*
|
||||
L012928 1111111011110011*
|
||||
L012944 1111111111111111*
|
||||
@ -410,17 +410,17 @@ L013504 1111111111111111*
|
||||
L013520 1111111111111111*
|
||||
|
||||
Note Block 2 PLA AND array *
|
||||
L013536 11110111110111011111111111111111111111111111111111111111111111111011111111111111*
|
||||
L013616 11111011111011011111111111111111111111111111111111111111111111111011111111111111*
|
||||
L013696 11110111111011111111111111110111111111111111111111111111111111111111111111111111*
|
||||
L013776 11111011110111111111111111110111111111111111111111111111111111111111111111111111*
|
||||
L013856 11111011111111111111111111111111111110111111111111111111111111111111111111111111*
|
||||
L013936 11111011111111111111111101111111111110111111111111111111111111111111111111111111*
|
||||
L014016 11111111111111111111111110111111111101111111111111111111111111111111111111111111*
|
||||
L013536 10110111110111111111111111111111111111111111111111111111111111111011111111111111*
|
||||
L013616 10111011111011111111111111111111111111111111111111111111111111111011111111111111*
|
||||
L013696 11110111110111011111111111111111111111111111111111111111111111111011111111111111*
|
||||
L013776 11111011111011011111111111111111111111111111111111111111111111111011111111111111*
|
||||
L013856 11110111111011111111111111110111111111111111111111111111111111111111111111111111*
|
||||
L013936 11111011110111111111111111110111111111111111111111111111111111111111111111111111*
|
||||
L014016 11111011111111111111111111111111111110111111111111111111111111111111111111111111*
|
||||
L014096 11111111111011111111111111111111111111111111111111111111111111111111111111111111*
|
||||
L014176 11110111111111111111111110111111111111111111111111111111111111111111111111111111*
|
||||
L014256 11111111111111111111111111111111111111111111111111111111111111111111111111111111*
|
||||
L014336 11111111111111111111111111111111111111111111111111111111111111111111111111111111*
|
||||
L014176 11111011111111111111111101111111111110111111111111111111111111111111111111111111*
|
||||
L014256 11111111111111111111111110111111111101111111111111111111111111111111111111111111*
|
||||
L014336 11110111111111111111111110111111111111111111111111111111111111111111111111111111*
|
||||
L014416 11111111111111111111111111111111111111111111111111111111111111111111111111111111*
|
||||
L014496 11111111111111111111111111111111111111111111111111111111111111111111111111111111*
|
||||
L014576 11111111111111111111111111111111111111111111111111111111111111111111111111111111*
|
||||
@ -472,13 +472,13 @@ L018016 0111111111111111*
|
||||
L018032 0111111111111111*
|
||||
L018048 0111111111111111*
|
||||
L018064 0111111111111111*
|
||||
L018080 1101011100111000*
|
||||
L018096 1111110111111111*
|
||||
L018112 1111110111111111*
|
||||
L018080 0111111111111111*
|
||||
L018096 0111111111111111*
|
||||
L018112 1101011100111000*
|
||||
L018128 1111111111111111*
|
||||
L018144 1111110111111111*
|
||||
L018160 1111111111111111*
|
||||
L018176 1111111111111111*
|
||||
L018160 1111110111111111*
|
||||
L018176 1111110111111111*
|
||||
L018192 1111111111111111*
|
||||
L018208 1111111111111111*
|
||||
L018224 1111111111111111*
|
||||
@ -528,7 +528,7 @@ L018896 1111111111111111*
|
||||
Note Block 2 I/O Macrocell Configuration 27 bits *
|
||||
N Aclk ClkOp Clk:2 ClkFreq R:2 P:2 RegMod:2 INz:2 FB:2 InReg St XorIn:2 RegCom Oe:4 Tm Slw Pu*
|
||||
L018912 000101111001110100000000011*
|
||||
L018939 000001111001111110011111100*
|
||||
L018939 000001111000011100011111100*
|
||||
L018966 000101111000011101001000111*
|
||||
L018993 000001111001111110011111100*
|
||||
L019020 000101111000011101001000111*
|
||||
@ -753,5 +753,5 @@ L025810 0*
|
||||
Note I/O Bank 1 Vcco *
|
||||
L025811 0*
|
||||
|
||||
C0C4E*
|
||||
AACE
|
||||
C0AA8*
|
||||
AABC
|
||||
|
@ -60,7 +60,8 @@ NET "HOST_DATA<6>" LOC = "P61" | IOSTANDARD = LVCMOS33 | SLEW = SLOW ;
|
||||
NET "HOST_DATA<7>" LOC = "P77" | IOSTANDARD = LVCMOS33 | SLEW = SLOW ;
|
||||
NET "HOST_DIRECTION" LOC = "P71" | IOSTANDARD = LVCMOS33 ;
|
||||
NET "HOST_DISABLE" LOC = "P76" | IOSTANDARD = LVCMOS33 ;
|
||||
NET "HOST_Q_INVERT" LOC = "P70" | IOSTANDARD = LVCMOS33 ;
|
||||
NET "HOST_Q_INVERT" LOC = "P70" | IOSTANDARD = LVCMOS33 ;
|
||||
NET "HOST_SYNC_EN" LOC = "P90" | IOSTANDARD = LVCMOS33 ;
|
||||
NET "HOST_SYNC" LOC = "P55" | IOSTANDARD = LVCMOS33;
|
||||
NET "HOST_SYNC_CMD" LOC = "P56" | IOSTANDARD = LVCMOS33 | SLEW = SLOW ;
|
||||
|
||||
|
@ -29,7 +29,8 @@ use UNISIM.vcomponents.all;
|
||||
entity top is
|
||||
Port(
|
||||
HOST_DATA : inout std_logic_vector(7 downto 0);
|
||||
HOST_CAPTURE : out std_logic;
|
||||
HOST_CAPTURE : out std_logic;
|
||||
HOST_SYNC_EN : in std_logic;
|
||||
HOST_SYNC_CMD : out std_logic;
|
||||
HOST_SYNC : in std_logic;
|
||||
HOST_DISABLE : in std_logic;
|
||||
@ -56,7 +57,8 @@ architecture Behavioral of top is
|
||||
signal transfer_direction_i : transfer_direction;
|
||||
|
||||
signal host_data_enable_i : std_logic;
|
||||
signal host_data_capture_o : std_logic;
|
||||
signal host_data_capture_o : std_logic;
|
||||
signal host_sync_enable : std_logic := '0';
|
||||
signal host_sync_o : std_logic := '0';
|
||||
signal host_sync_i : std_logic := '0';
|
||||
signal host_sync_latched : std_logic := '0';
|
||||
@ -94,7 +96,8 @@ begin
|
||||
else (others => 'Z');
|
||||
data_from_host_i <= HOST_DATA;
|
||||
|
||||
HOST_CAPTURE <= host_data_capture_o;
|
||||
HOST_CAPTURE <= host_data_capture_o;
|
||||
host_sync_enable <= HOST_SYNC_EN;
|
||||
host_sync_i <= HOST_SYNC;
|
||||
HOST_SYNC_CMD <= host_sync_o;
|
||||
|
||||
@ -153,11 +156,11 @@ begin
|
||||
if rising_edge(host_clk_i) then
|
||||
if transfer_direction_i = to_dac then
|
||||
if codec_clk_i = '1' then
|
||||
host_data_capture_o <= host_data_enable_i and host_sync_latched;
|
||||
host_data_capture_o <= host_data_enable_i and (host_sync_latched or not host_sync_enable);
|
||||
end if;
|
||||
else
|
||||
if codec_clk_i = '0' then
|
||||
host_data_capture_o <= host_data_enable_i and host_sync_latched;
|
||||
host_data_capture_o <= host_data_enable_i and (host_sync_latched or not host_sync_enable);
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
|
@ -275,9 +275,8 @@ void set_transceiver_mode(const transceiver_mode_t new_transceiver_mode) {
|
||||
if( _transceiver_mode != TRANSCEIVER_MODE_OFF ) {
|
||||
si5351c_activate_best_clock_source(&clock_gen);
|
||||
|
||||
if( _hw_sync_mode != HW_SYNC_MODE_OFF) {
|
||||
hw_sync_enable();
|
||||
}
|
||||
hw_sync_enable(_hw_sync_mode);
|
||||
|
||||
baseband_streaming_enable(&sgpio_config);
|
||||
}
|
||||
}
|
||||
|
@ -964,7 +964,7 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
|
||||
if(hw_sync) {
|
||||
fprintf(stderr, "call hackrf_set_hw_sync_mode(%d)\n", hw_sync);
|
||||
fprintf(stderr, "call hackrf_set_hw_sync_mode(%d)\n", hw_sync_enable);
|
||||
result = hackrf_set_hw_sync_mode(device, hw_sync_enable ? HW_SYNC_MODE_ON : HW_SYNC_MODE_OFF);
|
||||
if( result != HACKRF_SUCCESS ) {
|
||||
fprintf(stderr, "hackrf_set_hw_sync_mode() failed: %s (%d)\n", hackrf_error_name(result), result);
|
||||
|
Reference in New Issue
Block a user