From faba9ac2446b437aaa42d465936c147da1bd93ca Mon Sep 17 00:00:00 2001 From: Florian Kaltenberger <florian.kaltenberger@eurecom.fr> Date: Fri, 22 Apr 2022 17:08:00 +0200 Subject: [PATCH] Make USRP GPIO control more flexible - adding support for x410 GPIO --- executables/nr-ru.c | 29 ++++----- maketags | 2 +- radio/COMMON/common_lib.h | 2 +- radio/USRP/USERSPACE/LIB/usrp_lib.cpp | 87 +++++++++++++++------------ 4 files changed, 65 insertions(+), 55 deletions(-) diff --git a/executables/nr-ru.c b/executables/nr-ru.c index 96ec7e27593..3d9b581a63e 100644 --- a/executables/nr-ru.c +++ b/executables/nr-ru.c @@ -733,7 +733,7 @@ void tx_rf(RU_t *ru,int frame,int slot, uint64_t timestamp) { T_INT(0), T_BUFFER(&ru->common.txdata[0][fp->get_samples_slot_timestamp(slot,fp,0)], fp->samples_per_subframe * 4)); int sf_extension = 0; int siglen=fp->get_samples_per_slot(slot,fp); - int flags = 0; + int flags=0,flags_burst=0,flags_gpio=0; if (cfg->cell_config.frame_duplex_type.value == TDD && !get_softmodem_params()->continuous_tx) { int slot_type = nr_slot_select(cfg,frame,slot%fp->slots_per_frame); @@ -760,39 +760,37 @@ void tx_rf(RU_t *ru,int frame,int slot, uint64_t timestamp) { } //+ ru->end_of_burst_delay; - flags = 3; // end of burst + flags_burst = 3; // end of burst } else if (slot_type == NR_DOWNLINK_SLOT) { int prevslot_type = nr_slot_select(cfg,frame,(slot+(fp->slots_per_frame-1))%fp->slots_per_frame); int nextslot_type = nr_slot_select(cfg,frame,(slot+1)%fp->slots_per_frame); if (prevslot_type == NR_UPLINK_SLOT) { - flags = 2; // start of burst + flags_burst = 2; // start of burst sf_extension = ru->sf_extension; } else if (nextslot_type == NR_UPLINK_SLOT) { - flags = 3; // end of burst + flags_burst = 3; // end of burst } else { - flags = 1; // middle of burst + flags_burst = 1; // middle of burst } } } else { // FDD if (proc->first_tx == 1) { - flags = 2; // start of burst + flags_burst = 2; // start of burst } else { - flags = 1; // middle of burst + flags_burst = 1; // middle of burst } } - if (flags) { if (fp->freq_range==nr_FR2) { - // the beam index is written in bits 8-10 of the flags - // bit 11 enables the gpio programming // currently we switch beams every 10 slots (should = 1 TDD period in FR2) and we take the beam index of the first symbol of the first slot of this period int beam=0; if (slot%10==0) { if ( ru->common.beam_id && (ru->common.beam_id[0][slot*fp->symbols_per_slot] < 8)) { - beam = ru->common.beam_id[0][slot*fp->symbols_per_slot] | 8; + beam = ru->common.beam_id[0][slot*fp->symbols_per_slot]; } } + LOG_D(HW,"slot %d, beam %d\n",slot,ru->common.beam_id[0][slot*fp->symbols_per_slot]); /* if (slot==0 || slot==40) beam=0|8; @@ -800,9 +798,12 @@ void tx_rf(RU_t *ru,int frame,int slot, uint64_t timestamp) { if (slot==20 || slot==60) beam=2|8; if (slot==30 || slot==70) beam=3|8; */ - flags |= beam<<8; - LOG_D(HW,"slot %d, beam %d\n",slot,ru->common.beam_id[0][slot*fp->symbols_per_slot]); + + flags_gpio = beam & 0x1000; //enable change of gpio } + + flags = flags_burst | flags_gpio<<4; + if (proc->first_tx == 1) proc->first_tx = 0; VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_WRITE_FLAGS, flags ); @@ -825,7 +826,7 @@ void tx_rf(RU_t *ru,int frame,int slot, uint64_t timestamp) { (long long unsigned int)(timestamp+ru->ts_offset-ru->openair0_cfg.tx_sample_advance-sf_extension),frame,slot,proc->frame_tx_unwrap,slot, flags, siglen+sf_extension, txs,10*log10((double)signal_energy(txp[0],siglen+sf_extension))); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 0 ); //AssertFatal(txs == 0,"trx write function error %d\n", txs); - } + } // this is for RU with local RF unit diff --git a/maketags b/maketags index 5c7232320a0..87f445dd217 100755 --- a/maketags +++ b/maketags @@ -1,4 +1,4 @@ #!/bin/sh echo "building ctags for openair1 and openair2 ..." -ctags -e -R --exclude=openair1/DOCS/ --exclude=openair2/DOCS/ --exclude=openair1/SIMULATION/ --exclude=targets/DOCS/ --exclude=targets/PROJECTS/ openair1 openair2 openair3 targets cmake_targets common nfapi executables +ctags -e -R --exclude=openair1/DOCS/ --exclude=openair2/DOCS/ --exclude=openair1/SIMULATION/ --exclude=targets/DOCS/ --exclude=targets/PROJECTS/ openair1 openair2 openair3 targets cmake_targets common nfapi executables sdr diff --git a/radio/COMMON/common_lib.h b/radio/COMMON/common_lib.h index 3733914ef42..2db34949569 100644 --- a/radio/COMMON/common_lib.h +++ b/radio/COMMON/common_lib.h @@ -315,7 +315,7 @@ typedef struct { int cc; signed char first_packet; signed char last_packet; - int flags_msb; + int flags_gpio; } openair0_write_package_t; typedef struct { diff --git a/radio/USRP/USERSPACE/LIB/usrp_lib.cpp b/radio/USRP/USERSPACE/LIB/usrp_lib.cpp index 1f6fbd34b13..374411734c5 100644 --- a/radio/USRP/USERSPACE/LIB/usrp_lib.cpp +++ b/radio/USRP/USERSPACE/LIB/usrp_lib.cpp @@ -59,7 +59,6 @@ /** @addtogroup _USRP_PHY_RF_INTERFACE_ * @{ */ -int gpio789=0; extern int usrp_tx_thread; @@ -88,6 +87,9 @@ typedef struct { //! TX forward samples. We use usrp_time_offset to get this value int tx_forward_nsamps; //166 for 20Mhz + //! gpio bank to use + std::string gpio_bank; + // -------------------------------- // Debug and output control // -------------------------------- @@ -258,27 +260,41 @@ static int sync_to_gps(openair0_device *device) { return EXIT_SUCCESS; } +#define ATR_MASK 0x7f //pins controlled by ATR +#define ATR_RX 0x50 //data[4] and data[6] +#define ATR_XX 0x20 //data[5] +#define MAN_MASK ATR_MASK^0xFFF //manually controlled pins + /*! \brief Called to start the USRP transceiver. Return 0 if OK, < 0 if error @param device pointer to the device structure specific to the RF hardware target */ static int trx_usrp_start(openair0_device *device) { usrp_state_t *s = (usrp_state_t *)device->priv; - if (device->type != USRP_X400_DEV) { - // setup GPIO for TDD, GPIO(4) = ATR_RX - //set data direction register (DDR) to output - s->usrp->set_gpio_attr("FP0", "DDR", 0xfff, 0xfff); - //set lower 7 bits to be controlled automatically by ATR (the rest 5 bits are controlled manually) - s->usrp->set_gpio_attr("FP0", "CTRL", 0x7f,0xfff); - //set pins 4 (RX_TX_Switch) and 6 (Shutdown PA) to 1 when the radio is only receiving (ATR_RX) - s->usrp->set_gpio_attr("FP0", "ATR_RX", (1<<4)|(1<<6), 0x7f); - // set pin 5 (Shutdown LNA) to 1 when the radio is transmitting and receiveing (ATR_XX) - // (we use full duplex here, because our RX is on all the time - this might need to change later) - s->usrp->set_gpio_attr("FP0", "ATR_XX", (1<<5), 0x7f); - // set the output pins to 1 - s->usrp->set_gpio_attr("FP0", "OUT", 7<<7, 0xf80); - } + s->gpio_bank = "FP0"; //good for B210, X310 and N310 +#if UHD_VERSION>4000000 + if (device->type == USRP_X400_DEV) { + // Set every pin on GPIO0 to be controlled by DB0_RF0 + std::vector<std::string> sxx{12, "DB0_RF0"}; + s->gpio_bank = "GPIO0"; + s->usrp->set_gpio_src(s->gpio_bank, sxx); + } +#endif + + // setup GPIO for TDD, GPIO(4) = ATR_RX + //set data direction register (DDR) to output + s->usrp->set_gpio_attr(s->gpio_bank, "DDR", 0xfff, 0xfff); + //set bits to be controlled automatically by ATR + s->usrp->set_gpio_attr(s->gpio_bank, "CTRL", ATR_MASK, 0xfff); + //set bits to 1 when the radio is only receiving (ATR_RX) + s->usrp->set_gpio_attr(s->gpio_bank, "ATR_RX", ATR_RX, ATR_MASK); + // set bits to 1 when the radio is transmitting and receiveing (ATR_XX) + // (we use full duplex here, because our RX is on all the time - this might need to change later) + s->usrp->set_gpio_attr(s->gpio_bank, "ATR_XX", ATR_XX, ATR_MASK); + // set all other pins to manual + s->usrp->set_gpio_attr(s->gpio_bank, "OUT", MAN_MASK, 0xfff); + s->wait_for_first_pps = 1; s->rx_count = 0; s->tx_count = 0; @@ -373,8 +389,8 @@ static int trx_usrp_write(openair0_device *device, usrp_state_t *s = (usrp_state_t *)device->priv; int nsamps2; // aligned to upper 32 or 16 byte boundary - int flags_lsb = flags&0xff; - int flags_msb = (flags>>8)&0xff; + int flags_burst = flags&0xf; + int flags_gpio = (flags>>4)&0x1fff; //MSB to enable sending GPIO command, 12 LSB carry GPIO values int end; openair0_thread_t *write_thread = &device->write_thread; @@ -384,28 +400,28 @@ static int trx_usrp_write(openair0_device *device, bool first_packet_state=false,last_packet_state=false; - if (flags_lsb == 2) { // start of burst + if (flags_burst == 2) { // start of burst // s->tx_md.start_of_burst = true; // s->tx_md.end_of_burst = false; first_packet_state = true; last_packet_state = false; - } else if (flags_lsb == 3) { // end of burst + } else if (flags_burst == 3) { // end of burst //s->tx_md.start_of_burst = false; //s->tx_md.end_of_burst = true; first_packet_state = false; last_packet_state = true; - } else if (flags_lsb == 4) { // start and end + } else if (flags_burst == 4) { // start and end // s->tx_md.start_of_burst = true; // s->tx_md.end_of_burst = true; first_packet_state = true; last_packet_state = true; - } else if (flags_lsb==1) { // middle of burst + } else if (flags_burst==1) { // middle of burst // s->tx_md.start_of_burst = false; // s->tx_md.end_of_burst = false; first_packet_state = false; last_packet_state = false; } - else if (flags_lsb==10) { // fail safe mode + else if (flags_burst==10) { // fail safe mode // s->tx_md.has_time_spec = false; // s->tx_md.start_of_burst = false; // s->tx_md.end_of_burst = true; @@ -449,12 +465,11 @@ static int trx_usrp_write(openair0_device *device, s->tx_count++; VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_BEAM_SWITCHING_GPIO,1); - // bit 3 enables gpio (for backward compatibility) - if (flags_msb&8) { - // push GPIO bits 7-9 from flags_msb - int gpio789=(flags_msb&7)<<7; + // bit 13 enables gpio + if (flags_gpio&0x1000) { + // push GPIO bits s->usrp->set_command_time(s->tx_md.time_spec); - s->usrp->set_gpio_attr("FP0", "OUT", gpio789, 0x380); + s->usrp->set_gpio_attr(s->gpio_bank, "OUT", flags_gpio, MAN_MASK); s->usrp->clear_command_time(); } VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_BEAM_SWITCHING_GPIO,0); @@ -489,7 +504,7 @@ VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_BEAM_SWITCHI write_package[end].cc = cc; write_package[end].first_packet = first_packet_state; write_package[end].last_packet = last_packet_state; - write_package[end].flags_msb = flags_msb; + write_package[end].flags_gpio = flags_gpio; for (int i = 0; i < cc; i++) write_package[end].buff[i] = buff[i]; write_thread->count_write++; @@ -526,7 +541,7 @@ void *trx_usrp_write_thread(void * arg){ int cc; signed char first_packet; signed char last_packet; - int flags_msb; + int flags_gpio; while(1){ pthread_mutex_lock(&write_thread->mutex_write); @@ -544,7 +559,7 @@ void *trx_usrp_write_thread(void * arg){ cc = write_package[start].cc; first_packet = write_package[start].first_packet; last_packet = write_package[start].last_packet; - flags_msb = write_package[start].flags_msb; + flags_gpio = write_package[start].flags_gpio; write_thread->start = (write_thread->start + 1)% MAX_WRITE_THREAD_PACKAGE; write_thread->count_write--; pthread_mutex_unlock(&write_thread->mutex_write); @@ -589,11 +604,10 @@ void *trx_usrp_write_thread(void * arg){ s->tx_count++; // bit 3 enables gpio (for backward compatibility) - if (flags_msb&8) { - // push GPIO bits 7-9 from flags_msb - int gpio789=(flags_msb&7)<<7; + if (flags_gpio&0x1000) { + // push GPIO bits s->usrp->set_command_time(s->tx_md.time_spec); - s->usrp->set_gpio_attr("FP0", "OUT", gpio789, 0x380); + s->usrp->set_gpio_attr(s->gpio_bank, "OUT", flags_gpio, MAN_MASK); s->usrp->clear_command_time(); } @@ -740,11 +754,6 @@ static int trx_usrp_read(openair0_device *device, openair0_timestamp *ptimestamp s->rx_timestamp = s->rx_md.time_spec.to_ticks(s->sample_rate); *ptimestamp = s->rx_timestamp; - // push GPIO bits 7-9 from flags_msb - /*s->usrp->set_command_time(uhd::time_spec_t::from_ticks((s->rx_timestamp+(2*nsamps)),s->sample_rate)); - s->usrp->set_gpio_attr("FP0", "OUT", gpio789<<7, 0x380); - s->usrp->clear_command_time(); - gpio789 = (gpio789+1)&7;*/ recplay_state_t *recPlay=device->recplay_state; if ( recPlay != NULL) { // record mode -- GitLab