Blame view

RIOT/cpu/lm4f120/periph/adc.c 3.4 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
  /*
   * Copyright (C) 2016 Marc Poulhiès
   *
   * 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_lm4f120
   * @ingroup     drivers_periph_adc
   * @{
   *
   * @file
   * @brief       Low-level ADC driver implementation
   *
   * The current ADC driver implementation only supports ADC0.
   *
   * @author      Marc Poulhiès <dkm@kataplop.net>
   *
   * @}
   */
  
  #include <stdint.h>
  #include <string.h>
  
  #include "cpu.h"
  #include "mutex.h"
  #include "periph/adc.h"
  
  /*
   * @brief   ADC sequence used by this driver and oversampling settings
   * @{
   */
  #define SEQ             (3)
  #define OVERSAMPLE      (64)
  /** @} */
  
  /**
   * @brief   pin configuration parameters
   */
  struct adc_gpio_cfg_s {
      unsigned long gpio_base;
      unsigned long gpio_sysctl;
      unsigned short gpio_pin;
  };
  
  /**
   * @brief   Fixed ADC pin configuration
   */
  static const struct adc_gpio_cfg_s adc0_gpio[ADC_NUMOF] = {
      { GPIO_PORTE_BASE, SYSCTL_PERIPH_GPIOE, GPIO_PIN_3 }, /**< AIN0 */
      { GPIO_PORTE_BASE, SYSCTL_PERIPH_GPIOE, GPIO_PIN_2 }, /**< AIN1 */
      { GPIO_PORTE_BASE, SYSCTL_PERIPH_GPIOE, GPIO_PIN_1 }, /**< AIN2 */
      { GPIO_PORTE_BASE, SYSCTL_PERIPH_GPIOE, GPIO_PIN_0 }, /**< AIN3 */
      { GPIO_PORTD_BASE, SYSCTL_PERIPH_GPIOD, GPIO_PIN_3 }, /**< AIN4 */
      { GPIO_PORTD_BASE, SYSCTL_PERIPH_GPIOD, GPIO_PIN_2 }, /**< AIN5 */
      { GPIO_PORTD_BASE, SYSCTL_PERIPH_GPIOD, GPIO_PIN_1 }, /**< AIN6 */
      { GPIO_PORTD_BASE, SYSCTL_PERIPH_GPIOD, GPIO_PIN_0 }, /**< AIN7 */
      { GPIO_PORTE_BASE, SYSCTL_PERIPH_GPIOE, GPIO_PIN_5 }, /**< AIN8 */
      { GPIO_PORTE_BASE, SYSCTL_PERIPH_GPIOE, GPIO_PIN_4 }, /**< AIN9 */
      { GPIO_PORTB_BASE, SYSCTL_PERIPH_GPIOB, GPIO_PIN_4 }, /**< AIN10 */
      { GPIO_PORTB_BASE, SYSCTL_PERIPH_GPIOB, GPIO_PIN_5 }, /**< AIN11 */
  };
  
  /**
   * @brief   Lock to prevent concurrent access to the ADC
   */
  static mutex_t lock = MUTEX_INIT;
  
  static inline void prep(void)
  {
      mutex_lock(&lock);
      ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
  }
  
  static inline void done(void)
  {
      ROM_SysCtlPeripheralDisable(SYSCTL_PERIPH_ADC0);
      mutex_unlock(&lock);
  }
  
  int adc_init(adc_t line)
  {
      /* make sure the given ADC line is valid */
      if (line >= ADC_NUMOF) {
          return -1;
      }
  
      prep();
  
      ROM_SysCtlADCSpeedSet(SYSCTL_ADCSPEED_125KSPS);
      ROM_ADCHardwareOversampleConfigure(ADC0_BASE, OVERSAMPLE);
  
      ROM_SysCtlPeripheralEnable(adc0_gpio[line].gpio_sysctl);
      ROM_GPIOPinTypeADC(adc0_gpio[line].gpio_base, adc0_gpio[line].gpio_pin);
  
      done();
  
      return 0;
  }
  
  int adc_sample(adc_t line, adc_res_t res)
  {
      int value[2];
  
      if ((res != ADC_RES_10BIT) && (res != ADC_RES_12BIT)) {
          return -1;
      }
  
      prep();
  
      /* set channel */
      ROM_ADCSequenceConfigure(ADC0_BASE, SEQ, ADC_TRIGGER_PROCESSOR, 0);
      ROM_ADCSequenceStepConfigure(ADC0_BASE, SEQ, 0, line | ADC_CTL_IE | ADC_CTL_END);
      /* set resolution */
      ROM_ADCResolutionSet(ADC0_BASE, (unsigned long)res);
  
      /* start conversion and wait for results */
      ROM_ADCSequenceEnable(ADC0_BASE, SEQ);
      ROM_ADCIntClear(ADC0_BASE, SEQ);
      ROM_ADCProcessorTrigger(ADC0_BASE, SEQ);
      while (!ROM_ADCIntStatus(ADC0_BASE, SEQ, false)) {}
  
      /* get results */
      ROM_ADCSequenceDataGet(ADC0_BASE, SEQ, (unsigned long *) value);
  
      /* disable device again */
      ROM_ADCSequenceDisable(ADC0_BASE, SEQ);
      done();
  
      return value[0];
  }