mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
cpu/sam0_common: implement periph/dac
The sam0 MCUs all have a DAC peripheral. The DAC has a resulution of 10 or 12 bits and can have one or two output channels. The output pins are always hard-wired to PA2 for DAC0 and PA5 for DAC1 if it exists. On the same54-xpro I would only get a max value of ~1V when using the internal reference, so I configured it to use an external voltage reference. The external reference pin is hard-wired to PA3, so you'll have to connect that to 3.3V to get results.
This commit is contained in:
parent
096996ee22
commit
bfb3d52a63
177
cpu/sam0_common/periph/dac.c
Normal file
177
cpu/sam0_common/periph/dac.c
Normal file
@ -0,0 +1,177 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Beuth Hochschule für Technik Berlin
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup cpu_sam0_common
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Low-level DAC driver implementation
|
||||
*
|
||||
* @author Benjamin Valentin <benpicco@beuth-hochschule.de>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include "cpu.h"
|
||||
#include "periph/dac.h"
|
||||
#include "periph/gpio.h"
|
||||
|
||||
#define DAC_VAL(in) (in >> (16 - DAC_RES_BITS))
|
||||
|
||||
static void _dac_init_clock(dac_t line)
|
||||
{
|
||||
sam0_gclk_enable(DAC_CLOCK);
|
||||
|
||||
/* GCLK Setup */
|
||||
#ifdef GCLK_PCHCTRL_CHEN
|
||||
GCLK->PCHCTRL[DAC_GCLK_ID].reg = GCLK_PCHCTRL_CHEN
|
||||
| GCLK_PCHCTRL_GEN(DAC_CLOCK);
|
||||
#else
|
||||
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN
|
||||
| GCLK_CLKCTRL_GEN(DAC_CLOCK)
|
||||
| GCLK_CLKCTRL_ID(DAC_GCLK_ID);
|
||||
#endif
|
||||
|
||||
dac_poweron(line);
|
||||
}
|
||||
|
||||
static inline bool _ext_vref(void)
|
||||
{
|
||||
#ifdef DAC_CTRLB_REFSEL_VREFP
|
||||
return DAC_VREF == DAC_CTRLB_REFSEL_VREFP;
|
||||
#endif
|
||||
#ifdef DAC_CTRLB_REFSEL_VREFPU
|
||||
return (DAC_VREF == DAC_CTRLB_REFSEL_VREFPU) ||
|
||||
(DAC_VREF == DAC_CTRLB_REFSEL_VREFPB);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void _sync(void)
|
||||
{
|
||||
#ifdef DAC_SYNCBUSY_MASK
|
||||
while (DAC->SYNCBUSY.reg) {}
|
||||
#else
|
||||
while (DAC->STATUS.bit.SYNCBUSY) {}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef DAC_DACCTRL_CCTRL_Msk
|
||||
static uint32_t _get_CCTRL(uint32_t freq)
|
||||
{
|
||||
if (freq < 1200000) {
|
||||
return DAC_DACCTRL_CCTRL_CC100K;
|
||||
}
|
||||
|
||||
if (freq < 6000000) {
|
||||
return DAC_DACCTRL_CCTRL_CC1M;
|
||||
}
|
||||
|
||||
if (freq < 12000000) {
|
||||
return DAC_DACCTRL_CCTRL_CC12M;
|
||||
}
|
||||
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int8_t dac_init(dac_t line)
|
||||
{
|
||||
switch (line) {
|
||||
case 0:
|
||||
/* DAC0 is always connected to PA2 */
|
||||
gpio_init(GPIO_PIN(PA, 2), GPIO_OUT);
|
||||
gpio_init_mux(GPIO_PIN(PA, 2), GPIO_MUX_B);
|
||||
break;
|
||||
#ifdef PIN_PA05B_DAC_VOUT1
|
||||
case 1:
|
||||
/* DAC1 is always connected to PA5 */
|
||||
gpio_init(GPIO_PIN(PA, 5), GPIO_OUT);
|
||||
gpio_init_mux(GPIO_PIN(PA, 5), GPIO_MUX_B);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
return DAC_NOLINE;
|
||||
}
|
||||
|
||||
if (_ext_vref()) {
|
||||
/* PA3 is external reference voltage */
|
||||
gpio_init_mux(GPIO_PIN(PA, 3), GPIO_MUX_B);
|
||||
}
|
||||
|
||||
_dac_init_clock(line);
|
||||
|
||||
/* Settings can only be changed when DAC is disabled */
|
||||
DAC->CTRLA.bit.ENABLE = 0;
|
||||
_sync();
|
||||
|
||||
#ifdef DAC_DACCTRL_ENABLE
|
||||
DAC->DACCTRL[line].reg = DAC_DACCTRL_ENABLE
|
||||
| _get_CCTRL(sam0_gclk_freq(DAC_CLOCK));
|
||||
#endif
|
||||
|
||||
/* Set Reference Voltage & enable Output if needed */
|
||||
DAC->CTRLB.reg = DAC_VREF
|
||||
#ifdef DAC_CTRLB_EOEN
|
||||
| DAC_CTRLB_EOEN
|
||||
#endif
|
||||
;
|
||||
|
||||
DAC->CTRLA.bit.ENABLE = 1;
|
||||
_sync();
|
||||
|
||||
return DAC_OK;
|
||||
}
|
||||
|
||||
void dac_set(dac_t line, uint16_t value)
|
||||
{
|
||||
#ifdef DAC_SYNCBUSY_DATA1
|
||||
/* DAC has multiple outputs */
|
||||
const uint32_t mask = (1 << (DAC_SYNCBUSY_DATA_Pos + line));
|
||||
while (DAC->SYNCBUSY.reg & mask) {}
|
||||
|
||||
DAC->DATA[line].reg = DAC_VAL(value);
|
||||
#else
|
||||
/* DAC has only one output */
|
||||
(void) line;
|
||||
|
||||
_sync();
|
||||
DAC->DATA.reg = DAC_VAL(value);
|
||||
#endif
|
||||
}
|
||||
|
||||
void dac_poweron(dac_t line)
|
||||
{
|
||||
(void) line;
|
||||
|
||||
#ifdef PM_APBCMASK_DAC
|
||||
PM->APBCMASK.reg |= PM_APBCMASK_DAC;
|
||||
#endif
|
||||
#ifdef MCLK_APBCMASK_DAC
|
||||
MCLK->APBCMASK.reg |= MCLK_APBCMASK_DAC;
|
||||
#endif
|
||||
#ifdef MCLK_APBDMASK_DAC
|
||||
MCLK->APBDMASK.reg |= MCLK_APBDMASK_DAC;
|
||||
#endif
|
||||
}
|
||||
|
||||
void dac_poweroff(dac_t line)
|
||||
{
|
||||
(void) line;
|
||||
|
||||
#ifdef PM_APBCMASK_DAC
|
||||
PM->APBCMASK.reg &= ~PM_APBCMASK_DAC;
|
||||
#endif
|
||||
#ifdef MCLK_APBCMASK_DAC
|
||||
MCLK->APBCMASK.reg &= ~MCLK_APBCMASK_DAC;
|
||||
#endif
|
||||
#ifdef MCLK_APBDMASK_DAC
|
||||
MCLK->APBDMASK.reg &= ~MCLK_APBDMASK_DAC;
|
||||
#endif
|
||||
}
|
@ -115,6 +115,17 @@ typedef enum {
|
||||
} adc_res_t;
|
||||
/** @} */
|
||||
#endif /* ndef DOXYGEN */
|
||||
|
||||
/**
|
||||
* @brief The MCU has a 10 bit DAC
|
||||
*/
|
||||
#define DAC_RES_BITS (10)
|
||||
|
||||
/**
|
||||
* @brief The MCU has one DAC Output.
|
||||
*/
|
||||
#define DAC_NUMOF (1)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -69,6 +69,16 @@ enum {
|
||||
*/
|
||||
#define SPI_HWCS(x) (UINT_MAX - 1)
|
||||
|
||||
/**
|
||||
* @brief The MCU has a 12 bit DAC
|
||||
*/
|
||||
#define DAC_RES_BITS (12)
|
||||
|
||||
/**
|
||||
* @brief The MCU has two DAC outputs.
|
||||
*/
|
||||
#define DAC_NUMOF (2)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -62,6 +62,16 @@ typedef enum {
|
||||
#endif /* ndef DOXYGEN */
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief The MCU has a 10 bit DAC
|
||||
*/
|
||||
#define DAC_RES_BITS (10)
|
||||
|
||||
/**
|
||||
* @brief The MCU has one DAC Output.
|
||||
*/
|
||||
#define DAC_NUMOF (1)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -62,6 +62,16 @@ typedef enum {
|
||||
/** @} */
|
||||
#endif /* ndef DOXYGEN */
|
||||
|
||||
/**
|
||||
* @brief The MCU has a 12 bit DAC
|
||||
*/
|
||||
#define DAC_RES_BITS (12)
|
||||
|
||||
/**
|
||||
* @brief The MCU has two DAC outputs.
|
||||
*/
|
||||
#define DAC_NUMOF (2)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user