1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/cpu/sam0_common/periph/dac.c
Dylan Laduranty 292111a244 cpu/sam0/periph: remove bitfield usage in DAC driver
Signed-off-by: Dylan Laduranty <dylan.laduranty@mesotic.com>
2024-06-21 09:29:58 +02:00

186 lines
3.9 KiB
C

/*
* 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 <assert.h>
#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.reg & DAC_STATUS_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.reg &= ~DAC_CTRLA_ENABLE;
_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.reg |= DAC_CTRLA_ENABLE;
_sync();
#ifdef DAC_STATUS_READY
/* wait for DAC startup */
const uint32_t mask = 1 << (DAC_STATUS_READY_Pos + line);
while (!(DAC->STATUS.reg & mask)) {}
#endif
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
}