/* * 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 * * @} */ #include #include #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]; }