Commit 051fb056 authored by Robert Schmidt's avatar Robert Schmidt

Merge remote-tracking branch 'origin/fr2-interdigital-usrp-interface' into integration_2023_w30

parents 9bc00465 76ccc2f5
...@@ -726,6 +726,49 @@ void rx_rf(RU_t *ru,int *frame,int *slot) { ...@@ -726,6 +726,49 @@ void rx_rf(RU_t *ru,int *frame,int *slot) {
stop_meas(&ru->rx_fhaul); stop_meas(&ru->rx_fhaul);
} }
static radio_tx_gpio_flag_t get_gpio_flags(RU_t *ru, int slot)
{
radio_tx_gpio_flag_t flags_gpio = 0;
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
openair0_config_t *cfg0 = &ru->openair0_cfg;
switch (cfg0->gpio_controller) {
case RU_GPIO_CONTROL_GENERIC:
// currently we switch beams at the beginning of a slot and we take the beam index of the first symbol of this slot
// we only send the beam to the gpio if the beam is different from the previous slot
if (ru->common.beam_id) {
int prev_slot = (slot - 1 + fp->slots_per_frame) % fp->slots_per_frame;
const uint8_t *beam_ids = ru->common.beam_id[0];
int prev_beam = beam_ids[prev_slot * fp->symbols_per_slot];
int beam = beam_ids[slot * fp->symbols_per_slot];
if (prev_beam != beam) {
flags_gpio = beam | TX_GPIO_CHANGE; // enable change of gpio
LOG_I(HW, "slot %d, beam %d\n", slot, ru->common.beam_id[0][slot * fp->symbols_per_slot]);
}
}
break;
case RU_GPIO_CONTROL_INTERDIGITAL: {
// the beam index is written in bits 8-10 of the flags
// bit 11 enables the gpio programming
int beam = 0;
if ((slot % 10 == 0) && ru->common.beam_id && (ru->common.beam_id[0][slot * fp->symbols_per_slot] < 64)) {
// beam = ru->common.beam_id[0][slot*fp->symbols_per_slot] | 64;
beam = 1024; // hardcoded now for beam32 boresight
// beam = 127; //for the sake of trying beam63
LOG_D(HW, "slot %d, beam %d\n", slot, beam);
}
flags_gpio = beam | TX_GPIO_CHANGE;
// flags_gpio |= beam << 8; // MSB 8 bits are used for beam
LOG_I(HW, "slot %d, beam %d, flags_gpio %d\n", slot, beam, flags_gpio);
break;
}
default:
AssertFatal(false, "illegal GPIO controller %d\n", cfg0->gpio_controller);
}
return flags_gpio;
}
void tx_rf(RU_t *ru,int frame,int slot, uint64_t timestamp) { void tx_rf(RU_t *ru,int frame,int slot, uint64_t timestamp) {
RU_proc_t *proc = &ru->proc; RU_proc_t *proc = &ru->proc;
...@@ -783,47 +826,47 @@ void tx_rf(RU_t *ru,int frame,int slot, uint64_t timestamp) { ...@@ -783,47 +826,47 @@ void tx_rf(RU_t *ru,int frame,int slot, uint64_t timestamp) {
flags_burst = proc->first_tx == 1 ? TX_BURST_START : TX_BURST_MIDDLE; flags_burst = proc->first_tx == 1 ? TX_BURST_START : TX_BURST_MIDDLE;
} }
if (fp->freq_range==nr_FR2) { if (fp->freq_range == nr_FR2)
// currently we switch beams at the beginning of a slot and we take the beam index of the first symbol of this slot flags_gpio = get_gpio_flags(ru, slot);
// we only send the beam to the gpio if the beam is different from the previous slot
if ( ru->common.beam_id) {
int prev_slot = (slot - 1 + fp->slots_per_frame) % fp->slots_per_frame;
const uint8_t *beam_ids = ru->common.beam_id[0];
int prev_beam = beam_ids[prev_slot * fp->symbols_per_slot];
int beam = beam_ids[slot * fp->symbols_per_slot];
if (prev_beam != beam) {
flags_gpio = beam | TX_GPIO_CHANGE; // enable change of gpio
LOG_D(HW, "slot %d, beam %d\n", slot, ru->common.beam_id[0][slot * fp->symbols_per_slot]);
}
}
}
const int flags = flags_burst | flags_gpio << 4;
if (proc->first_tx == 1) proc->first_tx = 0; const int flags = flags_burst | (flags_gpio << 4);
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_WRITE_FLAGS, flags ); if (proc->first_tx == 1)
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_RU, frame ); proc->first_tx = 0;
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TTI_NUMBER_TX0_RU, slot );
for (i=0; i<ru->nb_tx; i++) VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_TRX_WRITE_FLAGS, flags);
txp[i] = (void *)&ru->common.txdata[i][fp->get_samples_slot_timestamp(slot,fp,0)]-sf_extension*sizeof(int32_t); VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_RU, frame);
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_TTI_NUMBER_TX0_RU, slot);
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, (timestamp+ru->ts_offset-ru->openair0_cfg.tx_sample_advance)&0xffffffff );
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 1 ); for (i = 0; i < ru->nb_tx; i++)
// prepare tx buffer pointers txp[i] = (void *)&ru->common.txdata[i][fp->get_samples_slot_timestamp(slot, fp, 0)] - sf_extension * sizeof(int32_t);
txs = ru->rfdevice.trx_write_func(&ru->rfdevice,
timestamp+ru->ts_offset-ru->openair0_cfg.tx_sample_advance-sf_extension, VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST,
txp, (timestamp + ru->ts_offset - ru->openair0_cfg.tx_sample_advance) & 0xffffffff);
siglen+sf_extension, VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 1);
ru->nb_tx, // prepare tx buffer pointers
flags); txs = ru->rfdevice.trx_write_func(&ru->rfdevice,
LOG_D(PHY,"[TXPATH] RU %d aa %d tx_rf, writing to TS %llu, %d.%d, unwrapped_frame %d, slot %d, flags %d, siglen+sf_extension %d, returned %d, E %f\n",ru->idx,i, timestamp + ru->ts_offset - ru->openair0_cfg.tx_sample_advance - sf_extension,
(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))); txp,
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 0 ); siglen + sf_extension,
//AssertFatal(txs == 0,"trx write function error %d\n", txs); ru->nb_tx,
flags);
LOG_D(PHY,
"[TXPATH] RU %d aa %d tx_rf, writing to TS %llu, %d.%d, unwrapped_frame %d, slot %d, flags %d, siglen+sf_extension %d, "
"returned %d, E %f\n",
ru->idx,
i,
(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 // this is for RU with local RF unit
...@@ -1881,6 +1924,23 @@ static void NRRCconfig_RU(void) ...@@ -1881,6 +1924,23 @@ static void NRRCconfig_RU(void)
RC.ru[j]->openair0_cfg.sdr_addrs = strdup(*(RUParamList.paramarray[j][RU_SDR_ADDRS].strptr)); RC.ru[j]->openair0_cfg.sdr_addrs = strdup(*(RUParamList.paramarray[j][RU_SDR_ADDRS].strptr));
} }
if (config_isparamset(RUParamList.paramarray[j], RU_GPIO_CONTROL)) {
if (strcmp(*RUParamList.paramarray[j][RU_GPIO_CONTROL].strptr, "generic") == 0) {
RC.ru[j]->openair0_cfg.gpio_controller = RU_GPIO_CONTROL_GENERIC;
LOG_I(PHY, "RU GPIO control set as 'generic'\n");
} else if (strcmp(*RUParamList.paramarray[j][RU_GPIO_CONTROL].strptr, "interdigital") == 0) {
RC.ru[j]->openair0_cfg.gpio_controller = RU_GPIO_CONTROL_INTERDIGITAL;
LOG_I(PHY, "RU GPIO control set as 'interdigital'\n");
} else {
AssertFatal(false,
"bad GPIO controller in configuration file: '%s'\n",
*(RUParamList.paramarray[j][RU_GPIO_CONTROL].strptr));
}
} else {
RC.ru[j]->openair0_cfg.gpio_controller = RU_GPIO_CONTROL_GENERIC;
LOG_I(PHY, "RU GPIO control set as 'generic'\n");
}
if (config_isparamset(RUParamList.paramarray[j], RU_TX_SUBDEV)) { if (config_isparamset(RUParamList.paramarray[j], RU_TX_SUBDEV)) {
RC.ru[j]->openair0_cfg.tx_subdev = strdup(*(RUParamList.paramarray[j][RU_TX_SUBDEV].strptr)); RC.ru[j]->openair0_cfg.tx_subdev = strdup(*(RUParamList.paramarray[j][RU_TX_SUBDEV].strptr));
LOG_I(PHY, "RU USRP tx subdev == %s\n", RC.ru[j]->openair0_cfg.tx_subdev); LOG_I(PHY, "RU USRP tx subdev == %s\n", RC.ru[j]->openair0_cfg.tx_subdev);
......
...@@ -112,6 +112,7 @@ typedef enum { ...@@ -112,6 +112,7 @@ typedef enum {
#define CONFIG_STRING_RU_NUM_INTERFACES "num_interfaces" #define CONFIG_STRING_RU_NUM_INTERFACES "num_interfaces"
#define CONFIG_STRING_RU_HALF_SLOT_PARALLELIZATION "half_slot_parallelization" #define CONFIG_STRING_RU_HALF_SLOT_PARALLELIZATION "half_slot_parallelization"
#define CONFIG_STRING_RU_RU_THREAD_CORE "ru_thread_core" #define CONFIG_STRING_RU_RU_THREAD_CORE "ru_thread_core"
#define CONFIG_STRING_RU_GPIO_CONTROL "gpio_controller"
#define HLP_RU_SF_AHEAD "LTE TX processing advance" #define HLP_RU_SF_AHEAD "LTE TX processing advance"
#define HLP_RU_SL_AHEAD "NR TX processing advance" #define HLP_RU_SL_AHEAD "NR TX processing advance"
...@@ -124,6 +125,7 @@ typedef enum { ...@@ -124,6 +125,7 @@ typedef enum {
#define HLP_RU_NUM_INTERFACES "Number of network interfaces for RU" #define HLP_RU_NUM_INTERFACES "Number of network interfaces for RU"
#define HLP_RU_HALF_SLOT_PARALLELIZATION "run half slots in parallel in RU FEP" #define HLP_RU_HALF_SLOT_PARALLELIZATION "run half slots in parallel in RU FEP"
#define HLP_RU_RU_THREAD_CORE "id of core to pin ru_thread, -1 is default" #define HLP_RU_RU_THREAD_CORE "id of core to pin ru_thread, -1 is default"
#define HLP_RU_GPIO_CONTROL "set the GPIO control type for the RU"
#define RU_LOCAL_IF_NAME_IDX 0 #define RU_LOCAL_IF_NAME_IDX 0
#define RU_LOCAL_ADDRESS_IDX 1 #define RU_LOCAL_ADDRESS_IDX 1
...@@ -167,6 +169,7 @@ typedef enum { ...@@ -167,6 +169,7 @@ typedef enum {
#define RU_NUM_INTERFACES 39 #define RU_NUM_INTERFACES 39
#define RU_HALF_SLOT_PARALLELIZATION 40 #define RU_HALF_SLOT_PARALLELIZATION 40
#define RU_RU_THREAD_CORE 41 #define RU_RU_THREAD_CORE 41
#define RU_GPIO_CONTROL 42
/*-----------------------------------------------------------------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------------------------------------------------------------*/
/* RU configuration parameters */ /* RU configuration parameters */
/* optname helpstr paramflags XXXptr defXXXval type numelt */ /* optname helpstr paramflags XXXptr defXXXval type numelt */
...@@ -215,6 +218,7 @@ typedef enum { ...@@ -215,6 +218,7 @@ typedef enum {
{CONFIG_STRING_RU_NUM_INTERFACES, HLP_RU_NUM_INTERFACES, 0, .uptr=NULL, .defintval=1, TYPE_UINT, 0}, \ {CONFIG_STRING_RU_NUM_INTERFACES, HLP_RU_NUM_INTERFACES, 0, .uptr=NULL, .defintval=1, TYPE_UINT, 0}, \
{CONFIG_STRING_RU_HALF_SLOT_PARALLELIZATION, HLP_RU_HALF_SLOT_PARALLELIZATION, 0, .uptr=NULL, .defintval=1, TYPE_UINT, 0}, \ {CONFIG_STRING_RU_HALF_SLOT_PARALLELIZATION, HLP_RU_HALF_SLOT_PARALLELIZATION, 0, .uptr=NULL, .defintval=1, TYPE_UINT, 0}, \
{CONFIG_STRING_RU_RU_THREAD_CORE, HLP_RU_RU_THREAD_CORE, 0, .uptr=NULL, .defintval=-1, TYPE_UINT, 0}, \ {CONFIG_STRING_RU_RU_THREAD_CORE, HLP_RU_RU_THREAD_CORE, 0, .uptr=NULL, .defintval=-1, TYPE_UINT, 0}, \
{CONFIG_STRING_RU_GPIO_CONTROL, HLP_RU_GPIO_CONTROL, 0, .strptr=NULL, .defstrval="generic", TYPE_STRING, 0}, \
} }
// clang-format on // clang-format on
......
...@@ -173,6 +173,10 @@ typedef struct { ...@@ -173,6 +173,10 @@ typedef struct {
notifiedFIFO_t *resp; notifiedFIFO_t *resp;
} udp_ctx_t; } udp_ctx_t;
typedef enum {
RU_GPIO_CONTROL_GENERIC,
RU_GPIO_CONTROL_INTERDIGITAL,
} gpio_control_t;
/*! \brief RF frontend parameters set by application */ /*! \brief RF frontend parameters set by application */
typedef struct { typedef struct {
...@@ -275,6 +279,8 @@ typedef struct { ...@@ -275,6 +279,8 @@ typedef struct {
int rxfh_cores[4]; int rxfh_cores[4];
//! Core IDs for TX FH //! Core IDs for TX FH
int txfh_cores[4]; int txfh_cores[4];
//! select the GPIO control method
gpio_control_t gpio_controller;
} openair0_config_t; } openair0_config_t;
/*! \brief RF mapping */ /*! \brief RF mapping */
......
...@@ -263,7 +263,42 @@ static int sync_to_gps(openair0_device *device) { ...@@ -263,7 +263,42 @@ static int sync_to_gps(openair0_device *device) {
#define ATR_MASK 0x7f //pins controlled by ATR #define ATR_MASK 0x7f //pins controlled by ATR
#define ATR_RX 0x50 //data[4] and data[6] #define ATR_RX 0x50 //data[4] and data[6]
#define ATR_XX 0x20 //data[5] #define ATR_XX 0x20 //data[5]
#define MAN_MASK ATR_MASK^0xFFF //manually controlled pins #define MAN_MASK ATR_MASK ^ 0xFFF // manually controlled pins
static void trx_usrp_start_interdigital_gpio(openair0_device *device, usrp_state_t *s)
{
AssertFatal(device->type == USRP_X400_DEV,
"interdigital frontend device for beam management can only be used together with an X400\n");
// s->gpio_bank="GPIO0";
std::vector<std::string> sxx{12, "DB0_RF0"};
// set every pin on GPIO0 to be ocntrolled by DB1_RF0
s->usrp->set_gpio_src(s->gpio_bank, sxx);
// set data direction register (DDR) to output
s->usrp->set_gpio_attr(s->gpio_bank, "DDR", 0xfff, 0xfff);
// set lower GPIO#1 to be controlled automatically by ATR (the rest bits are controlled manually)
s->usrp->set_gpio_attr(s->gpio_bank, "CTRL", (1 << 1), (1 << 1));
// set GPIO1 (Tx/Rx1) to 1 for MHU1 for transmistting
s->usrp->set_gpio_attr(s->gpio_bank, "ATR_XX", (1 << 1), (1 << 1));
// set GPIO4 (ID0) to 1 and GPIO2 (TX/RX2) &GPIO3 (ID1) to 0
s->usrp->set_gpio_attr(s->gpio_bank, "OUT", (1 << 4), 0x1c);
}
static void trx_usrp_start_generic_gpio(openair0_device *device, usrp_state_t *s)
{
// 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);
}
/*! \brief Called to start the USRP transceiver. Return 0 if OK, < 0 if error /*! \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 @param device pointer to the device structure specific to the RF hardware target
...@@ -280,21 +315,19 @@ static int trx_usrp_start(openair0_device *device) { ...@@ -280,21 +315,19 @@ static int trx_usrp_start(openair0_device *device) {
s->gpio_bank = (char *) "GPIO0"; s->gpio_bank = (char *) "GPIO0";
s->usrp->set_gpio_src(s->gpio_bank, sxx); s->usrp->set_gpio_src(s->gpio_bank, sxx);
} }
#endif #endif
switch (device->openair0_cfg->gpio_controller) {
case RU_GPIO_CONTROL_GENERIC:
trx_usrp_start_generic_gpio(device, s);
break;
case RU_GPIO_CONTROL_INTERDIGITAL:
trx_usrp_start_interdigital_gpio(device, s);
break;
default:
AssertFatal(false, "illegal GPIO controller %d\n", device->openair0_cfg->gpio_controller);
}
// 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->wait_for_first_pps = 1;
s->rx_count = 0; s->rx_count = 0;
s->tx_count = 0; s->tx_count = 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment