1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

cpu/atmega_common: add adc driver

This commit is contained in:
Laurent Navet 2017-02-15 21:28:10 +01:00 committed by smlng
parent d689a0c8a6
commit 9de00af063
22 changed files with 495 additions and 13 deletions

View File

@ -1,4 +1,5 @@
# Put defined MCU peripherals here (in alphabetical order)
FEATURES_PROVIDED += periph_adc
FEATURES_PROVIDED += periph_gpio
FEATURES_PROVIDED += periph_i2c
FEATURES_PROVIDED += periph_spi

View File

@ -109,6 +109,30 @@ static const gpio_t arduino_pinmap[] = {
#endif
};
/**
* @brief Look-up table for the Arduino's analog pins
*/
static const adc_t arduino_analog_map[] = {
ARDUINO_A0,
ARDUINO_A1,
ARDUINO_A2,
ARDUINO_A3,
ARDUINO_A4,
ARDUINO_A5,
ARDUINO_A6,
ARDUINO_A7,
#ifdef CPU_ATMEGA2560
ARDUINO_A8,
ARDUINO_A9,
ARDUINO_A10,
ARDUINO_A11,
ARDUINO_A12,
ARDUINO_A13,
ARDUINO_A14,
ARDUINO_A15,
#endif
};
#ifdef __cplusplus
}
#endif

View File

@ -25,6 +25,9 @@
#ifndef ARDUINO_PINMAP_H
#define ARDUINO_PINMAP_H
#include "periph/gpio.h"
#include "periph/adc.h"
#ifdef __cplusplus
extern "C" {
#endif
@ -155,9 +158,27 @@ extern "C" {
#define ARDUINO_PIN_A14 ARDUINO_PIN_68
#define ARDUINO_PIN_A15 ARDUINO_PIN_69
#endif
/** @ */
#define ARDUINO_A0 ADC_LINE(0)
#define ARDUINO_A1 ADC_LINE(1)
#define ARDUINO_A2 ADC_LINE(2)
#define ARDUINO_A3 ADC_LINE(3)
#define ARDUINO_A4 ADC_LINE(4)
#define ARDUINO_A5 ADC_LINE(5)
#define ARDUINO_A6 ADC_LINE(6)
#define ARDUINO_A7 ADC_LINE(7)
#ifdef CPU_ATMEGA2560
#define ARDUINO_A8 ADC_LINE(8)
#define ARDUINO_A9 ADC_LINE(9)
#define ARDUINO_A10 ADC_LINE(10)
#define ARDUINO_A11 ADC_LINE(11)
#define ARDUINO_A12 ADC_LINE(12)
#define ARDUINO_A13 ADC_LINE(13)
#define ARDUINO_A14 ADC_LINE(14)
#define ARDUINO_A15 ADC_LINE(15)
#endif
#ifdef __cplusplus
}
#endif

View File

@ -1,6 +1,7 @@
/*
* Copyright (C) 2014 Freie Universität Berlin, Hinnerk van Bruinehsen
* 2016 Laurent Navet <laurent.navet@gmail.com>
* 2017 HAW Hamburg, Dimitri Nahm
*
* 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
@ -17,6 +18,7 @@
* @author Hinnerk van Bruinehsen <h.v.bruinehsen@fu-berlin.de>
* @author Laurent Navet <laurent.navet@gmail.com>
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
* @author Dimitri Nahm <dimitri.nahm@haw-hamburg.de>
*/
#ifndef PERIPH_CONF_H
@ -136,9 +138,29 @@ extern "C" {
/** @} */
/**
* @brief I2C configuration
* @name I2C configuration
* @{
*/
#define I2C_NUMOF 1
/** @} */
/**
* @name ADC configuration
*
* The number of ADC channels of the atmega328p depends on the package:
* - 6-channel 10-bit ADC in PDIP package
* - 8-channel 10-bit ADC in TQFP and QFN/MLF package
* Arduino UNO / Duemilanove has thereby 6 channels. But only 5 channels can be
* used for ADC, because the pin of ADC5 emulate a software triggered interrupt.
* -> boards -> arduino-atmega-common -> include -> board_common.h
* @{
*/
#if defined (CPU_ATMEGA328P) || defined (CPU_ATMEGA1281)
#define ADC_NUMOF (8U)
#elif defined (CPU_ATMEGA2560)
#define ADC_NUMOF (16U)
#endif
/** @} */
#ifdef __cplusplus
}

View File

@ -115,6 +115,24 @@ static const gpio_t arduino_pinmap[] = {
ARDUINO_PIN_78,
};
/**
* @brief Look-up table for the Arduino's analog pins
*/
static const adc_t arduino_analog_map[] = {
ARDUINO_A0,
ARDUINO_A1,
ARDUINO_A2,
ARDUINO_A3,
ARDUINO_A4,
ARDUINO_A5,
ARDUINO_A6,
ARDUINO_A7,
ARDUINO_A8,
ARDUINO_A9,
ARDUINO_A10,
ARDUINO_A11,
};
#ifdef __cplusplus
}
#endif

View File

@ -55,6 +55,19 @@ static const gpio_t arduino_pinmap[] = {
ARDUINO_PIN_A6,
};
/**
* @brief Look-up table for the Arduino's analog pins
*/
static const adc_t arduino_analog_map[] = {
ARDUINO_A0,
ARDUINO_A1,
ARDUINO_A2,
ARDUINO_A3,
ARDUINO_A4,
ARDUINO_A5,
ARDUINO_A6,
};
#ifdef __cplusplus
}
#endif

View File

@ -23,6 +23,7 @@
#define ARDUINO_PINMAP_H
#include "periph/gpio.h"
#include "periph/adc.h"
#ifdef __cplusplus
extern "C" {
@ -58,6 +59,19 @@ extern "C" {
#define ARDUINO_PIN_A6 GPIO_PIN(PA, 7) /* AIN7 */
/** @} */
/**
* @name Mapping of Ardunino analog pins to RIOT ADC lines
* @{
*/
#define ARDUINO_A0 ADC_LINE(0)
#define ARDUINO_A1 ADC_LINE(1)
#define ARDUINO_A2 ADC_LINE(2)
#define ARDUINO_A3 ADC_LINE(3)
#define ARDUINO_A4 ADC_LINE(4)
#define ARDUINO_A5 ADC_LINE(5)
#define ARDUINO_A6 ADC_LINE(6)
/** @} */
#ifdef __cplusplus
}
#endif

View File

@ -58,6 +58,18 @@ static const gpio_t arduino_pinmap[] = {
ARDUINO_PIN_A5,
};
/**
* @brief Look-up table for the Arduino's analog pins
*/
static const adc_t arduino_analog_map[] = {
ARDUINO_A0,
ARDUINO_A1,
ARDUINO_A2,
ARDUINO_A3,
ARDUINO_A4,
ARDUINO_A5,
};
#ifdef __cplusplus
}
#endif

View File

@ -23,6 +23,7 @@
#define ARDUINO_PINMAP_H
#include "periph/gpio.h"
#include "periph/adc.h"
#ifdef __cplusplus
extern "C" {
@ -56,6 +57,18 @@ extern "C" {
#define ARDUINO_PIN_A5 GPIO_PIN(PB, 2)
/** @ */
/**
* @name Mapping of Ardunino analog pins to RIOT ADC lines
* @{
*/
#define ARDUINO_A0 ADC_LINE(0)
#define ARDUINO_A1 ADC_LINE(1)
#define ARDUINO_A2 ADC_LINE(2)
#define ARDUINO_A3 ADC_LINE(3)
#define ARDUINO_A4 ADC_LINE(4)
#define ARDUINO_A5 ADC_LINE(5)
/** @} */
#ifdef __cplusplus
}
#endif

View File

@ -58,6 +58,18 @@ static const gpio_t arduino_pinmap[] = {
ARDUINO_PIN_A5,
};
/**
* @brief Look-up table for the Arduino's analog pins
*/
static const adc_t arduino_analog_map[] = {
ARDUINO_A0,
ARDUINO_A1,
ARDUINO_A2,
ARDUINO_A3,
ARDUINO_A4,
ARDUINO_A5,
};
#ifdef __cplusplus
}
#endif

View File

@ -23,6 +23,7 @@
#define ARDUINO_PINMAP_H
#include "periph/gpio.h"
#include "periph/adc.h"
#ifdef __cplusplus
extern "C" {
@ -64,6 +65,18 @@ extern "C" {
#define ARDUINO_PIN_A5 GPIO_PIN(PORT_C, 0)
/** @ */
/**
* @name Mapping of Ardunino analog pins to RIOT ADC lines
* @{
*/
#define ARDUINO_A0 ADC_LINE(0)
#define ARDUINO_A1 ADC_LINE(1)
#define ARDUINO_A2 ADC_LINE(2)
#define ARDUINO_A3 ADC_LINE(3)
#define ARDUINO_A4 ADC_LINE(4)
#define ARDUINO_A5 ADC_LINE(5)
/** @} */
#ifdef __cplusplus
}
#endif

View File

@ -53,6 +53,18 @@ static const gpio_t arduino_pinmap[] = {
ARDUINO_PIN_A5,
};
/**
* @brief Look-up table for the Arduino's analog pins
*/
static const adc_t arduino_analog_map[] = {
ARDUINO_A0,
ARDUINO_A1,
ARDUINO_A2,
ARDUINO_A3,
ARDUINO_A4,
ARDUINO_A5,
};
#ifdef __cplusplus
}
#endif

View File

@ -23,6 +23,7 @@
#define ARDUINO_PINMAP_H
#include "periph/gpio.h"
#include "periph/adc.h"
#ifdef __cplusplus
extern "C" {
@ -74,6 +75,18 @@ extern "C" {
#endif
/** @ */
/**
* @name Mapping of Ardunino analog pins to RIOT ADC lines
* @{
*/
#define ARDUINO_A0 ADC_LINE(0)
#define ARDUINO_A1 ADC_LINE(1)
#define ARDUINO_A2 ADC_LINE(2)
#define ARDUINO_A3 ADC_LINE(3)
#define ARDUINO_A4 ADC_LINE(4)
#define ARDUINO_A5 ADC_LINE(5)
/** @} */
#ifdef __cplusplus
}
#endif

View File

@ -58,6 +58,20 @@ static const gpio_t arduino_pinmap[] = {
ARDUINO_PIN_A7
};
/**
* @brief Look-up table for the Arduino's analog pins
*/
static const adc_t arduino_analog_map[] = {
ARDUINO_A0,
ARDUINO_A1,
ARDUINO_A2,
ARDUINO_A3,
ARDUINO_A4,
ARDUINO_A5,
ARDUINO_A6,
ARDUINO_A7,
};
#ifdef __cplusplus
}
#endif

View File

@ -23,7 +23,7 @@
#define ARDUINO_PINMAP_H
#include "periph/gpio.h"
#include "periph/adc.h"
#ifdef __cplusplus
extern "C" {
#endif
@ -63,6 +63,20 @@ extern "C" {
#define ARDUINO_PIN_A7 GPIO_PIN(PORT_A, 2)
/** @ */
/**
* @name Mapping of Ardunino analog pins to RIOT ADC lines
* @{
*/
#define ARDUINO_A0 ADC_LINE(0)
#define ARDUINO_A1 ADC_LINE(1)
#define ARDUINO_A2 ADC_LINE(2)
#define ARDUINO_A3 ADC_LINE(3)
#define ARDUINO_A4 ADC_LINE(4)
#define ARDUINO_A5 ADC_LINE(5)
#define ARDUINO_A6 ADC_LINE(6)
#define ARDUINO_A7 ADC_LINE(7)
/** @} */
#ifdef __cplusplus
}
#endif

View File

@ -19,7 +19,7 @@
#ifndef ARDUINO_BOARD_H
#define ARDUINO_BOARD_H
#include "periph/gpio.h"
#include "arduino_pinmap.h"
#ifdef __cplusplus
extern "C" {
@ -28,14 +28,24 @@ extern "C" {
#define ARDUINO_LED (2)
static const gpio_t arduino_pinmap[] = {
GPIO_PIN(PORT_D, 12),
GPIO_PIN(PORT_D, 13),
GPIO_PIN(PORT_D, 14),
GPIO_PIN(PORT_D, 15),
GPIO_PIN(PORT_A, 12),
GPIO_PIN(PORT_A, 15),
GPIO_PIN(PORT_B, 1),
GPIO_PIN(PORT_B, 2),
ARDUINO_PIN_0,
ARDUINO_PIN_1,
ARDUINO_PIN_2,
ARDUINO_PIN_3,
ARDUINO_PIN_4,
ARDUINO_PIN_5,
ARDUINO_PIN_6,
ARDUINO_PIN_7,
};
/**
* @brief Look-up table for the Arduino's analog pins
*/
static const adc_t arduino_analog_map[] = {
ARDUINO_A0,
ARDUINO_A1,
ARDUINO_A2,
ARDUINO_A3,
};
#ifdef __cplusplus

View File

@ -0,0 +1,61 @@
/*
* Copyright (C) 2017 HAW Hamburg
*
* 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 boards_stm32f4discovery
* @{
*
* @file
* @brief Mapping from MCU pins to Arduino pins
*
* You can use the defines in this file for simplified interaction with the
* Arduino specific pin numbers.
*
* @author Sebastian Meiling <s@mlng.net>
*/
#ifndef ARDUINO_PINMAP_H
#define ARDUINO_PINMAP_H
#include "periph/gpio.h"
#include "periph/adc.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @name Mapping of MCU pins to Arduino pins
* @{
*/
#define ARDUINO_PIN_0 GPIO_PIN(PORT_D, 12)
#define ARDUINO_PIN_1 GPIO_PIN(PORT_D, 13)
#define ARDUINO_PIN_2 GPIO_PIN(PORT_D, 14)
#define ARDUINO_PIN_3 GPIO_PIN(PORT_D, 15)
#define ARDUINO_PIN_4 GPIO_PIN(PORT_A, 12)
#define ARDUINO_PIN_5 GPIO_PIN(PORT_A, 15)
#define ARDUINO_PIN_6 GPIO_PIN(PORT_B, 1)
#define ARDUINO_PIN_7 GPIO_PIN(PORT_B, 2)
/** @ */
/**
* @name Mapping of Ardunino analog pins to RIOT ADC lines
* @{
*/
#define ARDUINO_A0 ADC_LINE(0)
#define ARDUINO_A1 ADC_LINE(1)
#define ARDUINO_A2 ADC_LINE(2)
#define ARDUINO_A3 ADC_LINE(3)
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* ARDUINO_PINMAP_H */
/** @} */

View File

@ -1,4 +1,5 @@
# Put defined MCU peripherals here (in alphabetical order)
FEATURES_PROVIDED += periph_adc
FEATURES_PROVIDED += periph_gpio
FEATURES_PROVIDED += periph_i2c
FEATURES_PROVIDED += periph_spi

View File

@ -104,9 +104,18 @@ extern "C" {
/** @} */
/**
* @brief I2C configuration
* @name I2C configuration
* @{
*/
#define I2C_NUMOF 1
/** @} */
/**
* @name ADC configuration
* @{
*/
#define ADC_NUMOF (8U)
/** @} */
#ifdef __cplusplus
}

View File

@ -0,0 +1,143 @@
/*
* Copyright (C) 2016 Laurent Navet <laurent.navet@gmail.com>
* 2017 HAW Hamburg, Dimitri Nahm
*
* 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 ATmega family
*
* @author Laurent Navet <laurent.navet@gmail.com>
* @author Dimitri Nahm <dimitri.nahm@haw-hamburg.de>
* @author Sebastian Meiling <s@mlng.net>
* @}
*/
#include "cpu.h"
#include "mutex.h"
#include "assert.h"
#include "periph/adc.h"
#include "periph_conf.h"
#define ADC_MAX_CLK (200000U)
static mutex_t lock = MUTEX_INIT;
static inline void _prep(void)
{
mutex_lock(&lock);
/* Enable ADC */
ADCSRA |= (1 << ADEN);
}
static inline void _done(void)
{
/* Disable ADC */
ADCSRA &= ~(1 << ADEN);
mutex_unlock(&lock);
}
int adc_init(adc_t line)
{
/* check if the line is valid */
if (line >= ADC_NUMOF) {
return -1;
}
_prep();
/* Disable corresponding Digital input */
if (line < 8) {
DIDR0 |= (1 << line);
}
#if defined(CPU_ATMEGA2560)
else {
DIDR2 |= (1 << (line - 8));
}
#endif
/* Set ADC-pin as input */
#if defined(CPU_ATMEGA328P)
DDRC &= ~(1 << line);
PORTC &= ~(1 << line);
#elif defined(CPU_ATMEGA2560) || defined(CPU_ATMEGA1281)
if (line < 8) {
DDRF &= ~(1 << line);
PORTF &= ~(1 << line);
}
#if defined(CPU_ATMEGA2560)
else {
DDRK &= ~(1 << (line-8));
PORTK &= ~(1 << (line-8));
}
#endif /* CPU_ATMEGA2560 */
#endif /* CPU_ATMEGA328P */
/* set clock prescaler to get the maximal possible ADC clock value */
for (uint32_t clk_div = 1; clk_div < 8; ++clk_div) {
if ((CLOCK_CORECLOCK / (1 << clk_div)) <= ADC_MAX_CLK) {
ADCSRA |= clk_div;
break;
}
}
/* Ref Voltage is Vcc(5V) */
ADMUX |= (1 << REFS0);
_done();
return 0;
}
int adc_sample(adc_t line, adc_res_t res)
{
int sample = 0;
/* check if resolution is applicable */
if (res != ADC_RES_10BIT) {
return -1;
}
_prep();
/* set conversion channel */
#if defined(CPU_ATMEGA328P) || defined(CPU_ATMEGA1281)
ADMUX &= 0xf0;
ADMUX |= line;
#elif defined(CPU_ATMEGA2560)
if (line < 8) {
ADCSRB &= ~(1 << MUX5);
ADMUX &= 0xf0;
ADMUX |= line;
}
else {
ADCSRB |= (1 << MUX5);
ADMUX &= 0xf0;
ADMUX |= (line-8);
}
#endif
/* Start a new conversion. By default, this conversion will
be performed in single conversion mode. */
ADCSRA |= (1 << ADSC);
/* Wait until the conversion is complete */
while (ADCSRA & (1 << ADSC)) {}
/* Get conversion result */
sample = ADC;
/* Clear the ADIF flag */
ADCSRA |= (1 << ADIF);
_done();
return sample;
}

View File

@ -21,10 +21,13 @@
extern "C" {
#include "xtimer.h"
#include "periph/gpio.h"
#include "periph/adc.h"
}
#include "arduino.hpp"
#define ANALOG_PIN_NUMOF (sizeof(arduino_analog_map) / sizeof(arduino_analog_map[0]))
void pinMode(int pin, int mode)
{
gpio_mode_t m = GPIO_OUT;
@ -58,3 +61,32 @@ void delay(unsigned long msec)
{
xtimer_usleep(1000 * msec);
}
/*
* Bitfield for the state of the ADC-channels.
* 0: Not initialized
* 1: Successfully initialized
*/
static uint16_t adc_line_state = 0;
int analogRead(int arduino_pin)
{
int adc_value;
/* Check if the ADC line is valid */
assert((arduino_pin >= 0) && (arduino_pin < (int)ANALOG_PIN_NUMOF));
/* Initialization of given ADC channel */
if (!(adc_line_state & (1 << arduino_pin))) {
if (adc_init(arduino_analog_map[arduino_pin]) != 0) {
return -1;
}
/* The ADC channel is initialized */
adc_line_state |= 1 << arduino_pin;
}
/* Read the ADC channel */
adc_value = adc_sample(arduino_analog_map[arduino_pin], ADC_RES_10BIT);
return adc_value;
}

View File

@ -82,5 +82,15 @@ int digitalRead(int pin);
*/
void delay(unsigned long msec);
/**
* @brief Read the current value of the given analog pin
*
* @param[in] pin pin to read
*
* @return a value between 0 to 1023 that is proportionnal
* to the voltage applied to the pin
*/
int analogRead(int pin);
#endif /* ARDUINO_H */
/** @} */