Transceiver52M: Add 64 MHz resampling option with B100

Move B100 to the resampling interface with default
clocking. This temporarily resolves undetermined
FPGA clocking issues. This also provides extensible
support for multiple clocking rates and resampling
ratios.

Signed-off-by: Thomas Tsou <tom@tsou.cc>
This commit is contained in:
Thomas Tsou 2013-10-14 23:56:51 -04:00
parent c064124429
commit fe269fe31d
6 changed files with 88 additions and 46 deletions

View File

@ -32,8 +32,9 @@
#include "config.h"
#endif
#define BXXX_CLK_RT 52e6
#define BXXX_BASE_RT GSMRATE
#define B2XX_CLK_RT 52e6
#define B2XX_BASE_RT GSMRATE
#define B100_BASE_RT 400000
#define USRP2_BASE_RT 390625
#define TX_AMPL 0.3
#define SAMPLE_BUF_SZ (1 << 20)
@ -66,10 +67,10 @@ struct uhd_dev_offset {
static struct uhd_dev_offset uhd_offsets[NUM_USRP_TYPES * 2] = {
{ USRP1, 1, 0.0 },
{ USRP1, 4, 0.0 },
{ USRP2, 1, 1.1815e-4 },
{ USRP2, 4, 7.7538e-5 },
{ B100, 1, 9.9692e-5 },
{ B100, 4, 6.5545e-5 },
{ USRP2, 1, 1.2184e-4 },
{ USRP2, 4, 8.0230e-5 },
{ B100, 1, 1.2104e-4 },
{ B100, 4, 7.9307e-5 },
{ B2XX, 1, 9.9692e-5 },
{ B2XX, 4, 6.9248e-5 },
{ UMTRX, 1, 9.9692e-5 },
@ -108,6 +109,7 @@ static double select_rate(uhd_dev_type type, int sps)
case USRP2:
return USRP2_BASE_RT * sps;
case B100:
return B100_BASE_RT * sps;
case B2XX:
case UMTRX:
return GSMRATE * sps;
@ -412,9 +414,9 @@ int uhd_device::set_rates(double tx_rate, double rx_rate)
double offset_limit = 1.0;
double tx_offset, rx_offset;
// B100/200 are the only device where we set FPGA clocking
if ((dev_type == B100) || (dev_type == B2XX)) {
if (set_master_clk(BXXX_CLK_RT) < 0)
// B2XX is the only device where we set FPGA clocking
if (dev_type == B2XX) {
if (set_master_clk(B2XX_CLK_RT) < 0)
return -1;
}
@ -580,8 +582,12 @@ int uhd_device::open(const std::string &args)
// Print configuration
LOG(INFO) << "\n" << usrp_dev->get_pp_string();
if (dev_type == USRP2)
return RESAMP;
switch (dev_type) {
case B100:
return RESAMP_64M;
case USRP2:
return RESAMP_100M;
}
return NORMAL;
}

View File

@ -34,7 +34,7 @@ class RadioDevice {
enum TxWindowType { TX_WINDOW_USRP1, TX_WINDOW_FIXED };
/* Radio interface types */
enum RadioInterfaceType { NORMAL, RESAMP };
enum RadioInterfaceType { NORMAL, RESAMP_64M, RESAMP_100M };
static RadioDevice *make(int sps, bool skipRx = false);

View File

@ -51,8 +51,11 @@ RadioInterface::~RadioInterface(void)
close();
}
bool RadioInterface::init()
bool RadioInterface::init(int type)
{
if (type != RadioDevice::NORMAL)
return false;
close();
sendBuffer = new signalVector(OUTCHUNK * 20);

View File

@ -21,9 +21,6 @@
#include "radioVector.h"
#include "radioClock.h"
/** samples per GSM symbol */
#define SAMPSPERSYM 4
static const unsigned gSlotLen = 148; ///< number of symbols per slot, not counting guard periods
/** class to interface the transceiver with the USRP */
@ -86,13 +83,13 @@ public:
void start();
/** intialization */
virtual bool init();
virtual bool init(int type);
virtual void close();
/** constructor */
RadioInterface(RadioDevice* wRadio = NULL,
int receiveOffset = 3,
int wSPS = SAMPSPERSYM,
int wSPS = 4,
GSM::Time wStartTime = GSM::Time(0));
/** destructor */
@ -172,11 +169,11 @@ public:
RadioInterfaceResamp(RadioDevice* wRadio = NULL,
int receiveOffset = 3,
int wSPS = SAMPSPERSYM,
int wSPS = 4,
GSM::Time wStartTime = GSM::Time(0));
~RadioInterfaceResamp();
bool init();
bool init(int type);
void close();
};

View File

@ -28,9 +28,13 @@ extern "C" {
#include "convert.h"
}
/* Resampling parameters for 64 MHz clocking */
#define RESAMP_64M_INRATE 65
#define RESAMP_64M_OUTRATE 96
/* Resampling parameters for 100 MHz clocking */
#define RESAMP_INRATE 52
#define RESAMP_OUTRATE 75
#define RESAMP_100M_INRATE 52
#define RESAMP_100M_OUTRATE 75
/*
* Resampling filter bandwidth scaling factor
@ -41,11 +45,13 @@ extern "C" {
*/
#define RESAMP_TX4_FILTER 0.45
#define INCHUNK (RESAMP_INRATE * 4)
#define OUTCHUNK (RESAMP_OUTRATE * 4)
static Resampler *upsampler = NULL;
static Resampler *dnsampler = NULL;
static int resamp_inrate = 0;
static int resamp_inchunk = 0;
static int resamp_outrate = 0;
static int resamp_outchunk = 0;
short *convertRecvBuffer = NULL;
short *convertSendBuffer = NULL;
@ -86,22 +92,40 @@ void RadioInterfaceResamp::close()
}
/* Initialize I/O specific objects */
bool RadioInterfaceResamp::init()
bool RadioInterfaceResamp::init(int type)
{
float cutoff = 1.0f;
close();
switch (type) {
case RadioDevice::RESAMP_64M:
resamp_inrate = RESAMP_64M_INRATE;
resamp_outrate = RESAMP_64M_OUTRATE;
break;
case RadioDevice::RESAMP_100M:
resamp_inrate = RESAMP_100M_INRATE;
resamp_outrate = RESAMP_100M_OUTRATE;
break;
case RadioDevice::NORMAL:
default:
LOG(ALERT) << "Invalid device configuration";
return false;
}
resamp_inchunk = resamp_inrate * 4;
resamp_outchunk = resamp_outrate * 4;
if (mSPSTx == 4)
cutoff = RESAMP_TX4_FILTER;
dnsampler = new Resampler(RESAMP_INRATE, RESAMP_OUTRATE);
dnsampler = new Resampler(resamp_inrate, resamp_outrate);
if (!dnsampler->init()) {
LOG(ALERT) << "Rx resampler failed to initialize";
return false;
}
upsampler = new Resampler(RESAMP_OUTRATE, RESAMP_INRATE);
upsampler = new Resampler(resamp_outrate, resamp_inrate);
if (!upsampler->init(cutoff)) {
LOG(ALERT) << "Tx resampler failed to initialize";
return false;
@ -113,14 +137,16 @@ bool RadioInterfaceResamp::init()
* and requires headroom equivalent to the filter length. Low
* rate buffers are allocated in the main radio interface code.
*/
innerSendBuffer = new signalVector(INCHUNK * 20, upsampler->len());
outerSendBuffer = new signalVector(OUTCHUNK * 20);
innerSendBuffer = new signalVector(resamp_inchunk * 20,
upsampler->len());
outerSendBuffer = new signalVector(resamp_outchunk * 20);
outerRecvBuffer = new signalVector(OUTCHUNK * 2, dnsampler->len());
innerRecvBuffer = new signalVector(INCHUNK * 20);
outerRecvBuffer = new signalVector(resamp_outchunk * 2,
dnsampler->len());
innerRecvBuffer = new signalVector(resamp_inchunk * 20);
convertSendBuffer = new short[OUTCHUNK * 2 * 20];
convertRecvBuffer = new short[OUTCHUNK * 2 * 2];
convertSendBuffer = new short[resamp_outchunk * 2 * 20];
convertRecvBuffer = new short[resamp_outchunk * 2 * 2];
sendBuffer = innerSendBuffer;
recvBuffer = innerRecvBuffer;
@ -133,8 +159,8 @@ void RadioInterfaceResamp::pullBuffer()
{
bool local_underrun;
int rc, num_recv;
int inner_len = INCHUNK;
int outer_len = OUTCHUNK;
int inner_len = resamp_inchunk;
int outer_len = resamp_outchunk;
/* Outer buffer access size is fixed */
num_recv = mRadio->readSamples(convertRecvBuffer,
@ -170,15 +196,15 @@ void RadioInterfaceResamp::pushBuffer()
int rc, chunks, num_sent;
int inner_len, outer_len;
if (sendCursor < INCHUNK)
if (sendCursor < resamp_inchunk)
return;
chunks = sendCursor / INCHUNK;
chunks = sendCursor / resamp_inchunk;
if (chunks > 8)
chunks = 8;
inner_len = chunks * INCHUNK;
outer_len = chunks * OUTCHUNK;
inner_len = chunks * resamp_inchunk;
outer_len = chunks * resamp_outchunk;
/* Always send from the beginning of the buffer */
rc = upsampler->rotate((float *) innerSendBuffer->begin(), inner_len,

View File

@ -38,6 +38,15 @@
#define CONFIGDB "/etc/OpenBTS/OpenBTS.db"
/* Samples-per-symbol for downlink path
* 4 - Uses precision modulator (more computation, less distortion)
* 1 - Uses minimized modulator (less computation, more distortion)
*
* Other values are invalid. Receive path (uplink) is always
* downsampled to 1 sps
*/
#define SPS 4
using namespace std;
ConfigurationTable gConfig(CONFIGDB);
@ -138,7 +147,7 @@ int main(int argc, char *argv[])
srandom(time(NULL));
RadioDevice *usrp = RadioDevice::make(SAMPSPERSYM);
RadioDevice *usrp = RadioDevice::make(SPS);
int radioType = usrp->open(deviceArgs);
if (radioType < 0) {
LOG(ALERT) << "Transceiver exiting..." << std::endl;
@ -148,21 +157,22 @@ int main(int argc, char *argv[])
RadioInterface* radio;
switch (radioType) {
case RadioDevice::NORMAL:
radio = new RadioInterface(usrp, 3, SAMPSPERSYM, false);
radio = new RadioInterface(usrp, 3, SPS, false);
break;
case RadioDevice::RESAMP:
radio = new RadioInterfaceResamp(usrp, 3, SAMPSPERSYM, false);
case RadioDevice::RESAMP_64M:
case RadioDevice::RESAMP_100M:
radio = new RadioInterfaceResamp(usrp, 3, SPS, false);
break;
default:
LOG(ALERT) << "Unsupported configuration";
return EXIT_FAILURE;
}
if (!radio->init()) {
if (!radio->init(radioType)) {
LOG(ALERT) << "Failed to initialize radio interface";
}
Transceiver *trx = new Transceiver(trxPort, trxAddr.c_str(),
SAMPSPERSYM, GSM::Time(3,0), radio);
SPS, GSM::Time(3,0), radio);
if (!trx->init()) {
LOG(ALERT) << "Failed to initialize transceiver";
}