-
Notifications
You must be signed in to change notification settings - Fork 2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Basic DAC Driver, implementation on stm32f4discovery
- Loading branch information
Simon Brummer
committed
Nov 25, 2014
1 parent
f9c7e21
commit 5a4b966
Showing
4 changed files
with
342 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1 @@ | ||
FEATURES_PROVIDED += periph_gpio periph_spi periph_i2c periph_pwm periph_random periph_adc cpp | ||
|
||
FEATURES_PROVIDED += periph_gpio periph_spi periph_i2c periph_pwm periph_random periph_adc periph_dac cpp |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
/* | ||
* Copyright (C) 2014 Simon Brummer | ||
* | ||
* 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_stm32f4 | ||
* @{ | ||
* | ||
* @file | ||
* @brief Low-level DAC driver implementation | ||
* | ||
* @author Simon Brummer<simon.brummer@haw-hamburg.de> | ||
* | ||
* @} | ||
*/ | ||
|
||
#include "cpu.h" | ||
#include "periph/dac.h" | ||
#include "periph_conf.h" | ||
|
||
/* guard in case that no DAC device is defined */ | ||
#if DAC_NUMOF | ||
|
||
#define DAC_MAX_12BIT 0x0fff | ||
|
||
typedef struct { | ||
uint8_t shift_mod; | ||
} dac_config_t; | ||
|
||
dac_config_t dac_config[DAC_NUMOF]; | ||
|
||
int8_t dac_init(dac_t dev, dac_precision_t precision) | ||
{ | ||
DAC_TypeDef *dac = 0; | ||
dac_poweron(dev); | ||
|
||
switch (dev) { | ||
#if DAC_0_EN | ||
case DAC_0: | ||
dac = DAC_0_DEV; | ||
DAC_0_PORT_CLKEN(); | ||
/* Set Mode to analoge out, disable Pullup Pulldown Resistors for both channels */ | ||
DAC_0_PORT->MODER |= (3 << (DAC_0_CH0_PIN * 2) | 3 << (DAC_0_CH1_PIN * 2)); | ||
DAC_0_PORT->PUPDR &= ~(3 << (DAC_0_CH0_PIN * 2) | 3 << (DAC_0_CH1_PIN * 2)); | ||
break; | ||
#endif | ||
default: | ||
/* Unknown Device */ | ||
return -1; | ||
} | ||
|
||
/* Select Shift value to normalize given Value */ | ||
switch(precision) { | ||
case DAC_RES_6BIT: | ||
dac_config[dev].shift_mod = 0x06; /* 2^6 << 6 = 2^12 */ | ||
break; | ||
case DAC_RES_8BIT: | ||
dac_config[dev].shift_mod = 0x04; /* 2^8 << 4 = 2^12 */ | ||
break; | ||
case DAC_RES_10BIT: | ||
dac_config[dev].shift_mod = 0x02; /* 2^10 << 2 = 2^12 */ | ||
break; | ||
case DAC_RES_12BIT: | ||
dac_config[dev].shift_mod = 0x00; /* 2^12 << 0 = 2^12 */ | ||
break; | ||
/* Not Supported Resolutions */ | ||
case DAC_RES_14BIT: | ||
case DAC_RES_16BIT: | ||
default: | ||
dac_poweroff(dev); | ||
return -2; | ||
break; | ||
} | ||
|
||
/* Enable Channels, Clear Output */ | ||
dac->CR = 0; | ||
dac->CR |= (DAC_CR_EN1 | DAC_CR_EN2); | ||
dac->DHR12R1 = 0; | ||
dac->DHR12R2 = 0; | ||
|
||
return 0; | ||
} | ||
|
||
int8_t dac_write(dac_t dev, uint8_t channel, uint16_t value) | ||
{ | ||
DAC_TypeDef* __attribute__((unused)) dac = 0; | ||
uint16_t __attribute__((unused)) val = value << dac_config[dev].shift_mod; | ||
|
||
switch(dev){ | ||
#if DAC_0_EN | ||
case DAC_0: | ||
dac = DAC_0_DEV; | ||
|
||
if( DAC_MAX_12BIT < val ){ | ||
/* Value out of Range */ | ||
return -3; | ||
} | ||
|
||
switch(channel){ | ||
case 0: | ||
dac->DHR12R1 = val; | ||
break; | ||
case 1: | ||
dac->DHR12R2 = val; | ||
break; | ||
/* Invalid Channel */ | ||
default: | ||
return -2; | ||
} | ||
break; | ||
#endif | ||
/* Unknown Device */ | ||
default: | ||
return -1; | ||
} | ||
return 0; | ||
} | ||
|
||
int8_t dac_poweron(dac_t dev) | ||
{ | ||
switch (dev){ | ||
#if DAC_0_EN | ||
case DAC_0: | ||
DAC_0_CLKEN(); | ||
break; | ||
#endif | ||
default: | ||
/* Unknown Device */ | ||
return -1; | ||
} | ||
return 0; | ||
} | ||
|
||
int8_t dac_poweroff(dac_t dev) | ||
{ | ||
switch (dev) { | ||
#if DAC_0_EN | ||
case DAC_0: | ||
DAC_0_CLKDIS(); | ||
break; | ||
#endif | ||
default: | ||
/* Unknown Device */ | ||
return -1; | ||
} | ||
return 0; | ||
} | ||
|
||
uint16_t dac_map(dac_t dev, int value, int min, int max) | ||
{ | ||
return dac_mapf(dev, (int) value, (int) min, (int) max); | ||
} | ||
|
||
uint16_t dac_mapf(dac_t dev, float value, float min, float max) | ||
{ | ||
uint16_t val_12_bit = ((value - min) * DAC_MAX_12BIT)/(max-min); | ||
return val_12_bit >> dac_config[dev].shift_mod; | ||
} | ||
|
||
#undef DAC_MAX_12BIT | ||
|
||
#endif /* DAC_NUMOF */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
/* | ||
* Copyright (C) 2014 Simon Brummer | ||
* | ||
* 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 driver_periph_dac DAC | ||
* @ingroup driver_periph | ||
* @brief Low-level DAC peripheral driver | ||
* @{ | ||
* | ||
* @file | ||
* @brief Low-level DAC peripheral driver interface definitions | ||
* | ||
* @author Simon Brummer <simon.brummer@haw-hamburg.de> | ||
*/ | ||
|
||
#ifndef __DAC_H | ||
#define __DAC_H | ||
|
||
#include <stdint.h> | ||
#include "periph_conf.h" | ||
|
||
#ifdef __cplusplus | ||
extern "C" { | ||
#endif | ||
|
||
/* guard file in case no ADC device is defined */ | ||
#if DAC_NUMOF | ||
|
||
/** | ||
* @brief Definition avialable DAC devices | ||
* | ||
* Each DAC device is based on a hardware DAC which can have one or more | ||
* independet channels. | ||
*/ | ||
typedef enum { | ||
#if DAC_0_EN | ||
DAC_0 = 0, /**< DAC device 0 */ | ||
#endif | ||
#if DAC_1_EN | ||
DAC_1 = 1, /**< DAC device 1 */ | ||
#endif | ||
#if DAC_2_EN | ||
DAC_2 = 2, /**< DAC device 2 */ | ||
#endif | ||
#if DAC_3_EN | ||
DAC_3 = 3, /**< DAC device 3 */ | ||
#endif | ||
} dac_t; | ||
|
||
/** | ||
* @breif Possilbe DAC precision settings | ||
*/ | ||
typedef enum { | ||
DAC_RES_6BIT = 0, /**< DAC precision: 6 bit */ | ||
DAC_RES_8BIT, /**< DAC precision: 8 bit */ | ||
DAC_RES_10BIT, /**< DAC precision: 10 bit */ | ||
DAC_RES_12BIT, /**< DAC precision: 12 bit */ | ||
DAC_RES_14BIT, /**< DAC precision: 14 bit */ | ||
DAC_RES_16BIT, /**< DAC precision: 16 bit */ | ||
} dac_precision_t; | ||
|
||
/** | ||
* @brief Initialization of a given DAC device | ||
* | ||
* The DAC will be initialized with all possilble channels active. | ||
* On each channel will be initialized with a Zero on it. | ||
* | ||
* @param[in] dev the device to initialize | ||
* @param[in] precision the precision to use for conversion | ||
* | ||
* @return 0 on success | ||
* @return -1 on unknown DAC Device | ||
* @return -2 on precision not available | ||
*/ | ||
int8_t dac_init(dac_t dev, dac_precision_t precision); | ||
|
||
/** | ||
* @brief Write a value onto DAC Device on a given Channel. | ||
* | ||
* @param[in] dev the DAC device to use | ||
* @param[in] channel the channel used for Digital/Analoge conversion | ||
* @param[in] value the value to write onto DAC. | ||
* | ||
* @return 0 on success | ||
* @return -1 on unknown DAC Device | ||
* @return -2 on invalid channel | ||
* @return -3 if value is out of range. | ||
*/ | ||
int8_t dac_write(dac_t dev, uint8_t channel, uint16_t value); | ||
|
||
/** | ||
* @brief Enable power for the given DAC Device | ||
* | ||
* @param[in] dev the DAC device to power up. | ||
* | ||
* @return 0 on success | ||
* @return -1 on unknown DAC Device | ||
*/ | ||
int8_t dac_poweron(dac_t dev); | ||
|
||
/** | ||
* @brief Disable power for the given DAC Device | ||
* | ||
* @param[in] dev the DAC device to power down | ||
* | ||
* @return 0 on success | ||
* @return -1 on unknown DAC Device | ||
*/ | ||
int8_t dac_poweroff(dac_t dev); | ||
|
||
/** | ||
* @brief Helper function to map a given integer range to a valid DAC value. | ||
* | ||
* This function is useful for converting ranges of values to a valid DAC output value. | ||
* | ||
* The min value is assumed to be smaller than max value and value is assumed | ||
* to be between min and max. | ||
* | ||
* @param[in] dev the DAC Device to read precision value from | ||
* @param[in] value the value to map onto min and max | ||
* @param[in] min the lower bound of the target interval | ||
* @param[in] max the upper bound of the target interval | ||
* | ||
* @return the mapped value, in valid DAC range | ||
*/ | ||
uint16_t dac_map(dac_t dev, int value, int min, int max); | ||
|
||
/** | ||
* @brief Helper function to map a given float value range to a valid DAC value. | ||
* | ||
* @see dac_map | ||
* | ||
* @param[in] dev the DAC Device to read precision value from | ||
* @param[in] value the value to map onto min and max | ||
* @param[in] min the lower bound of the target interval | ||
* @param[in] max the upper bound of the target interval | ||
* | ||
* @return the mapped value, in valid DAC range | ||
*/ | ||
uint16_t dac_mapf(dac_t dev, float value, float min, float max); | ||
|
||
#endif/* DAC_NUMOF */ | ||
#ifdef __cplusplus | ||
} | ||
#endif | ||
#endif /* __DAC_H */ | ||
/** @} */ |