From 13e578bc844e5b6ef67ea301d766894cdaa1ceb9 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Mon, 9 Dec 2019 19:43:33 +0100 Subject: [PATCH] cpu/lpc2387: implement periph/adc lpc23xx has a 10 bit ADC with up to 8 channels. The ADC should be clocked at 4.5 MHz or less, so it uses (72MHz CCLK / 8) / 2. --- cpu/lpc2387/include/periph_cpu.h | 29 ++++++++++++ cpu/lpc2387/periph/adc.c | 81 ++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+) create mode 100644 cpu/lpc2387/periph/adc.c diff --git a/cpu/lpc2387/include/periph_cpu.h b/cpu/lpc2387/include/periph_cpu.h index c8e4d1c21d..17b66cca40 100644 --- a/cpu/lpc2387/include/periph_cpu.h +++ b/cpu/lpc2387/include/periph_cpu.h @@ -153,6 +153,35 @@ typedef enum { */ #define DAC_NUMOF (1U) +/** + * @brief Possible ADC resolution settings + * @{ + */ +#define HAVE_ADC_RES_T +typedef enum { + ADC_RES_16BIT = 0xff, /**< not applicable */ + ADC_RES_14BIT = 0xfe, /**< not applicable */ + ADC_RES_12BIT = 0xfd, /**< not applicable */ + ADC_RES_10BIT = 0b000, /**< ADC resolution: 10 bit */ + ADC_RES_9BIT = 0b001, /**< ADC resolution: 9 bit */ + ADC_RES_8BIT = 0b010, /**< ADC resolution: 8 bit */ + ADC_RES_7BIT = 0b011, /**< ADC resolution: 7 bit */ + ADC_RES_6BIT = 0b100, /**< ADC resolution: 6 bit */ + ADC_RES_5BIT = 0b101, /**< ADC resolution: 5 bit */ + ADC_RES_4BIT = 0b110, /**< ADC resolution: 4 bit */ + ADC_RES_3BIT = 0b111, /**< ADC resolution: 3 bit */ +} adc_res_t; +/** @} */ + +/** + * @brief ADC device configuration + */ +typedef struct { + uint8_t chan; /**< which ADC to use (0…7) */ + uint8_t pinsel; /**< PINSEL# of the ADC pin */ + uint32_t pinsel_msk; /**< PINSEL Mask for ADC pin */ +} adc_conf_t; + /* @} */ #ifdef __cplusplus } diff --git a/cpu/lpc2387/periph/adc.c b/cpu/lpc2387/periph/adc.c new file mode 100644 index 0000000000..428a052a8d --- /dev/null +++ b/cpu/lpc2387/periph/adc.c @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2019 Beuth Hochschule für Technik Berlin + * + * 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 drivers_periph + * @{ + * + * @file + * @brief Low-level ADC driver implementation for lpc23xx family + * + * @author Benjamin Valentin + * + * @} + */ + +#include "cpu.h" +#include "kernel_defines.h" +#include "periph/adc.h" +#include "periph_conf.h" + +int adc_init(adc_t line) +{ + /* check if the line is valid */ + if (line >= ADC_NUMOF) { + return -1; + } + + /* enable clock/power for ADC */ + PCONP |= BIT12; + + /* set ADC PCLK to CCLK/8 */ + PCLKSEL0 |= BIT25 + BIT25; + + /* configure AF for ADC pin */ + *(&PINSEL0 + adc_config[line].pinsel) |= adc_config[line].pinsel_msk; + + /* power down ADC */ + AD0CR = 0; + + return 0; +} + +int32_t adc_sample(adc_t line, adc_res_t res) +{ + uint32_t val; + + /* check if the line is valid */ + if (line >= ADC_NUMOF) { + return -1; + } + + /* check if resolution is applicable */ + if (res > 0xf0) { + return -1; + } + + /* Enable & configure ADC. + * burst mode is used even though we only do one conversion here + * in order to being able to configure the resolution. + */ + AD0CR = (1 << adc_config[line].chan) /* select channel */ + | (1 << 8) /* clocked at 4.5 MHz */ + | (1 << 16) /* enable burst mode */ + | (res << 17) /* select resolution */ + | (1 << 21) /* enable ADC */ + | (1 << 24); /* start conversion */ + + do { + val = *(&AD0DR0 + adc_config[line].chan); + } while (!(val & BIT31)); + + /* power down ADC */ + AD0CR = 0; + + return val & 0xFFFF; +}