From 8abd9a968f1aaea16239b1de7d627fb54160257f Mon Sep 17 00:00:00 2001 From: Tom Date: Fri, 17 Jun 2011 18:21:43 +0200 Subject: Initial Commit --- Src/osmocom-bb/src/target/firmware/layer1/afc.c | 130 ++++++++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 Src/osmocom-bb/src/target/firmware/layer1/afc.c (limited to 'Src/osmocom-bb/src/target/firmware/layer1/afc.c') diff --git a/Src/osmocom-bb/src/target/firmware/layer1/afc.c b/Src/osmocom-bb/src/target/firmware/layer1/afc.c new file mode 100644 index 0000000..a51a107 --- /dev/null +++ b/Src/osmocom-bb/src/target/firmware/layer1/afc.c @@ -0,0 +1,130 @@ +/* AFC (Automatic Frequency Correction) Implementation */ + +/* (C) 2010 by Harald Welte + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include +#include + +#include +#include + +#include +#include +#include + +#define AFC_INITIAL_DAC_VALUE -700 + +/* Over how many TDMA frames do we want to average? (this may change in dedicated mode) */ +#define AFC_PERIOD 40 +/* How many of our measurements have to be valid? */ +#define AFC_MIN_MUN_VALID 8 + +/* The actual AFC code */ + +struct afc_state { + struct running_avg ravg; /* running average */ + int16_t dac_value; /* current DAC output value */ + uint16_t arfcn; +}; + +static void afc_ravg_output(struct running_avg *ravg, int32_t avg); + +static struct afc_state afc_state = { + .ravg = { + .outfn = &afc_ravg_output, + .period = AFC_PERIOD, + .min_valid = AFC_MIN_MUN_VALID, + }, + .dac_value = AFC_INITIAL_DAC_VALUE, +}; + +/* The AFC DAC in the ABB has to be configured as follows: + * DAC = 1MHz / 947MHz * FreqErr(Hz) / AFCslop(ppm/LSB) + * where: + * 947 MHz is the center of EGSM + * AFCslope is coded F1.15, thus a normalization factor of 2^15 applies + */ + +#define AFC_NORM_FACTOR_GSM ((1<<15) / 947) +#define AFC_NORM_FACTOR_DCS ((1<<15) / 1894) + +/* we assume 8.769ppb per LSB, equals 0.008769 * 32768 == 287 */ +//#define AFC_SLOPE 320 +#define AFC_SLOPE 287 + +/* The DSP can measure the frequency error in the following ranges: + * FB_MODE0: +/- 20 kHz + * FB_MODE1: +/- 4 kHz + * Sync Burst: +/- 1 kHz + * Normal Burst: +/- 400 Hz + */ + +/* Update the AFC with a frequency error, bypassing averaging */ +void afc_correct(int16_t freq_error, uint16_t arfcn) +{ + int32_t afc_norm_factor; + int16_t delta; + + switch (gsm_arfcn2band(arfcn)) { + case GSM_BAND_900: + case GSM_BAND_850: + afc_norm_factor = AFC_NORM_FACTOR_GSM; + break; + default: + afc_norm_factor = AFC_NORM_FACTOR_DCS; + } + + delta = (int16_t) ((afc_norm_factor * (int32_t)freq_error) / AFC_SLOPE); + printd("afc_correct(error=%dHz, arfcn=%u): delta=%d, afc_dac(old=%d,new=%d)\n", + freq_error, arfcn, delta, afc_state.dac_value, afc_state.dac_value+delta); + afc_state.dac_value += delta; + + /* The AFC DAC has only 13 bits */ + if (afc_state.dac_value > 4095) + afc_state.dac_value = 4095; + else if (afc_state.dac_value < -4096) + afc_state.dac_value = -4096; +} + +void afc_reset(void) +{ + afc_state.dac_value = AFC_INITIAL_DAC_VALUE; +} + +void afc_input(int32_t freq_error, uint16_t arfcn, int valid) +{ + afc_state.arfcn = arfcn; + runavg_input(&afc_state.ravg, freq_error, valid); + runavg_check_output(&afc_state.ravg); +} + +/* callback function for runavg */ +static void afc_ravg_output(struct running_avg *ravg, int32_t avg) +{ + afc_correct(avg, afc_state.arfcn); +} + +/* Update DSP with new AFC DAC value to be used for next TDMA frame */ +void afc_load_dsp(void) +{ + dsp_api.db_w->d_afc = afc_state.dac_value; + dsp_api.db_w->d_ctrl_abb |= (1 << B_AFC); +} -- cgit v1.2.3-55-g7522