Blame view

RIOT/cpu/kinetis_common/periph/adc.c 6.46 KB
a752c7ab   elopes   add first test an...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
  /*
   * Copyright (C) 2014-2016 Freie Universität Berlin
   * Copyright (C) 2014 PHYTEC Messtechnik GmbH
   * Copyright (C) 2015 Eistec AB
   *
   * This file is subject to the terms and conditions of the GNU Lesser General
   * Public License v2.1. See the file LICENSE in the top level directory for more
   * details.
   */
  
  /**
   * @ingroup     cpu_kinetis_common
   * @ingroup     drivers_periph_adc
   * @{
   *
   * @file
   * @brief       Low-level ADC driver implementation
   *
   * @author      Hauke Petersen <hauke.petersen@fu-berlin.de>
   * @author      Johann Fischer <j.fischer@phytec.de>
   * @author      Jonas Remmert <j.remmert@phytec.de>
   * @author      Joakim Nohlgård <joakim.nohlgard@eistec.se>
   *
   * @}
   */
  #include <stdio.h>
  
  #include "cpu.h"
  #include "bit.h"
  #include "mutex.h"
  #include "periph/adc.h"
  
  /**
   * @brief   Maximum clock speed
   *
   * The ADC clock speed must be configured to be >2MHz and <12MHz in order for
   * the ADC to work. For ADC calibration to work as intended, the ADC clock speed
   * must further no be >4MHz, so we target a ADC clock speed > 2 and <4MHz.
   */
  #define ADC_MAX_CLK         (4000000U)
  
  static mutex_t locks[] = {
      MUTEX_INIT,
  #ifdef ADC1
      MUTEX_INIT,
  #endif
  };
  
  static inline ADC_Type *dev(adc_t line)
  {
      return adc_config[line].dev;
  }
  
  static inline int dev_num(adc_t line)
  {
      if (dev(line) == ADC0) {
          return 0;
      }
  #ifdef ADC1
      else if (dev(line) == ADC1) {
          return 1;
      }
  #endif
      return -1;
  }
  
  static inline void prep(adc_t line)
  {
      if (dev(line) == ADC0) {
          bit_set32(&SIM->SCGC6, SIM_SCGC6_ADC0_SHIFT);
      }
  #ifdef ADC1
      else if (dev(line) == ADC1) {
  #if defined(SIM_SCGC3_ADC1_SHIFT)
          bit_set32(&SIM->SCGC3, SIM_SCGC3_ADC1_SHIFT);
  #elif defined(SIM_SCGC6_ADC1_SHIFT)
          bit_set32(&SIM->SCGC6, SIM_SCGC6_ADC1_SHIFT);
  #else
  #error ADC1 clock gate is not known!
  #endif
      }
  #endif /* ADC1 */
      mutex_lock(&locks[dev_num(line)]);
  }
  
  static inline void done(adc_t line)
  {
      if (dev(line) == ADC0) {
          bit_clear32(&SIM->SCGC6, SIM_SCGC6_ADC0_SHIFT);
      }
  #ifdef ADC1
      else if (dev(line) == ADC1) {
  #if defined(SIM_SCGC3_ADC1_SHIFT)
          bit_clear32(&SIM->SCGC3, SIM_SCGC3_ADC1_SHIFT);
  #elif defined(SIM_SCGC6_ADC1_SHIFT)
          bit_clear32(&SIM->SCGC6, SIM_SCGC6_ADC1_SHIFT);
  #endif
      }
  #endif /* ADC1 */
      mutex_unlock(&locks[dev_num(line)]);
  }
  
  /**
   * @brief Perform ADC calibration routine.
   *
   * This is a recipe taken straight from the Kinetis K60 reference manual. It has
   * been tested on MK60DN512VLL10.
   *
   * @param[in]  dev          Pointer to ADC device to operate on.
   *
   * @return 0 on success
   * @return <0 on errors
   */
  int kinetis_adc_calibrate(ADC_Type *dev)
  {
      uint16_t cal;
  
      dev->SC3 |= ADC_SC3_CAL_MASK;
  
      while (dev->SC3 & ADC_SC3_CAL_MASK) {} /* wait for calibration to finish */
  
      while (!(dev->SC1[0] & ADC_SC1_COCO_MASK)) {}
  
      if (dev->SC3 & ADC_SC3_CALF_MASK) {
          /* calibration failed for some reason, possibly SC2[ADTRG] is 1 ? */
          return -1;
      }
  
      /* From the reference manual */
      /* 1. Initialize or clear a 16-bit variable in RAM. */
      /* 2. Add the plus-side calibration results CLP0, CLP1, CLP2, CLP3, CLP4,
       * and CLPS to the variable. */
      cal = dev->CLP0 + dev->CLP1 + dev->CLP2 + dev->CLP3 + dev->CLP4 + dev->CLPS;
      /* 3. Divide the variable by two. */
      cal /= 2;
      /* 4. Set the MSB of the variable. */
      cal |= (1 << 15);
      /* (5. The previous two steps can be achieved by setting the carry bit,
       * rotating to the right through the carry bit on the high byte and again on
       * the low byte.)
       * We ignore the above optimization suggestion, we most likely only perform
       * this calibration on startup and it will only save nanoseconds. */
      /* 6. Store the value in the plus-side gain calibration register PG. */
      dev->PG = cal;
      /* 7. Repeat the procedure for the minus-side gain calibration value. */
      cal = dev->CLM0 + dev->CLM1 + dev->CLM2 + dev->CLM3 + dev->CLM4 + dev->CLMS;
      cal /= 2;
      cal |= (1 << 15);
      dev->MG = cal;
  
      return 0;
  }
  
  int adc_init(adc_t line)
  {
      /* make sure the given line is valid */
      if (line >= ADC_NUMOF) {
          return -1;
      }
  
      /* prepare the device: lock and power on */
      prep(line);
  
      /* configure the connected pin mux */
      if (adc_config[line].pin != GPIO_UNDEF) {
          gpio_init_port(adc_config[line].pin, GPIO_AF_ANALOG);
      }
  
      /* The ADC requires at least 2 MHz module clock for full accuracy, and less
       * than 12 MHz */
      /* For the calibration it is important that the ADC clock is <= 4 MHz */
      uint32_t adiv;
      if (CLOCK_BUSCLOCK > (ADC_MAX_CLK << 3)) {
  #if KINETIS_HAVE_ADICLK_BUS_DIV_2
          /* Some CPUs, e.g. MK60D10, MKW22D5, provide an additional divide by two
           * divider for the bus clock as CFG1[ADICLK] = 0b01
           */
          adiv = ADC_CFG1_ADIV(3) | ADC_CFG1_ADICLK(1);
  #else
          /* Newer CPUs seem to have replaced this with various alternate clock
           * sources instead */
          adiv = ADC_CFG1_ADIV(3);
  #endif
      }
      else {
          unsigned int i = 0;
          while ((i < 3) && (CLOCK_BUSCLOCK > (ADC_MAX_CLK << i))) {
              ++i;
          }
          adiv = ADC_CFG1_ADIV(i);
      }
  
      /* set configuration register 1: clocking and precision */
      /* Set long sample time */
      dev(line)->CFG1 = ADC_CFG1_ADLSMP_MASK | adiv;
      /* select ADxxb channels, longest sample time (20 extra ADC cycles) */
      dev(line)->CFG2 = ADC_CFG2_MUXSEL_MASK | ADC_CFG2_ADLSTS(0);
      /* select software trigger, external ref pins */
      dev(line)->SC2 = ADC_SC2_REFSEL(0);
      /* select hardware average over 32 samples */
      dev(line)->SC3 = ADC_SC3_AVGE_MASK | ADC_SC3_AVGS(3);
      /* set an (arbitrary) input channel, single-ended mode */
      dev(line)->SC1[0] = ADC_SC1_ADCH(0);
  
      /* perform calibration routine */
      int res = kinetis_adc_calibrate(dev(line));
      done(line);
      return res;
  }
  
  int adc_sample(adc_t line, adc_res_t res)
  {
      int sample;
  
      /* check if resolution is applicable */
      if (res > 0xf0) {
          return -1;
      }
  
      /* lock and power on the device */
      prep(line);
  
      /* set resolution */
      dev(line)->CFG1 &= ~(ADC_CFG1_MODE_MASK);
      dev(line)->CFG1 |=  (res);
      /* select the channel that is sampled */
      dev(line)->SC1[0] = adc_config[line].chan;
      /* wait until conversion is complete */
      while (!(dev(line)->SC1[0] & ADC_SC1_COCO_MASK)) {}
      /* read and return result */
      sample = (int)dev(line)->R[0];
  
      /* power off and unlock the device */
      done(line);
  
      return sample;
  }