From 730c611fab2601072b517c4408defb6d173e37d3 Mon Sep 17 00:00:00 2001 From: Alexandre Abadie Date: Thu, 30 Mar 2017 15:02:20 +0200 Subject: [PATCH 1/3] cpu/stm32l1: add adc support --- cpu/stm32l1/include/periph_cpu.h | 24 ++++++ cpu/stm32l1/periph/adc.c | 137 +++++++++++++++++++++++++++++++ 2 files changed, 161 insertions(+) create mode 100644 cpu/stm32l1/periph/adc.c diff --git a/cpu/stm32l1/include/periph_cpu.h b/cpu/stm32l1/include/periph_cpu.h index cfb5e47888..2c947a8218 100644 --- a/cpu/stm32l1/include/periph_cpu.h +++ b/cpu/stm32l1/include/periph_cpu.h @@ -49,6 +49,30 @@ typedef struct { uint8_t chan; /**< DAC device used for this line */ } dac_conf_t; + +/** + * @brief ADC channel configuration data + */ +typedef struct { + gpio_t pin; /**< pin connected to the channel */ + uint8_t chan; /**< CPU ADC channel connected to the pin */ +} adc_conf_t; + +/** + * @brief Override the ADC resolution configuration + * @{ + */ +#define HAVE_ADC_RES_T +typedef enum { + ADC_RES_6BIT = (0x3 << 3), /**< ADC resolution: 6 bit */ + ADC_RES_8BIT = (0x2 << 3), /**< ADC resolution: 8 bit */ + ADC_RES_10BIT = (0x1 << 3), /**< ADC resolution: 10 bit */ + ADC_RES_12BIT = (0x0 << 3), /**< ADC resolution: 12 bit */ + ADC_RES_14BIT = (0xfe), /**< not applicable */ + ADC_RES_16BIT = (0xff) /**< not applicable */ +} adc_res_t; +/** @} */ + /** * @brief I2C configuration data structure */ diff --git a/cpu/stm32l1/periph/adc.c b/cpu/stm32l1/periph/adc.c new file mode 100644 index 0000000000..b4ae8fc736 --- /dev/null +++ b/cpu/stm32l1/periph/adc.c @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2016 Fundacion Inria Chile + * + * 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_stm32l1 + * @{ + * + * @file + * @brief Low-level ADC driver implementation + * + * @author Francisco Molina + * @author Hauke Petersen + * @author Nick v. IJzendoorn + * + * @} + */ + +#include "cpu.h" +#include "mutex.h" +#include "periph/adc.h" + +#ifdef ADC_CONFIG + +/** + * @brief Maximum allowed ADC clock speed + */ +#define MAX_ADC_SPEED (12000000U) + +/** + * @brief Load the ADC configuration + */ +static const adc_conf_t adc_config[] = ADC_CONFIG; + +/** + * @brief Allocate locks for all three available ADC device + * + * All STM32l1 CPU's have single ADC device + */ +static mutex_t lock = MUTEX_INIT; + +static inline void prep(void) +{ + mutex_lock(&lock); + RCC->APB2ENR |= RCC_APB2ENR_ADC1EN; +} + +static inline void done(void) +{ + RCC->APB2ENR &= ~(RCC_APB2ENR_ADC1EN); + mutex_unlock(&lock); +} + +int adc_init(adc_t line) +{ + uint32_t clk_div = 2; + + /* check if the line is valid */ + if (line >= ADC_NUMOF) { + return -1; + } + + /* lock and power-on the device */ + prep(); + + /* configure the pin */ + if ((adc_config[line].pin != GPIO_UNDEF)) + gpio_init_analog(adc_config[line].pin); + + /* set clock prescaler to get the maximal possible ADC clock value */ + for (clk_div = 2; clk_div < 8; clk_div += 2) { + if ((CLOCK_CORECLOCK / clk_div) <= MAX_ADC_SPEED) { + break; + } + } + + ADC->CCR = ((clk_div / 2) - 1) << 16; + + /* check if this channel is an internal ADC channel, if so + * enable the internal temperature and Vref */ + if (adc_config[line].chan == 16 || adc_config[line].chan == 17) { + ADC->CCR |= ADC_CCR_TSVREFE; + } + + /* enable the ADC module */ + ADC1->CR2 = ADC_CR2_ADON; + /* turn off during idle phase*/ + ADC1->CR1 = ADC_CR1_PDI; + + /* free the device again */ + done(); + + return 0; +} + +int adc_sample(adc_t line, adc_res_t res) +{ + int sample; + + /* check if resolution is applicable */ + if ( (res != ADC_RES_6BIT) && + (res != ADC_RES_8BIT) && + (res != ADC_RES_10BIT) && + (res != ADC_RES_12BIT)) { + return -1; + } + + /* lock and power on the ADC device */ + prep(); + + /* set resolution, conversion channel and single read */ + ADC1->CR1 |= res & ADC_CR1_RES; + ADC1->SQR1 &= ~ADC_SQR1_L; + ADC1->SQR5 = adc_config[line].chan; + + /* wait for regulat channel to be ready*/ + while (!(ADC1->SR & ADC_SR_RCNR)) {} + /* start conversion and wait for results */ + ADC1->CR2 |= ADC_CR2_SWSTART; + while (!(ADC1->SR & ADC_SR_EOC)) {} + /* finally read sample and reset the STRT bit in the status register */ + sample = (int)ADC1->DR; + ADC1 -> SR &= ~ADC_SR_STRT; + + /* power off and unlock device again */ + done(); + + return sample; +} + +#else +typedef int dont_be_pedantic; +#endif /* ADC_CONFIG */ From b4ff23580c3054ee7b9f741cb89988d92a12910a Mon Sep 17 00:00:00 2001 From: Alexandre Abadie Date: Thu, 30 Mar 2017 15:02:50 +0200 Subject: [PATCH 2/3] boards/nucleo-l1: add adc and dac configuration --- boards/nucleo-l1/Makefile.features | 2 ++ boards/nucleo-l1/include/periph_conf.h | 34 ++++++++++++++++++++------ 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/boards/nucleo-l1/Makefile.features b/boards/nucleo-l1/Makefile.features index 0458cbfedf..322a9f2b42 100644 --- a/boards/nucleo-l1/Makefile.features +++ b/boards/nucleo-l1/Makefile.features @@ -1,5 +1,7 @@ # Put defined MCU peripherals here (in alphabetical order) +FEATURES_PROVIDED += periph_adc FEATURES_PROVIDED += periph_cpuid +FEATURES_PROVIDED += periph_dac FEATURES_PROVIDED += periph_gpio FEATURES_PROVIDED += periph_i2c FEATURES_PROVIDED += periph_pwm diff --git a/boards/nucleo-l1/include/periph_conf.h b/boards/nucleo-l1/include/periph_conf.h index c74b43ecb1..ab587432a4 100644 --- a/boards/nucleo-l1/include/periph_conf.h +++ b/boards/nucleo-l1/include/periph_conf.h @@ -49,13 +49,6 @@ extern "C" { #define CLOCK_APB1 (CLOCK_CORECLOCK / 1) /** @} */ -/** - * @name DAC configuration - * @{ - */ -#define DAC_NUMOF (0) -/** @} */ - /** * @name Timer configuration * @{ @@ -221,7 +214,34 @@ static const i2c_conf_t i2c_config[] = { {I2C2, GPIO_PIN(PORT_B, 10), GPIO_PIN(PORT_B, 11), GPIO_OD_PU, GPIO_AF4, I2C2_ER_IRQn, I2C2_EV_IRQn}, }; +/** @} */ +/** + * @name ADC configuration + * @{ + */ +#define ADC_CONFIG { \ + { GPIO_PIN(PORT_A, 0), 0 }, \ + { GPIO_PIN(PORT_A, 1), 1 }, \ + { GPIO_PIN(PORT_A, 4), 4 }, \ + { GPIO_PIN(PORT_B, 0), 8 }, \ + { GPIO_PIN(PORT_C, 1), 11 }, \ + { GPIO_PIN(PORT_C, 0), 10 }, \ +} + +#define ADC_NUMOF (6U) +/** @} */ + +/** + * @name DAC configuration + * @{ + */ +#define DAC_CONFIG { \ + { GPIO_PIN(PORT_A, 4), 1}, \ + { GPIO_PIN(PORT_A, 5), 2}, \ +} + +#define DAC_NUMOF (2U) /** @} */ #ifdef __cplusplus From 66c870a446ffdcff93dea21f2537c877706d96e1 Mon Sep 17 00:00:00 2001 From: Alexandre Abadie Date: Thu, 6 Apr 2017 09:27:43 +0200 Subject: [PATCH 3/3] test/unittests: update ARM based boards list --- tests/unittests/Makefile | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/unittests/Makefile b/tests/unittests/Makefile index f7213e04a5..13f3789e1d 100644 --- a/tests/unittests/Makefile +++ b/tests/unittests/Makefile @@ -31,11 +31,11 @@ DISABLE_TEST_FOR_ARM7 := tests-relic ARM_CORTEX_M_BOARDS := airfy-beacon arduino-due arduino-zero cc2538dk ek-lm4f120xl \ f4vi1 fox frdm-k64f iotlab-m3 limifrog-v1 mbed_lpc1768 msbiot \ - mulle nrf51dongle nrf6310 nucleo144-f303 nucleo144-f429 nucleo144-f446 \ - nucleo32-f031 nucleo32-f303 nucleo32-l031 nucleo-f030 nucleo-f070 nucleo-f091 \ - nucleo-f302 nucleo-f303 nucleo-f334 nucleo-f401 nucleo-f410 nucleo-f411 \ - nucleo-l053 nucleo-l073 nucleo-l1 nucleo-l476 \ - opencm904 openmote-cc2538 pba-d-01-kw2x \ + mulle nrf51dongle nrf52840dk nrf6310 nucleo144-f303 nucleo144-f429 \ + nucleo144-f446 nucleo32-f031 nucleo32-f303 nucleo32-l031 nucleo-f030 \ + nucleo-f070 nucleo-f072 nucleo-f091 nucleo-f302 nucleo-f303 nucleo-f334 \ + nucleo-f401 nucleo-f410 nucleo-f411 nucleo-l053 nucleo-l073 nucleo-l1 \ + nucleo-l476 opencm904 openmote-cc2538 pba-d-01-kw2x \ pca10000 pca10005 remote saml21-xpro samr21-xpro slwstk6220a sodaq-autonomo \ spark-core stm32f0discovery stm32f3discovery stm32f4discovery \ udoo weio yunjia-nrf51822