src: use new libosmogsm and include/osmocom/[gsm|core] path to headers
[osmocom-bb.git] / src / target / firmware / layer1 / afc.c
1 /* AFC (Automatic Frequency Correction) Implementation */
2
3 /* (C) 2010 by Harald Welte <laforge@gnumonks.org>
4  *
5  * All Rights Reserved
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  */
22
23 #include <stdint.h>
24 #include <stdio.h>
25
26 #include <debug.h>
27 #include <osmocom/gsm/gsm_utils.h>
28
29 #include <layer1/afc.h>
30 #include <layer1/avg.h>
31 #include <calypso/dsp.h>
32
33 #define AFC_INITIAL_DAC_VALUE   -700
34
35 /* Over how many TDMA frames do we want to average? (this may change in dedicated mode) */
36 #define AFC_PERIOD              40
37 /* How many of our measurements have to be valid? */
38 #define AFC_MIN_MUN_VALID       8
39
40 /* The actual AFC code */
41
42 struct afc_state {
43         struct running_avg ravg;                /* running average */
44         int16_t         dac_value;              /* current DAC output value */
45         uint16_t        arfcn;
46 };
47
48 static void afc_ravg_output(struct running_avg *ravg, int32_t avg);
49
50 static struct afc_state afc_state = {
51         .ravg = {
52                 .outfn = &afc_ravg_output,
53                 .period = AFC_PERIOD,
54                 .min_valid = AFC_MIN_MUN_VALID,
55         },
56         .dac_value = AFC_INITIAL_DAC_VALUE,
57 };
58
59 /* The AFC DAC in the ABB has to be configured as follows:
60  * DAC = 1MHz / 947MHz * FreqErr(Hz) / AFCslop(ppm/LSB)
61  * where:
62  *      947 MHz is the center of EGSM
63  *      AFCslope is coded F1.15, thus a normalization factor of 2^15 applies
64  */
65
66 #define AFC_NORM_FACTOR_GSM     ((1<<15) / 947)
67 #define AFC_NORM_FACTOR_DCS     ((1<<15) / 1894)
68
69 /* we assume 8.769ppb per LSB, equals 0.008769 * 32768 == 287 */
70 //#define AFC_SLOPE             320
71 #define AFC_SLOPE               287
72
73 /* The DSP can measure the frequency error in the following ranges:
74  *      FB_MODE0:       +/- 20 kHz
75  *      FB_MODE1:       +/-  4 kHz
76  *      Sync Burst:     +/-  1 kHz
77  *      Normal Burst:   +/- 400 Hz
78  */
79
80 /* Update the AFC with a frequency error, bypassing averaging */
81 void afc_correct(int16_t freq_error, uint16_t arfcn)
82 {
83         int32_t afc_norm_factor;
84         int16_t delta;
85
86         switch (gsm_arfcn2band(arfcn)) {
87         case GSM_BAND_900:
88         case GSM_BAND_850:
89                 afc_norm_factor = AFC_NORM_FACTOR_GSM;
90                 break;
91         default:
92                 afc_norm_factor = AFC_NORM_FACTOR_DCS;
93         }
94
95         delta = (int16_t) ((afc_norm_factor * (int32_t)freq_error) / AFC_SLOPE);
96         printd("afc_correct(error=%dHz, arfcn=%u): delta=%d, afc_dac(old=%d,new=%d)\n",
97                 freq_error, arfcn, delta, afc_state.dac_value, afc_state.dac_value+delta);
98         afc_state.dac_value += delta;
99
100         /* The AFC DAC has only 13 bits */
101         if (afc_state.dac_value > 4095)
102                 afc_state.dac_value = 4095;
103         else if (afc_state.dac_value < -4096)
104                 afc_state.dac_value = -4096;
105 }
106
107 void afc_reset(void)
108 {
109         afc_state.dac_value = AFC_INITIAL_DAC_VALUE;
110 }
111
112 void afc_input(int32_t freq_error, uint16_t arfcn, int valid)
113 {
114         afc_state.arfcn = arfcn;
115         runavg_input(&afc_state.ravg, freq_error, valid);
116         runavg_check_output(&afc_state.ravg);
117 }
118
119 /* callback function for runavg */
120 static void afc_ravg_output(struct running_avg *ravg, int32_t avg)
121 {
122         afc_correct(avg, afc_state.arfcn);
123 }
124
125 /* Update DSP with new AFC DAC value to be used for next TDMA frame */
126 void afc_load_dsp(void)
127 {
128         dsp_api.db_w->d_afc = afc_state.dac_value;
129         dsp_api.db_w->d_ctrl_abb |= (1 << B_AFC);
130 }