Root/tools/atrf-xtal/atben.c

Source at commit 1de233a7c7fb2eca6f61682805aec0dda195a307 created 6 years 8 months ago.
By Werner Almesberger, tools/: fix artf_at86rf23[01] (should be atrf...) typo
1/*
2 * atrf-xtal/atben.c - ATBEN-specific driver and evaluation
3 *
4 * Written 2011, 2013 by Werner Almesberger
5 * Copyright 2011, 2013 Werner Almesberger
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
13/*
14 * WARNING: this program does very nasty things to the Ben and it doesn't
15 * like company. In particular, it resents:
16 *
17 * - the MMC driver - disable it with
18 * echo jz4740-mmc.0 >/sys/bus/platform/drivers/jz4740-mmc/unbind
19 * - the AT86RF230/1 kernel driver - either use a kernel that doesn't have
20 * it or disable it with
21 * echo spi2.0 >/sys/bus/spi/drivers/at86rf230/unbind
22 * - anything that accesses the screen - kill GUI, X server, etc.
23 * - the screen blanker - either disable it or make sure the screen stays
24 * dark, e.g., with
25 * echo 1 >/sys/devices/platform/jz4740-fb/graphics/fb0/blank
26 * - probably a fair number of other daemons and things as well - best to
27 * kill them all.
28 */
29
30
31#include <stdint.h>
32#include <stdlib.h>
33#include <stdio.h>
34#include <unistd.h>
35#include <math.h>
36#include <sys/mman.h>
37
38#include "at86rf230.h"
39#include "atrf.h"
40
41#include "atrf-xtal.h"
42
43
44#define MAX_COUNT (1000*1000)
45
46
47/* ----- RF setup ---------------------------------------------------------- */
48
49
50static void rf_setup(struct atrf_dsc *dsc, int size, int trim)
51{
52    static uint8_t buf[127];
53
54    atrf_reset_rf(dsc);
55    atrf_reg_write(dsc, REG_TRX_STATE, TRX_CMD_TRX_OFF);
56
57    atrf_reg_write(dsc, REG_XOSC_CTRL,
58        (XTAL_MODE_INT << XTAL_MODE_SHIFT) | trim);
59
60    /* minimum TX power, maximize delays, disable CRC */
61    switch (atrf_identify(dsc)) {
62    case atrf_at86rf230:
63        atrf_reg_write(dsc, REG_PHY_TX_PWR, 0xf);
64        break;
65    case atrf_at86rf231:
66        atrf_reg_write(dsc, REG_PHY_TX_PWR, 0xff);
67        atrf_reg_write(dsc, REG_TRX_CTRL_1, 0);
68        break;
69    default:
70        abort();
71    }
72
73    atrf_reg_write(dsc, REG_TRX_STATE, TRX_CMD_PLL_ON);
74    usleep(200); /* nominally 180 us worst-case */
75
76    atrf_buf_write(dsc, buf, size);
77
78    //atrf_reg_write(dsc, REG_IRQ_MASK, IRQ_TRX_END);
79    atrf_reg_write(dsc, REG_IRQ_MASK, 0xff);
80}
81
82
83/* ----- Ben hardware ------------------------------------------------------ */
84
85
86static volatile uint32_t *icmr, *icmsr, *icmcr;
87static uint32_t old_icmr;
88
89static volatile uint32_t *clkgr;
90static uint32_t old_clkgr;
91
92static volatile uint32_t *pdpin, *pddats, *pddatc;
93
94
95static void disable_interrupts(void)
96{
97    /*
98     * @@@ Race condition alert ! If we get interrupted/preempted between
99     * reading ICMR and masking all interrupts, and the code that runs
100     * between these two operations changes ICMR, then we may set an
101     * incorrect mask when restoring interrupts, which may hang the system.
102     */
103
104    old_icmr = *icmr;
105    *icmsr = 0xffffffff;
106}
107
108
109static void enable_interrupts(void)
110{
111    *icmcr = ~old_icmr;
112}
113
114
115/*
116 * @@@ Disabling the LCD clock will halng operations that depend on the LCD
117 * subsystem to advance. This includes the screen saver.
118 */
119
120static void disable_lcd(void)
121{
122    old_clkgr = *clkgr;
123    *clkgr = old_clkgr | 1 << 10;
124}
125
126
127static void enable_lcd(void)
128{
129    *clkgr = old_clkgr;
130}
131
132
133static void ben_setup(struct atrf_dsc *dsc)
134{
135    volatile void *base = atrf_ben_regs(dsc);
136
137    icmr = base+0x1004;
138    icmsr = base+0x1008;
139    icmcr = base+0x100c;
140
141    clkgr = base+0x20;
142
143    pdpin = base+0x10300;
144    pddats = base+0x10314;
145    pddatc = base+0x10318;
146
147    /*
148     * Ironically, switching the LCD clock on and off many times only
149     * increases the risk of a hang. Therefore, we leave it stopped during
150     * all the measurements and only enable it again at the end.
151     */
152    disable_lcd();
153}
154
155
156/* ----- Low-level interface ----------------------------------------------- */
157
158
159void atben_setup(struct atrf_dsc *dsc, int size, int trim)
160{
161    rf_setup(dsc, size, trim);
162    mlockall(MCL_CURRENT);
163    ben_setup(dsc);
164}
165
166
167unsigned atben_sample(struct atrf_dsc *dsc)
168{
169    unsigned i = MAX_COUNT;
170
171    (void) atrf_reg_read(dsc, REG_IRQ_STATUS);
172
173    disable_interrupts();
174
175#if 0
176    /*
177     * This is a high-level view of what the code should do. It has rather
178     * high overhead, though, so we optimize it below.
179     */
180
181    atrf_slp_tr(dsc, 1, 1);
182    while (i) {
183        if (atrf_interrupt(dsc))
184            break;
185        i--;
186    }
187#else
188    /*
189     * We hit registers directly. We also don't enforce the upper limit,
190     * to squeeze out a few more cycles and gain a finer resolution.
191     */
192
193    /* pulse SLP_TR */
194    *pddats = 1 << 9;
195    *pddatc = 1 << 9;
196
197    /* count the time until an interrupt arrives */
198    do i--;
199    while (!(*pdpin & 0x1000));
200
201#endif
202
203    enable_interrupts();
204
205    return MAX_COUNT-i;
206}
207
208
209void atben_cleanup(struct atrf_dsc *dsc)
210{
211    enable_lcd();
212}
213
214
215/* ----- Acquisition and evaluation ---------------------------------------- */
216
217
218static int cmp(const void *a, const void *b)
219{
220    return *(unsigned *) a-*(unsigned *) b;
221}
222
223
224
225static double eval(unsigned *res, int rep)
226{
227    double sum = 0;
228    int n = 0;
229    int i;
230
231    qsort(res, rep, sizeof(*res), cmp);
232    if (rep < 8)
233        return res[rep >> 1];
234    for (i = rep/8; i != rep-rep/8; i++) {
235        sum += res[i];
236        n++;
237    }
238    return (double) sum/n;
239}
240
241
242void do_atben(struct atrf_dsc *dsc, int size, int trim, int rep,
243    int dump_raw, double base, double ppm)
244{
245    unsigned *res;
246    double avg, rel;
247    int i;
248
249    res = malloc(rep*sizeof(*res));
250    if (!res) {
251        perror("malloc");
252        exit(1);
253    }
254
255    atben_setup(dsc, size, trim);
256
257    for (i = 0; i != rep; i++)
258        res[i] = atben_sample(dsc);
259
260    atben_cleanup(dsc);
261
262    atrf_close(dsc);
263
264    if (dump_raw) {
265        for (i = 0; i != rep; i++)
266            printf("%u\n", res[i]);
267        exit(0);
268    }
269
270    avg = eval(res, rep);
271    if (!base)
272        printf("%f\n", avg);
273    else {
274        rel = (avg/base-1)*1000000;
275        printf("%+f ppm", rel);
276        if (ppm && fabs(rel) > ppm) {
277            printf(" (outside bounds)\n");
278            exit(1);
279        }
280        putchar('\n');
281    }
282}
283

Archive Download this file



interactive