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

Merge pull request #4430 from haukepetersen/opt_periph_adc

drivers/periph: reworked the ADC driver
This commit is contained in:
Martine Lenders 2016-03-14 14:45:23 +01:00
commit d66625b6ca
46 changed files with 1008 additions and 1373 deletions

View File

@ -95,19 +95,13 @@ static const timer_conf_t timer_config[] = {
/** @} */
/**
* @name ADC configuration
* @brief ADC configuration
*
* The configuration consists simply of a list of channels that should be used
* @{
*/
#define ADC_NUMOF (1U)
#define ADC_0_EN 1
#define ADC_MAX_CHANNELS 4
/* ADC 0 device configuration */
#define ADC_0_CHANNELS 4
#define ADC_0_CH0 ADC_CONFIG_PSEL_AnalogInput3
#define ADC_0_CH1 ADC_CONFIG_PSEL_AnalogInput4
#define ADC_0_CH2 ADC_CONFIG_PSEL_AnalogInput5
#define ADC_0_CH3 ADC_CONFIG_PSEL_AnalogInput6
#define ADC_CONFIG {3, 4, 5, 6}
#define ADC_NUMOF (4)
/** @} */
/**

View File

@ -93,12 +93,11 @@ extern "C" {
/** @} */
/**
* @name ADC configuration
* @brief ADC configuration
* @{
*/
#define ADC_NUMOF 1
#define ADC_0_EN 1
#define ADC_MAX_CHANNELS 12
#define ADC_NUMOF (12)
/** @} */
#ifdef __cplusplus
}

View File

@ -104,6 +104,13 @@ static const uart_conf_t uart_config[] = {
#define UART_NUMOF (sizeof(uart_config) / sizeof(uart_config[0]))
/** @} */
/**
* @brief ADC configuration
* @{
*/
#define ADC_NUMOF (0)
/** @} */
#ifdef __cplusplus
}
#endif

View File

@ -20,7 +20,7 @@
#ifndef PERIPH_CONF_H
#define PERIPH_CONF_H
#include "cpu_conf.h"
#include "periph_cpu.h"
#ifdef __cplusplus
extern "C"
@ -45,6 +45,7 @@ extern "C"
#define KINETIS_MCG_PLL_FREQ 60000000
#define CLOCK_CORECLOCK KINETIS_MCG_PLL_FREQ
#define CLOCK_BUSCLOCK (CLOCK_CORECLOCK / 2)
/** @} */
@ -102,47 +103,17 @@ extern "C"
* @name ADC configuration
* @{
*/
#define ADC_NUMOF (1U)
#define ADC_0_EN 1
#define ADC_MAX_CHANNELS 6
static const adc_conf_t adc_config[] = {
/* dev, pin, channel */
{ ADC0, GPIO_PIN(PORT_B, 10), 14 },
{ ADC0, GPIO_PIN(PORT_B, 11), 15 },
{ ADC0, GPIO_PIN(PORT_C, 11), 7 },
{ ADC0, GPIO_PIN(PORT_C, 10), 6 },
{ ADC0, GPIO_PIN(PORT_C, 8), 4 },
{ ADC0, GPIO_PIN(PORT_C, 9), 5 },
};
/* ADC 0 configuration */
#define ADC_0_DEV ADC1
#define ADC_0_MODULE_CLOCK CLOCK_CORECLOCK
#define ADC_0_CHANNELS 6
#define ADC_0_CLKEN() (SIM->SCGC3 |= (SIM_SCGC3_ADC1_MASK))
#define ADC_0_CLKDIS() (SIM->SCGC3 &= ~(SIM_SCGC3_ADC1_MASK))
#define ADC_0_PORT_CLKEN() (SIM->SCGC5 |= (SIM_SCGC5_PORTB_MASK | SIM_SCGC5_PORTC_MASK))
/* ADC 0 channel 0 pin config */
#define ADC_0_CH0_PORT PORTB
#define ADC_0_CH0_PIN 10
#define ADC_0_CH0_PIN_AF 0
#define ADC_0_CH0 14
/* ADC 0 channel 1 pin config */
#define ADC_0_CH1_PORT PORTB
#define ADC_0_CH1_PIN 11
#define ADC_0_CH1_PIN_AF 0
#define ADC_0_CH1 15
/* ADC 0 channel 2 pin config */
#define ADC_0_CH2_PORT PORTC
#define ADC_0_CH2_PIN 11
#define ADC_0_CH2_PIN_AF 0
#define ADC_0_CH2 7
/* ADC 0 channel 3 pin config */
#define ADC_0_CH3_PORT PORTC
#define ADC_0_CH3_PIN 10
#define ADC_0_CH3_PIN_AF 0
#define ADC_0_CH3 6
/* ADC 0 channel 4 pin config */
#define ADC_0_CH4_PORT PORTC
#define ADC_0_CH4_PIN 8
#define ADC_0_CH4_PIN_AF 0
#define ADC_0_CH4 4
/* ADC 0 channel 5 pin config */
#define ADC_0_CH5_PORT PORTC
#define ADC_0_CH5_PIN 9
#define ADC_0_CH5_PIN_AF 0
#define ADC_0_CH5 5
#define ADC_NUMOF (sizeof(adc_config) / sizeof(adc_config[0]))
/** @} */
/**

View File

@ -100,25 +100,17 @@ extern "C" {
/**
* @name ADC configuration
*
* We need to define the following fields:
* PIN, device (ADCx), channel
* @{
*/
#define ADC_NUMOF (1U)
#define ADC_0_EN 1
#define ADC_MAX_CHANNELS 2
#define ADC_CONFIG { \
{GPIO_PIN(PORT_B, 0), 0, 8}, \
{GPIO_PIN(PORT_B, 1), 0, 9} \
}
/* ADC 0 configuration */
#define ADC_0_DEV ADC1
#define ADC_0_CHANNELS 2
#define ADC_0_CLKEN() (RCC->APB2ENR |= RCC_APB2ENR_ADC1EN)
#define ADC_0_CLKDIS() (RCC->APB2ENR &= ~(RCC_APB2ENR_ADC1EN))
#define ADC_0_PORT GPIOB
#define ADC_0_PORT_CLKEN() (RCC->AHB1ENR |= RCC_AHB1ENR_GPIOBEN)
/* ADC 0 channel 0 pin config */
#define ADC_0_CH0 8
#define ADC_0_CH0_PIN 0
/* ADC 0 channel 1 pin config */
#define ADC_0_CH1 9
#define ADC_0_CH1_PIN 1
#define ADC_NUMOF (2)
/** @} */
/**

View File

@ -20,6 +20,8 @@
#ifndef MULLE_PERIPH_CONF_H_
#define MULLE_PERIPH_CONF_H_
#include "periph_cpu.h"
#ifdef __cplusplus
extern "C"
{
@ -50,6 +52,9 @@ extern "C"
#define CPU_INT_FAST_CLK_HZ 4000000u
/** Default System clock value */
#define DEFAULT_SYSTEM_CLOCK (CPU_XTAL32k_CLK_HZ * 2929u)
/* bus clock for the peripherals */
#define CLOCK_BUSCLOCK (DEFAULT_SYSTEM_CLOCK / 2)
/** @} */
/**
@ -135,89 +140,19 @@ extern "C"
* @name ADC configuration
* @{
*/
#define ADC_NUMOF (2U)
#define ADC_0_EN 1
#define ADC_1_EN 1
#define ADC_MAX_CHANNELS 6
static const adc_conf_t adc_config[] = {
/* dev, pin, channel */
{ ADC0, GPIO_UNDEF, 26 }, /* internal: temperature sensor */
{ ADC0, GPIO_UNDEF, 27 }, /* internal: band gap */
{ ADC0, GPIO_UNDEF, 29 }, /* internal: V_REFSH */
{ ADC0, GPIO_UNDEF, 30 }, /* internal: V_REFSL */
{ ADC1, GPIO_UNDEF, 0 }, /* connected to Mulle Vbat/2 on PGA1_DP */
{ ADC1, GPIO_UNDEF, 19 }, /* connected to Mulle Vchr/2 on PGA1_DM */
};
/* ADC 0 configuration */
#define ADC_0_DEV ADC0
#define ADC_0_CHANNELS 4
#define ADC_0_CLKEN() (BITBAND_REG32(SIM->SCGC6, SIM_SCGC6_ADC0_SHIFT) = 1)
#define ADC_0_CLKDIS() (BITBAND_REG32(SIM->SCGC6, SIM_SCGC6_ADC0_SHIFT) = 0)
#define ADC_0_PORT_CLKEN() /* no PORT pins configured */
#define ADC_0_MODULE_CLOCK SystemBusClock
/* ADC 0 channel 0 pin config */
#define ADC_0_CH0 26 /* Temp sensor channel */
#define ADC_0_CH0_PORT 0 /* this channel is not part of the pin mux on this CPU */
#define ADC_0_CH0_PIN 0
#define ADC_0_CH0_PIN_AF 0
/* ADC 0 channel 1 pin config */
#define ADC_0_CH1 27 /* Band gap channel */
#define ADC_0_CH1_PORT 0 /* this channel is not part of the pin mux on this CPU */
#define ADC_0_CH1_PIN 0
#define ADC_0_CH1_PIN_AF 0
/* ADC 0 channel 2 pin config */
#define ADC_0_CH2 29 /* V_REFSH */
#define ADC_0_CH2_PORT 0 /* this channel is not part of the pin mux on this CPU */
#define ADC_0_CH2_PIN 0
#define ADC_0_CH2_PIN_AF 0
/* ADC 0 channel 3 pin config */
#define ADC_0_CH3 30 /* V_REFSL */
#define ADC_0_CH3_PORT 0 /* this channel is not part of the pin mux on this CPU */
#define ADC_0_CH3_PIN 0
#define ADC_0_CH3_PIN_AF 0
/* ADC 0 channel 4 pin config */
#define ADC_0_CH4 4
#define ADC_0_CH4_PORT 0
#define ADC_0_CH4_PIN 0
#define ADC_0_CH4_PIN_AF 0
/* ADC 0 channel 5 pin config */
#define ADC_0_CH5 5
#define ADC_0_CH5_PORT 0
#define ADC_0_CH5_PIN 0
#define ADC_0_CH5_PIN_AF 0
/* ADC 1 configuration */
#define ADC_1_DEV ADC1
#define ADC_1_CHANNELS 2
#define ADC_1_CLKEN() (BITBAND_REG32(SIM->SCGC3, SIM_SCGC3_ADC1_SHIFT) = 1)
#define ADC_1_CLKDIS() (BITBAND_REG32(SIM->SCGC3, SIM_SCGC3_ADC1_SHIFT) = 0)
#define ADC_1_PORT_CLKEN() /* no PORT pins configured */
#define ADC_1_MODULE_CLOCK SystemBusClock
/* ADC 1 channel 0 pin config */
#define ADC_1_CH0 0 /* DADP0, connected externally to Mulle Vbat/2 on PGA1_DP */
#define ADC_1_CH0_PORT 0 /* this channel is not part of the pin mux on this CPU */
#define ADC_1_CH0_PIN 0
#define ADC_1_CH0_PIN_AF 0
/* ADC 1 channel 1 pin config */
#define ADC_1_CH1 19 /* AD19, connected externally to Mulle Vchr/2 on PGA1_DM */
#define ADC_1_CH1_PORT 0 /* this channel is not part of the pin mux on this CPU */
#define ADC_1_CH1_PIN 0
#define ADC_1_CH1_PIN_AF 0
/* ADC 1 channel 2 pin config */
#define ADC_1_CH2 12
#define ADC_1_CH2_PIN 0
#define ADC_1_CH2_PIN_AF 0
#define ADC_1_CH2_PORT 0
/* ADC 1 channel 3 pin config */
#define ADC_1_CH3 13
#define ADC_1_CH3_PIN 0
#define ADC_1_CH3_PIN_AF 0
#define ADC_1_CH3_PORT 0
/* ADC 1 channel 4 pin config */
#define ADC_1_CH4 14
#define ADC_1_CH4_PIN 0
#define ADC_1_CH4_PIN_AF 0
#define ADC_1_CH4_PORT 0
/* ADC 1 channel 5 pin config */
#define ADC_1_CH5 15
#define ADC_1_CH5_PIN 0
#define ADC_1_CH5_PIN_AF 0
#define ADC_1_CH5_PORT 0
#define ADC_NUMOF (sizeof(adc_config) / sizeof(adc_config[0]))
/** @} */
/**
* @name PWM configuration
* @{

View File

@ -80,6 +80,15 @@ static const timer_conf_t timer_config[] = {
#define UART_PIN_CTS 10
/** @} */
/**
* @brief ADC configuration
*
* The configuration consists simply of a list of channels that should be used
* @{
*/
#define ADC_NUMOF (0)
/** @} */
/**
* @name Radio device configuration
*

View File

@ -118,6 +118,16 @@ static const timer_conf_t timer_config[] = {
#define SPI_1_PIN_MOSI 18
/** @} */
/**
* @brief ADC configuration
*
* The configuration consists simply of a list of channels that should be used
* @{
*/
#define ADC_NUMOF (0)
/** @} */
#ifdef __cplusplus
}
#endif

View File

@ -19,6 +19,8 @@
#ifndef PERIPH_CONF_H_
#define PERIPH_CONF_H_
#include "periph_cpu.h"
#ifdef __cplusplus
extern "C" {
#endif
@ -100,6 +102,13 @@ extern "C" {
#define RTC_NUMOF (1U)
/** @} */
/**
* @brief ADC configuration
* @{
*/
#define ADC_NUMOF (0)
/** @} */
#ifdef __cplusplus
}
#endif

View File

@ -161,6 +161,12 @@ static const uart_conf_t uart_config[] = {
#define I2C_0_SDA_CLKEN() (RCC->AHB1ENR |= RCC_AHB1ENR_GPIOBEN)
/** @} */
/**
* @brief ADC configuration
* @{
*/
#define ADC_NUMOF (0)
/** @} */
#ifdef __cplusplus
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2014 Freie Universität Berlin
* Copyright (C) 2014-2016 Freie Universität Berlin
* Copyright (C) 2014 PHYTEC Messtechnik GmbH
*
* This file is subject to the terms and conditions of the GNU Lesser General
@ -22,7 +22,7 @@
#ifndef PERIPH_CONF_H_
#define PERIPH_CONF_H_
#include "cpu_conf.h"
#include "periph_cpu.h"
#ifdef __cplusplus
extern "C"
@ -47,6 +47,7 @@ extern "C"
#define KINETIS_MCG_PLL_FREQ 48000000
#define CLOCK_CORECLOCK KINETIS_MCG_PLL_FREQ
#define CLOCK_BUSCLOCK CLOCK_CORECLOCK
/** @} */
@ -115,55 +116,23 @@ extern "C"
#define UART_1_AF 3
/** @} */
/**
* @name ADC configuration
* @{
*/
#define ADC_NUMOF (1U)
#define ADC_0_EN 1
#define ADC_MAX_CHANNELS 6
static const adc_conf_t adc_config[] = {
/* dev, pin, channel */
{ ADC0, GPIO_PIN(PORT_E, 2), 1 },
{ ADC0, GPIO_PIN(PORT_E, 3), 1 },
{ ADC0, GPIO_PIN(PORT_D, 7), 22 },
{ ADC0, GPIO_PIN(PORT_D, 5), 6 },
{ ADC0, GPIO_PIN(PORT_E, 0), 10 },
{ ADC0, GPIO_PIN(PORT_E, 1), 11 },
};
/* ADC 0 configuration */
#define ADC_0_DEV ADC0
#define ADC_0_MODULE_CLOCK CLOCK_CORECLOCK
#define ADC_0_CHANNELS 6
#define ADC_0_CLKEN() (SIM->SCGC6 |= (SIM_SCGC6_ADC0_MASK))
#define ADC_0_CLKDIS() (SIM->SCGC6 &= ~(SIM_SCGC6_ADC0_MASK))
#define ADC_0_PORT_CLKEN() (SIM->SCGC5 |= (SIM_SCGC5_PORTD_MASK | SIM_SCGC5_PORTE_MASK))
/* ADC 0 channel 0 pin config */
#define ADC_0_CH0 1
#define ADC_0_CH0_PIN 2
#define ADC_0_CH0_PIN_AF 0
#define ADC_0_CH0_PORT PORTE
/* ADC 0 channel 1 pin config */
#define ADC_0_CH1 1 /* PTE3 uses the same ADC_CH as PTE2, in single channel mode only one of them can be selected */
#define ADC_0_CH1_PIN 3
#define ADC_0_CH1_PIN_AF 0
#define ADC_0_CH1_PORT PORTE
/* ADC 0 channel 2 pin config */
#define ADC_0_CH2 22
#define ADC_0_CH2_PIN 7
#define ADC_0_CH2_PIN_AF 0
#define ADC_0_CH2_PORT PORTD
/* ADC 0 channel 3 pin config */
#define ADC_0_CH3 6
#define ADC_0_CH3_PIN 5
#define ADC_0_CH3_PIN_AF 0
#define ADC_0_CH3_PORT PORTD
/* ADC 0 channel 4 pin config */
#define ADC_0_CH4 10
#define ADC_0_CH4_PIN 0
#define ADC_0_CH4_PIN_AF 0
#define ADC_0_CH4_PORT PORTE
/* ADC 0 channel 5 pin config */
#define ADC_0_CH5 11
#define ADC_0_CH5_PIN 1
#define ADC_0_CH5_PIN_AF 0
#define ADC_0_CH5_PORT PORTE
#define ADC_NUMOF (sizeof(adc_config) / sizeof(adc_config[0]))
/** @} */
/**
* @name PWM configuration
* @{

View File

@ -82,6 +82,15 @@ static const timer_conf_t timer_config[] = {
#define UART_PIN_CTS 10
/** @} */
/**
* @brief ADC configuration
*
* The configuration consists simply of a list of channels that should be used
* @{
*/
#define ADC_NUMOF (0)
/** @} */
/**
* @name Radio device configuration
*

View File

@ -102,19 +102,13 @@ static const timer_conf_t timer_config[] = {
/** @} */
/**
* @name ADC configuration
* @brief ADC configuration
*
* The configuration consists simply of a list of channels that should be used
* @{
*/
#define ADC_NUMOF (1U)
#define ADC_0_EN 1
#define ADC_MAX_CHANNELS 4
/* ADC 0 device configuration */
#define ADC_0_CHANNELS 4
#define ADC_0_CH0 ADC_CONFIG_PSEL_AnalogInput0
#define ADC_0_CH1 ADC_CONFIG_PSEL_AnalogInput1
#define ADC_0_CH2 ADC_CONFIG_PSEL_AnalogInput2
#define ADC_0_CH3 ADC_CONFIG_PSEL_AnalogInput3
#define ADC_CONFIG {0, 1, 2, 3}
#define ADC_NUMOF (4)
/** @} */
/**

View File

@ -19,6 +19,8 @@
#ifndef PERIPH_CONF_H_
#define PERIPH_CONF_H_
#include "periph_cpu.h"
#ifdef __cplusplus
extern "C" {
#endif
@ -89,38 +91,22 @@ extern "C" {
/** @} */
/**
* @name ADC configuration
* @brief ADC configuration
*
* We need to configure the following values:
* [ pin, channel ]
* @{
*/
#define ADC_NUMOF (1U)
#define ADC_0_EN 1
#define ADC_MAX_CHANNELS 6
#define ADC_CONFIG { \
{ GPIO_PIN(PORT_C, 0), 10 },\
{ GPIO_PIN(PORT_C, 1), 11 },\
{ GPIO_PIN(PORT_C, 2), 12 },\
{ GPIO_PIN(PORT_C, 3), 13 },\
{ GPIO_PIN(PORT_C, 4), 14 },\
{ GPIO_PIN(PORT_C, 5), 15 } \
}
/* ADC 0 configuration */
#define ADC_0_DEV ADC1
#define ADC_0_CHANNELS 6
#define ADC_0_CLKEN() (RCC->APB2ENR |= RCC_APB2ENR_ADCEN)
#define ADC_0_CLKDIS() (RCC->APB2ENR &= ~(RCC_APB2ENR_ADCEN))
#define ADC_0_PORT GPIOC
#define ADC_0_PORT_CLKEN() (RCC->AHBENR |= RCC_AHBENR_GPIOCEN)
/* ADC 0 channel 0 pin config */
#define ADC_0_CH0 10
#define ADC_0_CH0_PIN 0
/* ADC 0 channel 1 pin config */
#define ADC_0_CH1 11
#define ADC_0_CH1_PIN 1
/* ADC 0 channel 2 pin config */
#define ADC_0_CH2 12
#define ADC_0_CH2_PIN 2
/* ADC 0 channel 3 pin config */
#define ADC_0_CH3 13
#define ADC_0_CH3_PIN 3
/* ADC 0 channel 4 pin config */
#define ADC_0_CH4 14
#define ADC_0_CH4_PIN 4
/* ADC 0 channel 5 pin config */
#define ADC_0_CH5 15
#define ADC_0_CH5_PIN 5
#define ADC_NUMOF (6)
/** @} */
/**

View File

@ -116,42 +116,20 @@ static const uart_conf_t uart_config[] = {
/** @} */
/**
* @name ADC configuration
* @brief ADC configuration
*
* We need to define the following fields:
* PIN, device (ADCx), channel
* @{
*/
#define ADC_NUMOF (2U)
#define ADC_0_EN 1
#define ADC_1_EN 1
#define ADC_MAX_CHANNELS 2
#define ADC_CONFIG { \
{GPIO_PIN(PORT_A, 1), 0, 1}, \
{GPIO_PIN(PORT_A, 4), 0, 4}, \
{GPIO_PIN(PORT_C, 1), 1, 11}, \
{GPIO_PIN(PORT_C, 2), 1, 12} \
}
/* ADC 0 configuration */
#define ADC_0_DEV ADC1
#define ADC_0_CHANNELS 2
#define ADC_0_CLKEN() (RCC->APB2ENR |= RCC_APB2ENR_ADC1EN)
#define ADC_0_CLKDIS() (RCC->APB2ENR &= ~(RCC_APB2ENR_ADC1EN))
#define ADC_0_PORT GPIOA
#define ADC_0_PORT_CLKEN() (RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN)
/* ADC 0 channel 0 pin config */
#define ADC_0_CH0 1
#define ADC_0_CH0_PIN 1
/* ADC 0 channel 1 pin config */
#define ADC_0_CH1 4
#define ADC_0_CH1_PIN 4
/* ADC 1 configuration */
#define ADC_1_DEV ADC2
#define ADC_1_CHANNELS 2
#define ADC_1_CLKEN() (RCC->APB2ENR |= RCC_APB2ENR_ADC2EN)
#define ADC_1_CLKDIS() (RCC->APB2ENR &= ~(RCC_APB2ENR_ADC2EN))
#define ADC_1_PORT GPIOC
#define ADC_1_PORT_CLKEN() (RCC->AHB1ENR |= RCC_AHB1ENR_GPIOCEN)
/* ADC 1 channel 0 pin config */
#define ADC_1_CH0 11
#define ADC_1_CH0_PIN 1
/* ADC 1 channel 1 pin config */
#define ADC_1_CH1 12
#define ADC_1_CH1_PIN 2
#define ADC_NUMOF (4)
/** @} */
/**

View File

@ -266,15 +266,6 @@ extern "C" {
#define PWM_1_CH2_AF 0x81
/* @} */
/**
* @brief ADC configuration
* @{
*/
#define ADC_NUMOF (1U)
#define ADC_0_EN 1
#define ADC_MAX_CHANNELS 8
/* @} */
#ifdef __cplusplus
}
#endif

View File

@ -100,19 +100,13 @@ static const timer_conf_t timer_config[] = {
/** @} */
/**
* @name ADC configuration
* @brief ADC configuration
*
* The configuration consists simply of a list of channels that should be used
* @{
*/
#define ADC_NUMOF (1U)
#define ADC_0_EN 1
#define ADC_MAX_CHANNELS 4
/* ADC 0 device configuration */
#define ADC_0_CHANNELS 4
#define ADC_0_CH0 ADC_CONFIG_PSEL_AnalogInput4
#define ADC_0_CH1 ADC_CONFIG_PSEL_AnalogInput5
#define ADC_0_CH2 ADC_CONFIG_PSEL_AnalogInput6
#define ADC_0_CH3 ADC_CONFIG_PSEL_AnalogInput7
#define ADC_CONFIG {4, 5, 6, 7}
#define ADC_NUMOF (4)
/** @} */
/**

View File

@ -21,6 +21,7 @@
#include <stdint.h>
#include "cpu.h"
#include "mcg.h"
#include "cpu_conf.h"
#define SIM_CLKDIV1_60MHZ (SIM_CLKDIV1_OUTDIV1(0) | \

View File

@ -32,8 +32,6 @@
#error "undefined CPU_MODEL"
#endif
#include "mcg.h"
#ifdef __cplusplus
extern "C"
{

View File

@ -100,7 +100,6 @@
#ifndef __MCG_CPU_H
#define __MCG_CPU_H
#include "cpu_conf.h"
#include "periph_conf.h"
#if KINETIS_CPU_USE_MCG

View File

@ -109,6 +109,31 @@ enum {
GPIO_PORTS_NUMOF /**< overall number of available ports */
};
/**
* @brief Override default ADC resolution values
* @{
*/
#define HAVE_ADC_RES_T
typedef enum {
ADC_RES_6BIT = (0xfe), /**< not supported */
ADC_RES_8BIT = ADC_CFG1_MODE(0), /**< ADC resolution: 8 bit */
ADC_RES_10BIT = ADC_CFG1_MODE(2), /**< ADC resolution: 10 bit */
ADC_RES_12BIT = ADC_CFG1_MODE(1), /**< ADC resolution: 12 bit */
ADC_RES_14BIT = (0xff), /**< ADC resolution: 14 bit */
ADC_RES_16BIT = ADC_CFG1_MODE(3) /**< ADC resolution: 16 bit */
} adc_res_t;
/** @} */
/**
* @brief CPU specific ADC configuration
*/
typedef struct {
ADC_Type *dev; /**< ADC device */
gpio_t pin; /**< pin to use, set to GPIO_UNDEF for internal
* channels */
uint8_t chan; /**< ADC channel */
} adc_conf_t;
/**
* @brief CPU internal function for initializing PORTs
*

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2014 Freie Universität Berlin
* Copyright (C) 2014-2016 Freie Universität Berlin
* Copyright (C) 2014 PHYTEC Messtechnik GmbH
* Copyright (C) 2015 Eistec AB
*
@ -25,18 +25,68 @@
#include <stdio.h>
#include "cpu.h"
#include "mutex.h"
#include "periph/adc.h"
#include "periph_conf.h"
/* guard in case that no ADC device is defined */
#if ADC_NUMOF
/**
* @brief Maximum clock speed
*
* The ADC clock speed must be configured to be >2MHz and <12MHz in order for
* the ADC to work. For ADC calibration to work as intended, the ADC clock speed
* must further no be >4MHz, so we target a ADC clock speed > 2 and <4MHz.
*/
#define ADC_MAX_CLK (4000000U)
typedef struct {
int max_value;
int bits;
} adc_config_t;
static mutex_t locks[] = {
MUTEX_INIT,
#ifdef ADC1
MUTEX_INIT,
#endif
};
adc_config_t adc_config[ADC_NUMOF];
static inline ADC_Type *dev(adc_t line)
{
return adc_config[line].dev;
}
static inline int dev_num(adc_t line)
{
if (dev(line) == ADC0) {
return 0;
}
#ifdef ADC1
else if (dev(line) == ADC1) {
return 1;
}
#endif
return -1;
}
static inline void prep(adc_t line)
{
if (dev(line) == ADC0) {
BITBAND_REG32(SIM->SCGC6, SIM_SCGC6_ADC0_SHIFT) = 1;
}
#ifdef ADC1
else {
BITBAND_REG32(SIM->SCGC3, SIM_SCGC3_ADC1_SHIFT) = 1;
}
#endif
mutex_lock(&locks[dev_num(line)]);
}
static inline void done(adc_t line)
{
if (dev(line) == ADC0) {
BITBAND_REG32(SIM->SCGC6, SIM_SCGC6_ADC0_SHIFT) = 0;
}
#ifdef ADC1
else {
BITBAND_REG32(SIM->SCGC3, SIM_SCGC3_ADC1_SHIFT) = 0;
}
#endif
mutex_unlock(&locks[dev_num(line)]);
}
/**
* @brief Perform ADC calibration routine.
@ -44,34 +94,31 @@ adc_config_t adc_config[ADC_NUMOF];
* This is a recipe taken straight from the Kinetis K60 reference manual. It has
* been tested on MK60DN512VLL10.
*
* @param[in] ADC_ptr Pointer to ADC device to operate on.
* @param[in] dev Pointer to ADC device to operate on.
*
* @return 0 on success
* @return <0 on errors
*/
int kinetis_adc_calibrate(ADC_Type *ADC_ptr)
int kinetis_adc_calibrate(ADC_Type *dev)
{
uint16_t cal;
ADC_ptr->SC3 |= ADC_SC3_CAL_MASK;
dev->SC3 |= ADC_SC3_CAL_MASK;
while (ADC_ptr->SC3 & ADC_SC3_CAL_MASK); /* wait for calibration to finish */
while (dev->SC3 & ADC_SC3_CAL_MASK) {} /* wait for calibration to finish */
while (!(ADC_ptr->SC1[0] & ADC_SC1_COCO_MASK));
while (!(dev->SC1[0] & ADC_SC1_COCO_MASK)) {}
if (ADC_ptr->SC3 & ADC_SC3_CALF_MASK) {
if (dev->SC3 & ADC_SC3_CALF_MASK) {
/* calibration failed for some reason, possibly SC2[ADTRG] is 1 ? */
return -1;
}
/*
* Following the steps in the reference manual:
*/
/* From the reference manual */
/* 1. Initialize or clear a 16-bit variable in RAM. */
/* 2. Add the plus-side calibration results CLP0, CLP1, CLP2, CLP3, CLP4, and
* CLPS to the variable. */
cal = ADC_ptr->CLP0 + ADC_ptr->CLP1 + ADC_ptr->CLP2 + ADC_ptr->CLP3 +
ADC_ptr->CLP4 + ADC_ptr->CLPS;
/* 2. Add the plus-side calibration results CLP0, CLP1, CLP2, CLP3, CLP4,
* and CLPS to the variable. */
cal = dev->CLP0 + dev->CLP1 + dev->CLP2 + dev->CLP3 + dev->CLP4 + dev->CLPS;
/* 3. Divide the variable by two. */
cal /= 2;
/* 4. Set the MSB of the variable. */
@ -82,345 +129,88 @@ int kinetis_adc_calibrate(ADC_Type *ADC_ptr)
* We ignore the above optimization suggestion, we most likely only perform
* this calibration on startup and it will only save nanoseconds. */
/* 6. Store the value in the plus-side gain calibration register PG. */
ADC_ptr->PG = cal;
dev->PG = cal;
/* 7. Repeat the procedure for the minus-side gain calibration value. */
cal = ADC_ptr->CLM0 + ADC_ptr->CLM1 + ADC_ptr->CLM2 + ADC_ptr->CLM3 +
ADC_ptr->CLM4 + ADC_ptr->CLMS;
cal = dev->CLM0 + dev->CLM1 + dev->CLM2 + dev->CLM3 + dev->CLM4 + dev->CLMS;
cal /= 2;
cal |= (1 << 15);
ADC_ptr->MG = cal;
dev->MG = cal;
return 0;
}
int adc_init(adc_t dev, adc_precision_t precision)
int adc_init(adc_t line)
{
ADC_Type *adc = 0;
PORT_Type *port[ADC_MAX_CHANNELS];
uint8_t pins[ADC_MAX_CHANNELS];
uint8_t af[ADC_MAX_CHANNELS];
int channels = 0;
uint32_t mode = 0;
uint32_t div = 0;
int i = 0;
uint32_t clock = 0;
adc_poweron(dev);
switch (dev) {
#if ADC_0_EN
case ADC_0:
adc = ADC_0_DEV;
port[0] = ADC_0_CH0_PORT;
port[1] = ADC_0_CH1_PORT;
port[2] = ADC_0_CH2_PORT;
port[3] = ADC_0_CH3_PORT;
port[4] = ADC_0_CH4_PORT;
port[5] = ADC_0_CH5_PORT;
pins[0] = ADC_0_CH0_PIN;
pins[1] = ADC_0_CH1_PIN;
pins[2] = ADC_0_CH2_PIN;
pins[3] = ADC_0_CH3_PIN;
pins[4] = ADC_0_CH4_PIN;
pins[5] = ADC_0_CH5_PIN;
af[0] = ADC_0_CH0_PIN_AF;
af[1] = ADC_0_CH1_PIN_AF;
af[2] = ADC_0_CH2_PIN_AF;
af[3] = ADC_0_CH3_PIN_AF;
af[4] = ADC_0_CH4_PIN_AF;
af[5] = ADC_0_CH5_PIN_AF;
channels = ADC_0_CHANNELS;
clock = ADC_0_MODULE_CLOCK;
ADC_0_PORT_CLKEN();
break;
#endif
#if ADC_1_EN
case ADC_1:
adc = ADC_1_DEV;
port[0] = ADC_1_CH0_PORT;
port[1] = ADC_1_CH1_PORT;
port[2] = ADC_1_CH2_PORT;
port[3] = ADC_1_CH3_PORT;
port[4] = ADC_1_CH4_PORT;
port[5] = ADC_1_CH5_PORT;
pins[0] = ADC_1_CH0_PIN;
pins[1] = ADC_1_CH1_PIN;
pins[2] = ADC_1_CH2_PIN;
pins[3] = ADC_1_CH3_PIN;
pins[4] = ADC_1_CH4_PIN;
pins[5] = ADC_1_CH5_PIN;
af[0] = ADC_1_CH0_PIN_AF;
af[1] = ADC_1_CH1_PIN_AF;
af[2] = ADC_1_CH2_PIN_AF;
af[3] = ADC_1_CH3_PIN_AF;
af[4] = ADC_1_CH4_PIN_AF;
af[5] = ADC_1_CH5_PIN_AF;
channels = ADC_1_CHANNELS;
clock = ADC_1_MODULE_CLOCK;
ADC_1_PORT_CLKEN();
break;
#endif
default:
return -1;
}
if (channels > ADC_MAX_CHANNELS) {
/* make sure the given line is valid */
if (line >= ADC_NUMOF) {
return -1;
}
/* set precision, these numbers are valid for the K60 */
switch (precision) {
case ADC_RES_6BIT:
/* Not supported by hardware, use 8 bit mode. */
mode = ADC_CFG1_MODE(0);
adc_config[dev].bits = 8;
break;
/* prepare the device: lock and power on */
prep(line);
case ADC_RES_8BIT:
mode = ADC_CFG1_MODE(0);
adc_config[dev].bits = 8;
break;
case ADC_RES_10BIT:
mode = ADC_CFG1_MODE(2);
adc_config[dev].bits = 10;
break;
case ADC_RES_12BIT:
mode = ADC_CFG1_MODE(1);
adc_config[dev].bits = 12;
break;
case ADC_RES_14BIT:
/* Not supported by hardware, use 16 bit mode. */
mode = ADC_CFG1_MODE(3);
adc_config[dev].bits = 16;
break;
case ADC_RES_16BIT:
mode = ADC_CFG1_MODE(3);
adc_config[dev].bits = 16;
break;
}
adc_config[dev].max_value = (1 << adc_config[dev].bits) - 1;
for (i = 0; i < channels; i++) {
/* Check whether we need to set the pin mux for this channel. */
if (port[i] != NULL) {
port[i]->PCR[pins[i]] = PORT_PCR_MUX(af[i]);
}
/* configure the connected pin mux */
if (adc_config[line].pin != GPIO_UNDEF) {
gpio_init_port(adc_config[line].pin, GPIO_AF_ANALOG);
}
/* The ADC requires at least 2 MHz module clock for full accuracy, and less
* than 12 MHz */
/* For the calibration it is important that the ADC clock is <= 4 MHz */
if (clock > 4000000 * 8) {
/* Need to divide by 16, we set the clock input to BusClock/2 and
* divide clock by 8 (the maximum divider) */
div = ADC_CFG1_ADIV(3) | ADC_CFG1_ADICLK(1);
}
else if (clock > 4000000 * 4) {
/* divide clock by 8 */
div = ADC_CFG1_ADIV(3);
}
else if (clock > 4000000 * 2) {
/* divide clock by 4 */
div = ADC_CFG1_ADIV(2);
}
else if (clock > 4000000 * 1) {
/* divide clock by 2 */
div = ADC_CFG1_ADIV(1);
uint32_t adiv;
int i = 4;
if (CLOCK_BUSCLOCK > (ADC_MAX_CLK * 8)) {
adiv = ADC_CFG1_ADIV(3) | ADC_CFG1_ADICLK(1);
}
else {
/* no clock divider */
div = ADC_CFG1_ADIV(0);
while ((i > 0) && (CLOCK_BUSCLOCK < (ADC_MAX_CLK * i))) {
i--;
}
adiv = ADC_CFG1_ADIV(i - 1);
}
/* set configuration register 1: clocking and precision */
/* Set long sample time */
adc->CFG1 = ADC_CFG1_ADLSMP_MASK | mode | div;
dev(line)->CFG1 = ADC_CFG1_ADLSMP_MASK | adiv;
/* select ADxxb channels, longest sample time (20 extra ADC cycles) */
adc->CFG2 = ADC_CFG2_MUXSEL_MASK | ADC_CFG2_ADLSTS(0);
dev(line)->CFG2 = ADC_CFG2_MUXSEL_MASK | ADC_CFG2_ADLSTS(0);
/* select software trigger, external ref pins */
adc->SC2 = ADC_SC2_REFSEL(0);
dev(line)->SC2 = ADC_SC2_REFSEL(0);
/* select hardware average over 32 samples */
adc->SC3 = ADC_SC3_AVGE_MASK | ADC_SC3_AVGS(3);
dev(line)->SC3 = ADC_SC3_AVGE_MASK | ADC_SC3_AVGS(3);
/* set an (arbitrary) input channel, single-ended mode */
adc->SC1[0] = ADC_SC1_ADCH(ADC_0_CH0);
adc->SC1[1] = ADC_SC1_ADCH(ADC_0_CH0);
dev(line)->SC1[0] = ADC_SC1_ADCH(0);
/* perform calibration routine */
if (kinetis_adc_calibrate(adc) != 0) {
int res = kinetis_adc_calibrate(dev(line));
done(line);
return res;
}
int adc_sample(adc_t line, adc_res_t res)
{
int sample;
/* check if resolution is applicable */
if (res > 0xf0) {
return -1;
}
return 0;
}
int adc_sample(adc_t dev, int channel)
{
ADC_Type *adc = 0;
switch (dev) {
#if ADC_0_EN
case ADC_0:
adc = ADC_0_DEV;
/* start single conversion on corresponding channel */
switch (channel) {
case 0:
adc->SC1[0] = ADC_SC1_ADCH(ADC_0_CH0);
break;
case 1:
adc->SC1[0] = ADC_SC1_ADCH(ADC_0_CH1);
break;
case 2:
adc->SC1[0] = ADC_SC1_ADCH(ADC_0_CH2);
break;
case 3:
adc->SC1[0] = ADC_SC1_ADCH(ADC_0_CH3);
break;
case 4:
adc->SC1[0] = ADC_SC1_ADCH(ADC_0_CH4);
break;
case 5:
adc->SC1[0] = ADC_SC1_ADCH(ADC_0_CH5);
break;
default:
return -1;
}
break;
#endif
#if ADC_1_EN
case ADC_1:
adc = ADC_1_DEV;
/* start single conversion on corresponding channel */
switch (channel) {
case 0:
adc->SC1[0] = ADC_SC1_ADCH(ADC_1_CH0);
break;
case 1:
adc->SC1[0] = ADC_SC1_ADCH(ADC_1_CH1);
break;
case 2:
adc->SC1[0] = ADC_SC1_ADCH(ADC_1_CH2);
break;
case 3:
adc->SC1[0] = ADC_SC1_ADCH(ADC_1_CH3);
break;
case 4:
adc->SC1[0] = ADC_SC1_ADCH(ADC_1_CH4);
break;
case 5:
adc->SC1[0] = ADC_SC1_ADCH(ADC_1_CH5);
break;
default:
return -1;
}
break;
#endif
}
/* lock and power on the device */
prep(line);
/* set resolution */
dev(line)->CFG1 &= ~(ADC_CFG1_MODE_MASK);
dev(line)->CFG1 |= (res);
/* select the channel that is sampled */
dev(line)->SC1[0] = adc_config[line].chan;
/* wait until conversion is complete */
/* TODO: Use interrupts and yield the thread */
while (!(adc->SC1[0] & ADC_SC1_COCO_MASK));
while (!(dev(line)->SC1[0] & ADC_SC1_COCO_MASK)) {}
/* read and return result */
return (int)adc->R[0];
sample = (int)dev(line)->R[0];
/* power off and unlock the device */
done(line);
return sample;
}
void adc_poweron(adc_t dev)
{
switch (dev) {
#if ADC_0_EN
case ADC_0:
ADC_0_CLKEN();
break;
#endif
#if ADC_1_EN
case ADC_1:
ADC_1_CLKEN();
break;
#endif
}
}
void adc_poweroff(adc_t dev)
{
switch (dev) {
#if ADC_0_EN
case ADC_0:
ADC_0_CLKDIS();
break;
#endif
#if ADC_1_EN
case ADC_1:
ADC_1_CLKDIS();
break;
#endif
}
}
int adc_map(adc_t dev, int value, int min, int max)
{
int scale = max - min;
/* NB: There is additional room for the multiplication result if using the
* actual precision setting of the ADC as the limit in this if statement: */
if (scale < (1 << 16)) {
/* The ADCs on these CPUs are limited to 16 bits, the result of
* value x scale will be 31 bits long or less. We use the upper part
* of a 32 bit word when scaling */
int32_t tmp = value * scale;
/* Divide by ADC range to get the scaled result */
return (tmp / (1 << adc_config[dev].bits));
}
else {
/* Target scale is too large to use int32_t as an in between result */
int64_t tmp = scale;
/* Make sure the compiler does not generate code which will truncate the
* result. */
tmp *= value;
/* Divide by ADC range to get the scaled result */
tmp /= (1 << adc_config[dev].bits);
return tmp;
}
}
float adc_mapf(adc_t dev, int value, float min, float max)
{
return ((max - min) / ((float)adc_config[dev].max_value)) * value;
}
#endif /* ADC_NUMOF */

View File

@ -21,6 +21,7 @@
#include <stdint.h>
#include "cpu.h"
#include "mcg.h"
#include "cpu_conf.h"
#define FLASH_BASE (0x00000000)

View File

@ -37,8 +37,6 @@
#error "undefined CPU_MODEL"
#endif
#include "mcg.h"
#ifdef __cplusplus
extern "C"
{

View File

@ -52,7 +52,6 @@ typedef enum {
} gpio_pp_t;
/** @} */
/**
* @brief Override values for pin direction configuration
* @{
@ -88,6 +87,19 @@ enum {
PORT_F = 5, /**< port F */
};
/**
* @brief Override resolution options
*/
#define HAVE_ADC_RES_T
typedef enum {
ADC_RES_6BIT = 0xa00, /**< not supported by hardware */
ADC_RES_8BIT = 0xb00, /**< not supported by hardware */
ADC_RES_10BIT = ADC_RES_10BIT_S, /**< ADC resolution: 10 bit */
ADC_RES_12BIT = ADC_RES_12BIT_S, /**< ADC resolution: 12 bit */
ADC_RES_14BIT = 0xc00, /**< not supported by hardware */
ADC_RES_16BIT = 0xd00, /**< not supported by hardware */
} adc_res_t;
#ifdef __cplusplus
}
#endif

View File

@ -13,6 +13,8 @@
* @file
* @brief Low-level ADC driver implementation
*
* The current ADC driver implementation only supports ADC0.
*
* @author Marc Poulhiès <dkm@kataplop.net>
*
* @}
@ -22,152 +24,109 @@
#include <string.h>
#include "cpu.h"
#include "mutex.h"
#include "periph/adc.h"
#include "periph_conf.h"
#if ADC_NUMOF
/*
* @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;
};
static const struct adc_gpio_cfg_s adc0_gpio[ADC_MAX_CHANNELS] = {
{ 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_PORTE_BASE, SYSCTL_PERIPH_GPIOD, GPIO_PIN_3 }, // AIN4
{ GPIO_PORTE_BASE, SYSCTL_PERIPH_GPIOD, GPIO_PIN_2 }, // AIN5
{ GPIO_PORTE_BASE, SYSCTL_PERIPH_GPIOD, GPIO_PIN_1 }, // AIN6
{ GPIO_PORTE_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_PORTE_BASE, SYSCTL_PERIPH_GPIOB, GPIO_PIN_4 }, // AIN10
{ GPIO_PORTE_BASE, SYSCTL_PERIPH_GPIOB, GPIO_PIN_5 }, // AIN11
/**
* @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_PORTE_BASE, SYSCTL_PERIPH_GPIOD, GPIO_PIN_3 }, /**< AIN4 */
{ GPIO_PORTE_BASE, SYSCTL_PERIPH_GPIOD, GPIO_PIN_2 }, /**< AIN5 */
{ GPIO_PORTE_BASE, SYSCTL_PERIPH_GPIOD, GPIO_PIN_1 }, /**< AIN6 */
{ GPIO_PORTE_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_PORTE_BASE, SYSCTL_PERIPH_GPIOB, GPIO_PIN_4 }, /**< AIN10 */
{ GPIO_PORTE_BASE, SYSCTL_PERIPH_GPIOB, GPIO_PIN_5 }, /**< AIN11 */
};
/*
* We only support ADC0 for now
/**
* @brief Lock to prevent concurrent access to the ADC
*/
#define ADC_0_SYSCTL SYSCTL_PERIPH_ADC0
#define ADC_0_GPIO adc0_gpio
#define ADC_0_BASE ADC0_BASE
#define ADC_0_SEQ 3
static mutex_t lock = MUTEX_INIT;
int adc_init(adc_t dev, adc_precision_t precision)
static inline void prep(void)
{
unsigned long adc_base;
unsigned long adc_seq;
switch (dev) {
#if ADC_0_EN
case ADC_0:
adc_base = ADC_0_BASE;
adc_seq = ADC_0_SEQ;
break;
#endif
}
ROM_SysCtlADCSpeedSet(SYSCTL_ADCSPEED_125KSPS);
adc_poweron(dev);
ROM_ADCHardwareOversampleConfigure(adc_base, 64);
ROM_ADCSequenceDisable(adc_base, adc_seq);
return 0;
mutex_lock(&lock);
ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
}
int adc_sample(adc_t dev, int channel)
static inline void done(void)
{
int value[2];
unsigned long adc_base;
unsigned long adc_seq;
unsigned long adc_gpio_port = 0;
unsigned long adc_gpio_pin = 0;
unsigned long adc_gpio_sysctl = 0;
ROM_SysCtlPeripheralDisable(SYSCTL_PERIPH_ADC0);
mutex_unlock(&lock);
}
if (channel >= ADC_MAX_CHANNELS) {
int adc_init(adc_t line)
{
/* make sure the given ADC line is valid */
if (line >= ADC_NUMOF) {
return -1;
}
switch (dev) {
#if ADC_0_EN
case ADC_0:
adc_base = ADC_0_BASE;
adc_seq = ADC_0_SEQ;
prep();
adc_gpio_port = ADC_0_GPIO[channel].gpio_base;
adc_gpio_sysctl = ADC_0_GPIO[channel].gpio_sysctl;
adc_gpio_pin = ADC_0_GPIO[channel].gpio_pin;
break;
#endif
}
ROM_SysCtlPeripheralEnable(adc_gpio_sysctl);
ROM_GPIOPinTypeADC(adc_gpio_port, adc_gpio_pin);
ROM_SysCtlADCSpeedSet(SYSCTL_ADCSPEED_125KSPS);
ROM_ADCHardwareOversampleConfigure(ADC0_BASE, OVERSAMPLE);
ROM_ADCSequenceDisable(adc_base, adc_seq);
ROM_ADCIntClear(adc_base, adc_seq);
ROM_SysCtlPeripheralEnable(adc0_gpio[line].gpio_sysctl);
ROM_GPIOPinTypeADC(adc0_gpio[line].gpio_base, adc0_gpio[line].gpio_pin);
ROM_ADCSequenceConfigure(adc_base, adc_seq, ADC_TRIGGER_PROCESSOR, 0);
done();
ROM_ADCSequenceStepConfigure(adc_base, adc_seq, 0, channel | ADC_CTL_IE | ADC_CTL_END);
ROM_ADCSequenceEnable(adc_base, adc_seq);
ROM_ADCIntClear(adc_base, adc_seq);
ROM_ADCProcessorTrigger(adc_base, adc_seq);
while (!ROM_ADCIntStatus(adc_base, adc_seq, false)) {
}
ROM_ADCIntClear(adc_base, adc_seq);
ROM_ADCSequenceDataGet(adc_base, adc_seq, (unsigned long *) value);
return value[0];
}
void adc_poweron(adc_t dev)
{
unsigned long adc_sysctl;
switch (dev) {
#if ADC_0_EN
case ADC_0:
adc_sysctl = ADC_0_SYSCTL;
break;
#endif
}
ROM_SysCtlPeripheralEnable(adc_sysctl);
}
void adc_poweroff(adc_t dev)
{
unsigned long adc_sysctl;
switch (dev) {
#if ADC_0_EN
case ADC_0:
adc_sysctl = ADC_0_SYSCTL;
break;
#endif
}
ROM_SysCtlPeripheralDisable(adc_sysctl);
}
/*
* Currently not supported
*/
int adc_map(adc_t dev, int value, int min, int max)
{
return 0;
}
/*
* Currently not supported
*/
float adc_mapf(adc_t dev, int value, float min, float max)
int adc_sample(adc_t line, adc_res_t res)
{
return 0.0;
}
int value[2];
#endif /* ADC_NUMOF */
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];
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015 Freie Universität Berlin
* Copyright (C) 2015-2016 Freie Universität 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
@ -14,6 +14,7 @@
* @brief CPU specific definitions for internal peripheral handling
*
* @author Paul RATHGEB <paul.rathgeb@skynet.be>
* @author Hauke Petersen<hauke.petersen@fu-berlin.de>
*/
#ifndef PERIPH_CPU_H_
@ -39,6 +40,28 @@ extern "C" {
*/
#define CPUID_LEN (16U)
/**
* @brief Define number of available ADC lines
*
* TODO: check this value
*/
#define ADC_NUMOF (10U)
/**
* @brief Override the ADC resolution settings
* @{
*/
#define HAVE_ADC_RES_T
typedef enum {
ADC_RES_6BIT = 0, /**< ADC resolution: 6 bit */
ADC_RES_8BIT, /**< ADC resolution: 8 bit */
ADC_RES_10BIT, /**< ADC resolution: 10 bit */
ADC_RES_12BIT, /**< ADC resolution: 12 bit */
ADC_RES_14BIT, /**< ADC resolution: 14 bit */
ADC_RES_16BIT, /**< ADC resolution: 16 bit */
} adc_res_t;
/** @} */
#ifdef __cplusplus
}
#endif

View File

@ -1,9 +1,9 @@
/*
* Copyright (C) 2015 Freie Universität Berlin
* Copyright (C) 2015-2016 Freie Universität 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.
* 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.
*/
/**
@ -13,114 +13,91 @@
* @file
* @brief Low-level ADC driver implementation
*
* @author Paul RATHGEB <paul.rathgeb@skynet.be>
* @author Paul Rathgeb <paul.rathgeb@skynet.be>
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
*
* @}
*/
#include <stdint.h>
#include <string.h>
#include "cpu.h"
#include "mutex.h"
#include "periph/adc.h"
#include "periph_conf.h"
/* guard in case that no ADC device is defined */
#if ADC_NUMOF
/**
* @brief Mutex to synchronize ADC access from different threads
*/
static mutex_t lock = MUTEX_INIT;
static inline uint32_t *_adc_channel_to_pin(int channel)
static inline uint32_t *pincfg_reg(adc_t line)
{
return (channel < 6) ? ((uint32_t*)(LPC_IOCON) + (11 + channel))
: ((uint32_t*)(LPC_IOCON) + (16 + channel));
int offset = (line < 6) ? (11 + line) : (16 + line);
return ((uint32_t *)(LPC_IOCON) + offset);
}
int adc_init(adc_t dev, adc_precision_t precision)
static inline void prep(void)
{
adc_poweron(dev);
mutex_lock(&lock);
LPC_SYSCON->PDRUNCFG &= ~(1 << 4);
LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 13);
}
/* Set resolution */
switch (precision) {
case ADC_RES_6BIT:
LPC_ADC->CR |= (0x04 << 17);
break;
case ADC_RES_8BIT:
LPC_ADC->CR |= (0x02 << 17);
break;
case ADC_RES_10BIT:
LPC_ADC->CR |= (0x0 << 17);
break;
case ADC_RES_12BIT:
case ADC_RES_14BIT:
case ADC_RES_16BIT:
/* Resolution > 10 bits unsupported */
adc_poweroff(dev);
return -1;
break;
}
static inline void done(void)
{
LPC_SYSCON->SYSAHBCLKCTRL &= ~(1 << 13);
LPC_SYSCON->PDRUNCFG |= (1 << 4);
mutex_unlock(&lock);
}
int adc_init(adc_t line)
{
uint32_t *pincfg;
prep();
/* ADC frequency : 3MHz */
LPC_ADC->CR |= (15 << 8);
LPC_ADC->CR = (15 << 8);
/* configure the connected pin */
pincfg = pincfg_reg(line);
/* Put the pin in its ADC alternate function */
if (line < 5) {
*pincfg |= 2;
}
else {
*pincfg |= 1;
}
/* Configure ADMODE in analog input */
*pincfg &= ~(1 << 7);
done();
return 0;
}
int adc_sample(adc_t dev, int channel)
int adc_sample(adc_t line, adc_res_t res)
{
if (channel > ADC_MAX_CHANNELS) {
int sample;
/* check if resolution is valid */
if (res < 0xff) {
return -1;
}
/* Compute the IOCON register for the channel */
uint32_t *cfg = _adc_channel_to_pin(channel);
/* Put the pin in its ADC alternate function */
if (channel < 5) {
*cfg |= 2;
}
else {
*cfg |= 1;
}
/* Configure ADMODE in analog input */
*cfg &= ~(1 << 7);
/* prepare the device */
prep();
/* set resolution */
LPC_ADC->CR &= ~(0x7 << 17);
LPC_ADC->CR |= res;
/* Start a conversion */
LPC_ADC->CR |= (1 << channel) | (1 << 24);
LPC_ADC->CR |= (1 << line) | (1 << 24);
/* Wait for the end of the conversion */
while (!(LPC_ADC->DR[channel] & (1 << 31)));
while (!(LPC_ADC->DR[line] & (1 << 31))) {}
/* Read and return result */
return (LPC_ADC->DR[channel] >> 6);
}
sample = (LPC_ADC->DR[line] >> 6);
void adc_poweron(adc_t dev)
{
switch (dev) {
#if ADC_0_EN
case ADC_0:
LPC_SYSCON->PDRUNCFG &= ~(1 << 4);
LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 13);
break;
#endif
}
}
done();
void adc_poweroff(adc_t dev)
{
switch (dev) {
#if ADC_0_EN
case ADC_0:
LPC_SYSCON->PDRUNCFG |= (1 << 4);
LPC_SYSCON->SYSAHBCLKCTRL &= ~(1 << 13);
break;
#endif
}
return sample;
}
int adc_map(adc_t dev, int value, int min, int max)
{
return 0;
}
float adc_mapf(adc_t dev, int value, float min, float max)
{
return 0.0;
}
#endif /* ADC_NUMOF */

View File

@ -1,10 +1,10 @@
/*
* Copyright (C) 2014 Freie Universität Berlin
* Copyright (C) 2015 Ludwig Knüpfer
* Copyright (C) 2014-2016 Freie Universität Berlin
* 2015 Ludwig Knüpfer
*
* 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.
* 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.
*/
/**
@ -12,7 +12,7 @@
* @{
*
* @file
* @brief Low-level UART driver implementation
* @brief Low-level ADC driver implementation
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
* @author Ludwig Knüpfer <ludwig.knuepfer@fu-berlin.de>
@ -21,114 +21,73 @@
*/
#include "cpu.h"
#include "mutex.h"
#include "periph/adc.h"
#include "periph_conf.h"
/* guard file in case no ADC device is defined */
#if ADC_NUMOF
/**
* @brief Load the ADC configuration
* @{
*/
#ifdef ADC_CONFIG
static const uint8_t adc_config[] = ADC_CONFIG;
#else
static const uint8_t adc_config[] = {};
#endif
/* save the maximum value configured for the ADC */
int adc_max_value;
/**
* @brief Lock to prevent concurrency issues when used from different threads
*/
static mutex_t lock;
int adc_init(adc_t dev, adc_precision_t precision)
static inline void prep(void)
{
/* the NRF51822 only supports one ADC... */
if (dev != ADC_0) {
return -2;
}
/* power on ADC */
mutex_lock(&lock);
NRF_ADC->POWER = 1;
NRF_ADC->ENABLE = 1;
}
/* disable ADC interrupts */
NRF_ADC->INTENSET = (ADC_INTENSET_END_Disabled << ADC_INTENSET_END_Pos);
static inline void done(void)
{
NRF_ADC->ENABLE = 0;
NRF_ADC->POWER = 0;
mutex_unlock(&lock);
}
/* configure ADC, set precision, internal reference to VBG */
switch (precision) {
case ADC_RES_8BIT:
adc_max_value = 255;
NRF_ADC->CONFIG = (ADC_CONFIG_RES_8bit << ADC_CONFIG_RES_Pos);
break;
case ADC_RES_10BIT:
adc_max_value = 1023;
NRF_ADC->CONFIG = (ADC_CONFIG_RES_10bit << ADC_CONFIG_RES_Pos);
break;
default:
NRF_ADC->POWER = 0;
return -1;
int adc_init(adc_t line)
{
if (line >= ADC_NUMOF) {
return -1;
}
/* select the reference voltage / prescaler */
NRF_ADC->CONFIG |= (ADC_CONFIG_EXTREFSEL_None << ADC_CONFIG_EXTREFSEL_Pos);
NRF_ADC->CONFIG |= (ADC_CONFIG_REFSEL_VBG << ADC_CONFIG_REFSEL_Pos);
NRF_ADC->CONFIG |= (ADC_CONFIG_INPSEL_AnalogInputOneThirdPrescaling << ADC_CONFIG_INPSEL_Pos);
/* enable the ADC */
NRF_ADC->ENABLE = (ADC_ENABLE_ENABLE_Enabled << ADC_ENABLE_ENABLE_Pos);
return 0;
}
int adc_sample(adc_t dev, int channel)
int adc_sample(adc_t line, adc_res_t res)
{
if (dev != ADC_0) {
return -2;
int val;
/* check if resolution is valid */
if (res > 2) {
return -1;
}
/* set channel */
NRF_ADC->CONFIG &= ~(ADC_CONFIG_PSEL_Msk);
NRF_ADC->CONFIG |= (ADC_CONFIG_PSEL_Disabled << ADC_CONFIG_PSEL_Pos);
switch (channel) {
case 0:
NRF_ADC->CONFIG |= (ADC_0_CH0 << ADC_CONFIG_PSEL_Pos);
break;
case 1:
NRF_ADC->CONFIG |= (ADC_0_CH1 << ADC_CONFIG_PSEL_Pos);
break;
case 2:
NRF_ADC->CONFIG |= (ADC_0_CH2 << ADC_CONFIG_PSEL_Pos);
break;
case 3:
NRF_ADC->CONFIG |= (ADC_0_CH3 << ADC_CONFIG_PSEL_Pos);
break;
default:
return -1;
}
/* prepare device */
prep();
/* set resolution, line, and use 1/3 input and ref voltage scaling */
NRF_ADC->CONFIG = ((ADC_CONFIG_REFSEL_SupplyOneThirdPrescaling << 5) |
(ADC_CONFIG_INPSEL_AnalogInputOneThirdPrescaling << 2) |
(1 << (adc_config[line] + 8)) |
res);
/* start conversion */
NRF_ADC->TASKS_START = 1;
/* wait for conversion to be complete */
while (((NRF_ADC->BUSY & ADC_BUSY_BUSY_Msk) >> ADC_BUSY_BUSY_Pos) == ADC_BUSY_BUSY_Busy) {}
NRF_ADC->EVENTS_END = 1;
while (NRF_ADC->BUSY == 1) {}
/* get result */
val = (int)NRF_ADC->RESULT;
/* return result */
return (int)NRF_ADC->RESULT;
/* free device */
done();
return val;
}
void adc_poweron(adc_t dev)
{
if (dev == ADC_0) {
NRF_ADC->POWER = 1;
}
}
void adc_poweroff(adc_t dev)
{
if (dev == ADC_0) {
NRF_ADC->POWER = 0;
}
}
int adc_map(adc_t dev, int value, int min, int max)
{
return (int)adc_mapf(dev, value, (float)min, (float)max);
}
float adc_mapf(adc_t dev, int value, float min, float max)
{
(void) dev;
return ((max - min) / ((float)adc_max_value)) * value;
}
#endif /* ADC_NUMOF */

View File

@ -77,6 +77,21 @@ typedef enum {
} gpio_flank_t;
/** @} */
/**
* @brief Override ADC resolution values
* @{
*/
#define HAVE_ADC_RES_T
typedef enum {
ADC_RES_6BIT = 0xf0, /**< ADC resolution: 6 bit */
ADC_RES_8BIT = 0x00, /**< ADC resolution: 8 bit */
ADC_RES_10BIT = 0x02, /**< ADC resolution: 10 bit */
ADC_RES_12BIT = 0xf1, /**< ADC resolution: 12 bit */
ADC_RES_14BIT = 0xf2, /**< ADC resolution: 14 bit */
ADC_RES_16BIT = 0xf3 /**< ADC resolution: 16 bit */
} adc_res_t;
/** @} */
/**
* @brief Timer configuration options
*/

View File

@ -77,6 +77,29 @@ typedef enum {
GPIO_AF3, /**< use alternate function 3 */
} gpio_af_t;
/**
* @brief Override ADC resolution values
* @{
*/
#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 ADC line configuration values
*/
typedef struct {
gpio_t pin; /**< pin to use */
uint8_t chan; /**< internal channel the pin is connected to */
} adc_conf_t;
/**
* @brief Configure the alternate function for the given pin
*

View File

@ -1,9 +1,9 @@
/*
* Copyright (C) 2014 Freie Universität Berlin
* Copyright (C) 2014-2016 Freie Universität 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.
* 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.
*/
/**
@ -18,164 +18,90 @@
* @}
*/
#include <stdint.h>
#include <string.h>
#include "cpu.h"
#include "mutex.h"
#include "periph/adc.h"
#include "periph_conf.h"
/* guard in case that no ADC device is defined */
#if ADC_NUMOF
/**
* @brief Maximum allowed ADC clock speed
*/
#define MAX_ADC_SPEED (12000000U)
typedef struct {
uint8_t precision;
} adc_config_t;
adc_config_t config[ADC_NUMOF];
int adc_init(adc_t dev, adc_precision_t precision)
{
ADC_TypeDef *adc = 0;
adc_poweron(dev);
switch (dev) {
#if ADC_0_EN
case ADC_0:
adc = ADC_0_DEV;
ADC_0_PORT_CLKEN();
ADC_0_PORT->MODER |= ((3 << ADC_0_CH0_PIN) | (3 << ADC_0_CH1_PIN) |
(3 << ADC_0_CH2_PIN) | (3 << ADC_0_CH3_PIN) |
(3 << ADC_0_CH4_PIN) | (3 << ADC_0_CH5_PIN));
break;
/**
* @brief Load the ADC configuration
* @{
*/
#ifdef ADC_CONFIG
static const adc_conf_t adc_config[] = ADC_CONFIG;
#else
static const adc_conf_t adc_config[] = {};
#endif
default:
return -1;
/**
* @brief Allocate locks for all three available ADC device
*
* All STM32F0 CPUs we support so far only come with a single ADC device.
*/
static mutex_t lock = MUTEX_INIT;
static inline void prep(void)
{
mutex_lock(&lock);
RCC->APB2ENR |= RCC_APB2ENR_ADCEN;
}
static inline void done(void)
{
RCC->APB2ENR &= ~(RCC_APB2ENR_ADCEN);
mutex_unlock(&lock);
}
int adc_init(adc_t line)
{
/* make sure the given line is valid */
if (line >= ADC_NUMOF) {
return -1;
}
/* reset control registers */
adc->CR = 0;
adc->CFGR1 = 0;
adc->CFGR2 = 0;
/* set resolution */
config[dev].precision = (6 + (2 * precision));
switch (precision) {
case ADC_RES_6BIT:
adc->CFGR1 |= ADC_CFGR1_RES_0 | ADC_CFGR1_RES_1;
break;
case ADC_RES_8BIT:
adc->CFGR1 |= ADC_CFGR1_RES_1;
break;
case ADC_RES_10BIT:
adc->CFGR1 |= ADC_CFGR1_RES_0;
break;
case ADC_RES_12BIT:
break;
case ADC_RES_14BIT:
case ADC_RES_16BIT:
adc_poweroff(dev);
return -1;
}
/* configure sampling time to 41.5 cycles */
adc->SMPR = 4;
/* enable the ADC module */
adc->CR = ADC_CR_ADEN;
/* lock and power on the device */
prep();
/*configure the pin */
gpio_init_analog(adc_config[line].pin);
/* reset configuration */
ADC1->CFGR2 = 0;
/* enable device */
ADC1->CR = ADC_CR_ADEN;
/* configure sampling time to save value */
ADC1->SMPR = 0x3; /* 28.5 ADC clock cycles */
/* power off an release device for now */
done();
return 0;
}
int adc_sample(adc_t dev, int channel)
int adc_sample(adc_t line, adc_res_t res)
{
ADC_TypeDef *adc = 0;
int sample;
switch (dev) {
#if ADC_0_EN
case ADC_0:
adc = ADC_0_DEV;
switch (channel) {
case 0:
adc->CHSELR = (1 << ADC_0_CH0);
break;
case 1:
adc->CHSELR = (1 << ADC_0_CH1);
break;
case 2:
adc->CHSELR = (1 << ADC_0_CH2);
break;
case 3:
adc->CHSELR = (1 << ADC_0_CH3);
break;
case 4:
adc->CHSELR = (1 << ADC_0_CH4);
break;
case 5:
adc->CHSELR = (1 << ADC_0_CH5);
break;
default:
return -1;
}
break;
#endif
default:
return -1;
/* check if resolution is applicable */
if (res > 0xf0) {
return -1;
}
/* start single conversion */
adc->CR |= ADC_CR_ADSTART;
/* wait until conversion is complete */
while (!(adc->ISR & ADC_ISR_EOC)) {}
/* read and return result */
return (int)adc->DR;
}
/* lock and power on the ADC device */
prep();
void adc_poweron(adc_t dev)
{
switch (dev) {
#if ADC_0_EN
case ADC_0:
ADC_0_CLKEN();
break;
#endif
#if ADC_1_EN
case ADC_1:
ADC_1_CLKEN();
break;
#endif
}
}
/* set resolution and channel */
ADC1->CFGR1 = res;
ADC1->CHSELR = (1 << adc_config[line].chan);
/* start conversion and wait for results */
ADC1->CR |= ADC_CR_ADSTART;
while (!(ADC1->ISR & ADC_ISR_EOC)) {}
/* read result */
sample = (int)ADC1->DR;
void adc_poweroff(adc_t dev)
{
switch (dev) {
#if ADC_0_EN
case ADC_0:
ADC_0_CLKDIS();
break;
#endif
#if ADC_1_EN
case ADC_1:
ADC_1_CLKDIS();
break;
#endif
}
}
/* unlock and power off device again */
done();
int adc_map(adc_t dev, int value, int min, int max)
{
return 0;
return sample;
}
float adc_mapf(adc_t dev, int value, float min, float max)
{
return 0.0;
}
#endif /* ADC_NUMOF */

View File

@ -25,6 +25,15 @@
extern "C" {
#endif
/**
* @brief Available number of ADC devices
*/
#if defined(CPU_MODEL_STM32F401RE)
#define ADC_DEVS (1U)
#elif defined(CPU_MODEL_STM32F407VG) || defined(CPU_MODEL_STM32F415RG)
#define ADC_DEVS (3U)
#endif
/**
* @brief Overwrite the default gpio_t type definition
* @{
@ -43,6 +52,30 @@ typedef uint32_t gpio_t;
*/
#define GPIO_PIN(x, y) ((GPIOA_BASE + (x << 10)) | y)
/**
* @brief declare needed generic SPI functions
* @{
*/
#define PERIPH_SPI_NEEDS_TRANSFER_BYTES
#define PERIPH_SPI_NEEDS_TRANSFER_REG
#define PERIPH_SPI_NEEDS_TRANSFER_REGS
/** @} */
/**
* @brief Override the ADC resolution configuration
* @{
*/
#define HAVE_ADC_RES_T
typedef enum {
ADC_RES_6BIT = 0x03000000, /**< ADC resolution: 6 bit */
ADC_RES_8BIT = 0x02000000, /**< ADC resolution: 8 bit */
ADC_RES_10BIT = 0x01000000, /**< ADC resolution: 10 bit */
ADC_RES_12BIT = 0x00000000, /**< ADC resolution: 12 bit */
ADC_RES_14BIT = 1, /**< ADC resolution: 14 bit (not supported) */
ADC_RES_16BIT = 2 /**< ADC resolution: 16 bit (not supported)*/
} adc_res_t;
/** @} */
/**
* @brief Available ports on the STM32F4 family
*/
@ -95,6 +128,16 @@ typedef struct {
} uart_conf_t;
/** @} */
/**
* @brief ADC channel configuration data
*/
typedef struct {
gpio_t pin; /**< pin connected to the channel */
uint8_t dev; /**< ADCx - 1 device used for the channel */
uint8_t chan; /**< CPU ADC channel connected to the pin */
uint8_t rcc; /**< bit in the RCC APB2 enable register */
} adc_conf_t;
/**
* @brief Configure the alternate function for the given pin
*
@ -105,6 +148,13 @@ typedef struct {
*/
void gpio_init_af(gpio_t pin, gpio_af_t af);
/**
* @brief Configure the given pin to be used as ADC input
*
* @param[in] pin pin to configure
*/
void gpio_init_analog(gpio_t pin);
/**
* @brief Power on the DMA device the given stream belongs to
*

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2014 Freie Universität Berlin
* Copyright (C) 2014-2016 Freie Universität 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
@ -19,167 +19,111 @@
*/
#include "cpu.h"
#include "mutex.h"
#include "periph/adc.h"
#include "periph_conf.h"
/* guard in case that no ADC device is defined */
#if ADC_NUMOF
/**
* @brief Maximum allowed ADC clock speed
*/
#define MAX_ADC_SPEED (12000000U)
typedef struct {
int max_value;
} adc_config_t;
/**
* @brief Load the ADC configuration
* @{
*/
#ifdef ADC_CONFIG
static const adc_conf_t adc_config[] = ADC_CONFIG;
#else
static const adc_conf_t adc_config[] = {};
#endif
adc_config_t adc_config[ADC_NUMOF];
/**
* @brief Allocate locks for all three available ADC devices
*/
static mutex_t locks[] = {
#if ADC_DEVS > 1
MUTEX_INIT,
#endif
#if ADC_DEVS > 2
MUTEX_INIT,
#endif
MUTEX_INIT
};
int adc_init(adc_t dev, adc_precision_t precision)
static inline ADC_TypeDef *dev(adc_t line)
{
ADC_TypeDef *adc = 0;
return (ADC_TypeDef *)(ADC1_BASE + (adc_config[line].dev << 8));
}
adc_poweron(dev);
static inline void prep(adc_t line)
{
mutex_lock(&locks[adc_config[line].dev]);
RCC->APB2ENR |= (RCC_APB2ENR_ADC1EN << adc_config[line].dev);
}
switch (dev) {
#if ADC_0_EN
case ADC_0:
adc = ADC_0_DEV;
ADC_0_PORT_CLKEN();
ADC_0_PORT->MODER |= (3 << (ADC_0_CH0_PIN * 2) | 3 << (ADC_0_CH1_PIN * 2));
break;
#endif
#if ADC_1_EN
case ADC_1:
adc = ADC_1_DEV;
ADC_1_PORT_CLKEN();
ADC_1_PORT->MODER |= (3 << (ADC_1_CH0_PIN * 2) | 3 << (ADC_1_CH1_PIN * 2));
break;
#endif
default:
return -1;
static inline void done(adc_t line)
{
RCC->APB2ENR &= ~(RCC_APB2ENR_ADC1EN << adc_config[line].dev);
mutex_unlock(&locks[adc_config[line].dev]);
}
int adc_init(adc_t line)
{
uint32_t clk_div = 2;
/* check if the line is valid */
if (line >= ADC_NUMOF) {
return -1;
}
/* reset control registers */
adc->CR1 = 0;
adc->CR2 = 0;
adc->SQR1 = 0;
/* lock and power-on the device */
prep(line);
/* set precision */
switch (precision) {
case ADC_RES_6BIT:
adc->CR1 |= ADC_CR1_RES_0 | ADC_CR1_RES_1;
adc_config[dev].max_value = 0x3f;
break;
case ADC_RES_8BIT:
adc->CR1 |= ADC_CR1_RES_1;
adc_config[dev].max_value = 0xff;
break;
case ADC_RES_10BIT:
adc->CR1 |= ADC_CR1_RES_0;
adc_config[dev].max_value = 0x3ff;
break;
case ADC_RES_12BIT:
adc_config[dev].max_value = 0xfff;
break;
case ADC_RES_14BIT:
case ADC_RES_16BIT:
adc_poweroff(dev);
return -1;
/* configure the pin */
gpio_init_analog(adc_config[line].pin);
/* set sequence length to 1 conversion and enable the ADC device */
dev(line)->SQR1 = 0;
dev(line)->CR2 = ADC_CR2_ADON;
/* 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;
/* set clock prescaler */
ADC->CCR = (3 << 16); /* ADC clock = 10,5MHz */
/* enable the ADC module */
adc->CR2 |= ADC_CR2_ADON;
/* free the device again */
done(line);
return 0;
}
int adc_sample(adc_t dev, int channel)
int adc_sample(adc_t line, adc_res_t res)
{
ADC_TypeDef *adc = 0;
int sample;
switch (dev) {
#if ADC_0_EN
case ADC_0:
adc = ADC_0_DEV;
switch (channel) {
case 0:
adc->SQR3 = ADC_0_CH0 & 0x1f;
break;
case 1:
adc->SQR3 = ADC_0_CH1 & 0x1f;
break;
default:
return -1;
}
break;
#endif
#if ADC_1_EN
case ADC_1:
adc = ADC_1_DEV;
switch (channel) {
case 0:
adc->SQR3 = ADC_1_CH0 & 0x1f;
break;
case 1:
adc->SQR3 = ADC_1_CH1 & 0x1f;
break;
default:
return -1;
}
break;
#endif
/* check if resolution is applicable */
if (res < 0xff) {
return -1;
}
/* start single conversion */
adc->CR2 |= ADC_CR2_SWSTART;
/* wait until conversion is complete */
while (!(adc->SR & ADC_SR_EOC)) {}
/* read and return result */
return (int)adc->DR;
}
/* lock and power on the ADC device */
prep(line);
void adc_poweron(adc_t dev)
{
switch (dev) {
#if ADC_0_EN
case ADC_0:
ADC_0_CLKEN();
break;
#endif
#if ADC_1_EN
case ADC_1:
ADC_1_CLKEN();
break;
#endif
}
}
/* wait for any ongoing conversions to finish */
while (dev(line)->SR & ADC_SR_STRT) {}
/* set resolution and conversion channel */
dev(line)->CR1 = res;
dev(line)->SQR3 = adc_config[line].chan;
/* start conversion and wait for results */
dev(line)->CR2 |= ADC_CR2_SWSTART;
while (!(dev(line)->SR & ADC_SR_EOC)) {}
/* finally read sample and reset the STRT bit in the status register */
sample = (int)dev(line)->DR;
dev(line)->SR &= ~ADC_SR_STRT;
void adc_poweroff(adc_t dev)
{
switch (dev) {
#if ADC_0_EN
case ADC_0:
ADC_0_CLKDIS();
break;
#endif
#if ADC_1_EN
case ADC_1:
ADC_1_CLKDIS();
break;
#endif
}
}
/* power off and unlock device again */
done(line);
int adc_map(adc_t dev, int value, int min, int max)
{
return (int)adc_mapf(dev, value, (float)min, (float)max);
return sample;
}
float adc_mapf(adc_t dev, int value, float min, float max)
{
return ((max - min) / ((float)adc_config[dev].max_value)) * value;
}
#endif /* ADC_NUMOF */

View File

@ -148,6 +148,14 @@ void gpio_init_af(gpio_t pin, gpio_af_t af)
port->AFR[(pin_num > 7) ? 1 : 0] |= (af << ((pin_num & 0x07) * 4));
}
void gpio_init_analog(gpio_t pin)
{
/* enable clock */
RCC->AHB1ENR |= (RCC_AHB1ENR_GPIOAEN << _port_num(pin));
/* set to analog mode */
_port(pin)->MODER |= (0x3 << (2 * _pin_num(pin)));
}
void gpio_irq_enable(gpio_t pin)
{
EXTI->IMR |= (1 << _pin_num(pin));

View File

@ -33,8 +33,7 @@ extern "C" {
* @brief device descriptor for a MQ-3 sensor
*/
typedef struct {
adc_t adc_dev; /**< the used ADC device */
int adc_chan; /**< used channel of the ADC */
adc_t adc_line; /**< the used ADC line */
} mq3_t;
/**
@ -47,12 +46,11 @@ typedef struct {
*
* @param[out] dev device descriptor of an MQ-3 sensor
* @param[in] adc the ADC device the sensor is connected to
* @param[in] channel the channel of the ADC device used
*
* @return 0 on success
* @return -1 on error
*/
int mq3_init(mq3_t *dev, adc_t adc, int channel);
int mq3_init(mq3_t *dev, adc_t adc_line);
/**
* @brief Read the RAW sensor value, can be between 0 and MQ3_MAX_RAW_VALUE

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2014 Freie Universität Berlin
* Copyright (C) 2014-2015 Freie Universität 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
@ -9,7 +9,29 @@
/**
* @defgroup drivers_periph_adc ADC
* @ingroup drivers_periph
* @brief Low-level ADC peripheral driver
* @brief Low-level ADC peripheral driver interface
*
* This is a very simple ADC interface to allow platform independent access to
* a MCU's ADC unit(s). This interface is intentionally designed as simple as
* possible, to allow for very easy implementation and maximal portability.
*
* As of now, the interface does not allow for any advanced ADC concepts (e.g.
* continuous mode, scan sequences, injections). It is to be determined, if
* these features will ever be integrated in this interface, or if it does make
* more sense to create a second, advanced ADC interface for this.
*
* The ADC driver interface is built around the concept of ADC lines. An ADC
* line in this context is a tuple consisting out of a hardware ADC device (an
* ADC functional unit on the MCU) and an ADC channel connected to pin.
*
* If a MCU has more than one hardware ADC unit, the ADC lines can be mapped in
* a way, that it is possible to sample multiple lines in parallel, given that
* the ADC implementation allows for interruption of the program flow while
* waiting for the result of a conversion (e.g. through putting the calling
* thread to sleep while waiting for the conversion results).
*
* @todo Extend interface for continuous mode?
*
* @{
*
* @file
@ -18,128 +40,99 @@
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
*/
#ifndef ADC_H
#define ADC_H
#ifndef PERIPH_ADC_H
#define PERIPH_ADC_H
#include "periph_cpu.h"
#include "periph_conf.h"
#ifdef __cplusplus
extern "C" {
#endif
/* guard file in case no ADC device is defined */
#if ADC_NUMOF
/**
* @brief Definition available ADC devices
*
* Each ADC device is based on a hardware ADC which can have one or more
* multiplexed channels.
* @brief Make sure the number of available ADC lines is defined
* @{
*/
typedef enum {
#if ADC_0_EN
ADC_0 = 0, /**< ADC device 0 */
#ifndef ADC_NUMOF
#error "ADC_NUMOF undefined"
#endif
#if ADC_1_EN
ADC_1, /**< ADC device 1 */
#endif
#if ADC_2_EN
ADC_2, /**< ADC device 2 */
#endif
#if ADC_3_EN
ADC_3, /**< ADC device 3 */
#endif
} adc_t;
/** @} */
/**
* @brief Possible ADC precision settings
* @brief Define default ADC type identifier
* @{
*/
typedef enum {
ADC_RES_6BIT = 0, /**< ADC precision: 6 bit */
ADC_RES_8BIT, /**< ADC precision: 8 bit */
ADC_RES_10BIT, /**< ADC precision: 10 bit */
ADC_RES_12BIT, /**< ADC precision: 12 bit */
ADC_RES_14BIT, /**< ADC precision: 14 bit */
ADC_RES_16BIT, /**< ADC precision: 16 bit */
} adc_precision_t;
#ifndef HAVE_ADC_T
typedef unsigned int adc_t;
#endif
/** @} */
/**
* @brief Initialization of a given ADC device
* @brief Default ADC undefined value
* @{
*/
#ifndef ADC_UNDEF
#define ADC_UNDEF (0xffff)
#endif
/** @} */
/**
* @brief Default ADC line access macro
* @{
*/
#ifndef ADC_LINE
#define ADC_LINE(x) (x)
#endif
/** @} */
/**
* @brief Possible ADC resolution settings
* @{
*/
#ifndef HAVE_ADC_RES_T
typedef enum {
ADC_RES_6BIT = 0, /**< ADC resolution: 6 bit */
ADC_RES_8BIT, /**< ADC resolution: 8 bit */
ADC_RES_10BIT, /**< ADC resolution: 10 bit */
ADC_RES_12BIT, /**< ADC resolution: 12 bit */
ADC_RES_14BIT, /**< ADC resolution: 14 bit */
ADC_RES_16BIT, /**< ADC resolution: 16 bit */
} adc_res_t;
#endif
/** @} */
/**
* @brief Initialize the given ADC line
*
* The ADC will be initialized in synchronous, blocking mode, so no callbacks for finished
* conversions are required as conversions are presumed to be very fast (somewhere in the
* range of some us).
* The ADC line is initialized in synchronous, blocking mode.
*
* @param[in] dev the device to initialize
* @param[in] precision the precision to use for conversion
* @param[in] line line to initialize
*
* @return 0 on success
* @return -1 on precision not available
* @return -1 on invalid ADC line
*/
int adc_init(adc_t dev, adc_precision_t precision);
int adc_init(adc_t line);
/**
* @brief Start a new conversion by using the given channel.
* @brief Sample a value from the given ADC line
*
* If a conversion on any channel on the given ADC core is in progress, it is aborted.
* This function blocks until the conversion has finished. Please note, that if
* more than one line share the same ADC device, and if these lines are sampled
* at the same time (e.g. from different threads), the one called secondly waits
* for the first to finish before its conversion starts.
*
* @param[in] dev the ADC device to use for the conversion
* @param[in] channel the channel to convert from
* @param[in] line line to sample
* @param[in] resolution resolution to use for conversion
*
* @return the converted value
* @return -1 on invalid channel
* @return the sampled value on success
* @return -1 if resolution is not applicable
*/
int adc_sample(adc_t dev, int channel);
/**
* @brief Enable the power for the given ADC device
*
* @param[in] dev the ADC device to power up
*/
void adc_poweron(adc_t dev);
/**
* @brief Disable the power for the given ADC device
*
* @param[in] dev the ADC device to power down
*/
void adc_poweroff(adc_t dev);
/**
* @brief Helper function to map a converted value to the given integer range.
*
* This function is useful for converting sampled ADC values into their physical representation.
*
* The min value is asserted to be smaller than the max value.
*
* @param[in] dev the ADC device to read the precision value from (as input interval)
* @param[in] value the value to map
* @param[in] min the lower bound of the target interval
* @param[in] max the upper bound of the target interval
*
* @return the mapped value
*/
int adc_map(adc_t dev, int value, int min, int max);
/**
* @brief Helper function to map a converted value to the given float range
*
* @see adc_map
*
* @param[in] dev the ADC device to read the precision value from (as input interval)
* @param[in] value the value to map
* @param[in] min the lower bound of the target interval
* @param[in] max the upper bound of the target interval
*
* @return the mapped value
*/
float adc_mapf(adc_t dev, int value, float min, float max);
#endif /* ADC_NUMOF */
int adc_sample(adc_t line, adc_res_t res);
#ifdef __cplusplus
}
#endif
#endif /* ADC_H */
#endif /* PERIPH_ADC_H */
/** @} */

View File

@ -24,16 +24,15 @@
#define MIN (100U) /* TODO: calibrate to useful value */
#define FACTOR (2.33f) /* TODO: calibrate to useful value */
int mq3_init(mq3_t *dev, adc_t adc, int channel)
int mq3_init(mq3_t *dev, adc_t adc_line)
{
dev->adc_dev = adc;
dev->adc_chan = channel;
return adc_init(dev->adc_dev, PRECISION);
dev->adc_line = adc_line;
return adc_init(dev->adc_line);
}
int mq3_read_raw(mq3_t *dev)
{
return adc_sample(dev->adc_dev, dev->adc_chan);
return adc_sample(dev->adc_line, PRECISION);
}
int mq3_read(mq3_t *dev)

1
sys/adc_util/Makefile Normal file
View File

@ -0,0 +1 @@
include $(RIOTBASE)/Makefile.base

41
sys/adc_util/adc_util.c Normal file
View File

@ -0,0 +1,41 @@
/*
* Copyright (C) 2015 Freie Universität 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 sys_adc_util
* @{
*
* @file
* @brief ADC utility function implementation
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
*
* @}
*/
#include "adc_util.h"
/* keep a max value to ADC resolution mapping for quick access in the ROM */
static const int val_max[] = {
[ADC_RES_6BIT] = 0x003f,
[ADC_RES_8BIT] = 0x00ff,
[ADC_RES_10BIT] = 0x03ff,
[ADC_RES_12BIT] = 0x0fff,
[ADC_RES_14BIT] = 0x3fff,
[ADC_RES_16BIT] = 0xffff
}
int adc_util_map(int sample, adc_res_t res, int min, int max)
{
return ((((max - min) * sample) / val_max[res]) + min);
}
float adc_util_mapf(int sample, adc_res_t res, float min, float max)
{
return ((((max - min) * sample) / val_max[res]) + min);
}

67
sys/include/adc_util.h Normal file
View File

@ -0,0 +1,67 @@
/*
* Copyright (C) 2015 Freie Universität 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.
*/
/**
* @defgroup sys_adc_util ADC utilities
* @ingroup sys
* @brief Utility functions for handling ADC samples
*
* @{
* @file
* @brief ADC utility function interfaces
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
*/
#ifndef ADC_UTIL_H
#define ADC_UTIL_H
#include "periph/adc.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Map a sampled ADC value to a given range
*
* This function is useful for converting sampled ADC values into their physical
* representation.
*
* The min value is asserted to be smaller than the max value.
*
* @param[in] sample sampled ADC value
* @param[in] res ADC resolution
* @param[in] min the lower bound of the target interval
* @param[in] max the upper bound of the target interval
*
* @return the mapped value
*/
int adc_util_map(int sample, adc_res_t res, int min, int max);
/**
* @brief Map a sampled ADC value to a given range (using floating point
* arithmetics)
*
* @see adc_util_map
*
* @param[in] sample sampled ADC value
* @param[in] res ADC resolution
* @param[in] min the lower bound of the target interval
* @param[in] max the upper bound of the target interval
*
* @return the mapped value
*/
float adc_util_mapf(int sample, adc_res_t res, float min, float max);
#ifdef __cplusplus
}
#endif
#endif /* ADC_UTIL_H */
/** @} */

View File

@ -7,11 +7,9 @@ USEMODULE += mq3
USEMODULE += xtimer
# set default device parameters in case they are undefined
MQ3_ADC ?= ADC_0
MQ3_CHAN ?= 0
MQ3_ADC_LINE ?= ADC_LINE\(0\)
# export parameters
CFLAGS += -DMQ3_ADC=$(MQ3_ADC)
CFLAGS += -DMQ3_CHAN=$(MQ3_CHAN)
CFLAGS += -DMQ3_ADC_LINE=$(MQ3_ADC_LINE)
include $(RIOTBASE)/Makefile.include

View File

@ -25,11 +25,8 @@
#include "periph_conf.h"
#include "periph/adc.h"
#ifndef MQ3_ADC
#error "MQ3_ADC is not specified"
#endif
#ifndef MQ3_CHAN
#error "MQ3_CHAN is not specified"
#ifndef MQ3_ADC_LINE
#error "MQ3_ADC_LINE is not specified"
#endif
int main(void)
@ -38,8 +35,8 @@ int main(void)
int res;
puts("MQ-3 alcohol sensor test application\n");
printf("Initializing MQ-3 sensor at ADC_%i, channel %i... ", MQ3_ADC, MQ3_CHAN);
res = mq3_init(&dev, MQ3_ADC, MQ3_CHAN);
printf("Initializing MQ-3 sensor at ADC_LINE(%i)... ", (int)MQ3_ADC_LINE);
res = mq3_init(&dev, MQ3_ADC_LINE);
if (res == 0) {
puts("[ok]\n");
}

View File

@ -1,11 +1,11 @@
Expected result
===============
When running this test, you should see the samples of all configured ADC channels
When running this test, you should see the samples of all configured ADC lines
continuously streamed to std-out.
Background
==========
This test application will initialize each configured ADC device to sample with
This test application will initialize each configured ADC lines to sample with
10-bit accuracy. Once configured the application will continuously convert each
available channel and print the conversion results to std-out.

View File

@ -1,17 +1,17 @@
/*
* Copyright (C) 2014 Freie Universität Berlin
* Copyright (C) 2014-2015 Freie Universität 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.
* 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 tests
* @ingroup tests
* @{
*
* @file
* @brief Test case for the low-level ADC driver
* @brief Test application for peripheral ADC drivers
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
*
@ -20,64 +20,43 @@
#include <stdio.h>
#include "cpu.h"
#include "board.h"
#include "xtimer.h"
#include "periph/adc.h"
#if ADC_NUMOF < 1
#error "Please enable at least 1 ADC device to run this test"
#endif
#define RES ADC_RES_10BIT
#define DELAY (100 * 1000U)
static int values[ADC_NUMOF][ADC_MAX_CHANNELS];
int main(void)
{
puts("\nRIOT ADC peripheral driver test\n");
puts("This test simply converts each available ADC channel about every 10ms\n\n");
uint32_t last = xtimer_now();
int sample = 0;
puts("\nRIOT ADC peripheral driver test\n");
puts("This test will sample all available ADC lines once every 100ms with\n"
"a 10-bit resolution and print the sampled results to STDIO\n\n");
/* initialize all available ADC lines */
for (int i = 0; i < ADC_NUMOF; i++) {
/* initialize result vector */
for (int j = 0; j < ADC_MAX_CHANNELS; j++) {
values[i][j] = -1;
}
/* initialize ADC device */
printf("Initializing ADC_%i @ %i bit resolution", i, (6 + (2* RES)));
if (adc_init(i, RES) == 0) {
puts(" ...[ok]");
}
else {
puts(" ...[failed]");
if (adc_init(ADC_LINE(i)) < 0) {
printf("Initialization of ADC_LINE(%i) failed\n", i);
return 1;
} else {
printf("Successfully initialized ADC_LINE(%i)\n", i);
}
}
puts("\n");
while (1) {
/* convert each channel for this ADC device */
for (int i = 0; i < ADC_NUMOF; i++) {
for (int j = 0; j < ADC_MAX_CHANNELS; j++) {
values[i][j] = adc_sample(i, j);
sample = adc_sample(ADC_LINE(i), RES);
if (sample < 0) {
printf("ADC_LINE(%i): 10-bit resolution not applicable\n", i);
} else {
printf("ADC_LINE(%i): %i\n", i, sample);
}
}
/* print the results */
printf("Values: ");
for (int i = 0; i < ADC_NUMOF; i++) {
for (int j = 0; j < ADC_MAX_CHANNELS; j++) {
if (values[i][j] >= 0) {
printf("ADC_%i-CH%i: %4i ", i, j, values[i][j]);
}
}
}
printf("\n");
/* sleep a little while */
xtimer_usleep(DELAY);
xtimer_usleep_until(&last, DELAY);
}
return 0;

View File

@ -32,6 +32,7 @@
#endif
#define RES DAC_RES_10BIT
#define ADC_RES ADC_RES_10BIT
#define DELAY (1000 * 1000U)
#define MAX_VALUE_STEPS 1000
@ -60,9 +61,9 @@ int main(void)
return 1;
}
#if ADC_NUMOF > 0
printf("Initializing ADC_0 @ %i bit resolution", (6 + (2* RES)));
if (adc_init(0, RES) == 0) {
#ifdef ADC_NUMOF
printf("Initializing ADC_LINE(0)");
if (adc_init(ADC_LINE(0)) == 0) {
puts(" ...[ok]");
}
else {
@ -82,9 +83,9 @@ int main(void)
printf("%i: Something went wrong writing DAC\n", status_dac_write);
return -1;
}
#if ADC_NUMOF > 0
#ifdef ADC_NUMOF
/* Read values from ADC */
int sample = adc_sample(ADC_0, 0);
int sample = adc_sample(ADC_LINE(0), ADC_RES);
if (sample < 0) {
printf("%i: Something went wrong sampling ADC\n", sample);
return -1;