From 78d18f6c74a9f918c99ae14d24e2fb0f3513e63d Mon Sep 17 00:00:00 2001 From: Jeff McBride Date: Mon, 18 May 2020 13:39:04 -0700 Subject: [PATCH] [dac] Add basic STM32F4 driver --- src/modm/platform/dac/stm32/dac.hpp | 123 +++++++++++++++++++++++ src/modm/platform/dac/stm32/dac_impl.hpp | 68 +++++++++++++ src/modm/platform/dac/stm32/module.lb | 24 +++++ src/modm/platform/gpio/stm32/pin.hpp.in | 9 ++ 4 files changed, 224 insertions(+) create mode 100644 src/modm/platform/dac/stm32/dac.hpp create mode 100644 src/modm/platform/dac/stm32/dac_impl.hpp create mode 100644 src/modm/platform/dac/stm32/module.lb diff --git a/src/modm/platform/dac/stm32/dac.hpp b/src/modm/platform/dac/stm32/dac.hpp new file mode 100644 index 0000000000..68249d6f86 --- /dev/null +++ b/src/modm/platform/dac/stm32/dac.hpp @@ -0,0 +1,123 @@ +#ifndef MODM_STM32_DAC_HPP +#define MODM_STM32_DAC_HPP + +#include +#include "../device.hpp" +#include + +namespace modm { + +namespace platform { + +/** + * Digital-to-Analog Converter (DAC) + * + * Supports simple synchronous access to the 2-channel DAC found on most STM32 + * microcontrollers. + * + * @author Jeff McBride + * @ingroup modm_platform_dac + */ +class Dac { +public: + /** + * The DAC has two output channels, Channel1 and Channel2 + */ + enum class Channel : uint8_t { + Channel1 = 0, + Channel2 = 1 + }; + + template< template class... Signals > + static void + connect() + { + using Connector = GpioConnector; + Connector::connect(); + } + + /** + * Initialize the D/A converter. + * + * Enables the RCC clock output for the DAC + */ + static inline void initialize(); + + /** Enable DAC output for the given channel + * + * @param chan The channel to be enabled + * + * @pre The DAC clock must be enabled with initialize() + */ + static inline void enableChannel(Channel chan); + + /** + * Disable DAC output for the given channel + * + * @param chan The channel to be disabled + * + * @pre The DAC clock must be enabled with initialize() + */ + static inline void disableChannel(Channel chan); + + /** + * Control the output buffer setting + * + * @param chan The channel to enable/disable the output buffer on + * @param enable true to turn on the output buffer, false to turn it off + * + * @pre The DAC clock must be enabled with initialize() + */ + static inline void enableOutputBuffer(Channel chan, bool enable); + + /** + * Set the output voltage for a DAC channel + * + * @param chan The channel to set + * @param value The 12-bit DAC output value, range 0-4095. + * + * @pre The DAC clock must be enabled with initialize() + */ + static inline void setOutput(Channel chan, uint16_t value); + + /** + * Set output value for Channel1 + * + * Equivalent to setOutput(modm::platform::Dac::Channel1, value) + * + * @param value The 12-bit DAC output value, range 0-4095 + * + * @pre The DAC clock must be enabled with initialize() + */ + static inline void setOutput1(uint16_t value); + + /** + * Set output value for Channel2 + * + * Equivalent to setOutput(modm::platform::Dac::Channel2, value) + * + * @param value The 12-bit DAC output value, range 0-4095 + * + * @pre The DAC clock must be enabled with initialize() + */ + static inline void setOutput2(uint16_t value); + + /// Get the channel for a Pin + template< class Gpio > + static inline constexpr Channel + getPinChannel() + { + constexpr int8_t channel{Gpio::template DacChannel}; + static_assert(channel >= 0, "Dac does not have a channel for this pin!"); + return Channel(channel); + } + +}; + +} // namespace platform + +} // namespace modm + +#include "dac_impl.hpp" + +#endif // MODM_STM32_DAC_HPP \ No newline at end of file diff --git a/src/modm/platform/dac/stm32/dac_impl.hpp b/src/modm/platform/dac/stm32/dac_impl.hpp new file mode 100644 index 0000000000..5dd1e9b775 --- /dev/null +++ b/src/modm/platform/dac/stm32/dac_impl.hpp @@ -0,0 +1,68 @@ +#ifndef MODM_STM32_DAC_HPP +# error "Don't include this file directly, use 'dac.hpp' instead!" +#endif + +#include + +void modm::platform::Dac::initialize() { + Rcc::enable(); +} + +void modm::platform::Dac::enableChannel(Channel chan) { + switch(chan) { + case Channel::Channel1: + DAC1->CR |= DAC_CR_EN1_Msk; + break; + case Channel::Channel2: + DAC1->CR |= DAC_CR_EN2_Msk; + break; + } +} + +void modm::platform::Dac::disableChannel(Channel chan) { + switch(chan) { + case Channel::Channel1: + DAC1->CR &= ~DAC_CR_EN1_Msk; + break; + case Channel::Channel2: + DAC1->CR &= ~DAC_CR_EN2_Msk; + break; + } +} + +void modm::platform::Dac::enableOutputBuffer(Channel chan, bool enable) { + uint32_t chanShift = 0; + switch(chan) { + case Channel::Channel1: + chanShift = 0; + break; + case Channel::Channel2: + chanShift = 16; + break; + }; + + if(enable) { + DAC1->CR &= ~(DAC_CR_BOFF1_Msk << chanShift); + } else { + DAC1->CR |= DAC_CR_BOFF1_Msk << chanShift; + } +} + +void modm::platform::Dac::setOutput(Channel chan, uint16_t value) { + switch(chan) { + case Channel::Channel1: + DAC1->DHR12R1 = value & DAC_DHR12R1_DACC1DHR_Msk; + break; + case Channel::Channel2: + DAC1->DHR12R2 = value & DAC_DHR12R2_DACC2DHR_Msk; + break; + } +} + +void modm::platform::Dac::setOutput1(uint16_t value) { + setOutput(Channel::Channel1, value); +} + +void modm::platform::Dac::setOutput2(uint16_t value) { + setOutput(Channel::Channel2, value); +} \ No newline at end of file diff --git a/src/modm/platform/dac/stm32/module.lb b/src/modm/platform/dac/stm32/module.lb new file mode 100644 index 0000000000..dac90cb6c3 --- /dev/null +++ b/src/modm/platform/dac/stm32/module.lb @@ -0,0 +1,24 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import os + +def init(module): + module.name = ":platform:dac" + module.description = "Digital-to-Analog Converter (DAC)" + +def prepare(module, options): + if not options[":target"].has_driver("dac:stm32"): + return False + + if not options[":target"].identifier.family == 'f4': + return False + + module.depends(":cmsis:device") + + return True + +def build(env): + env.outbasepath = "modm/src/modm/platform/dac" + env.copy("dac.hpp") + env.copy("dac_impl.hpp") \ No newline at end of file diff --git a/src/modm/platform/gpio/stm32/pin.hpp.in b/src/modm/platform/gpio/stm32/pin.hpp.in index 956d889eb9..b6c58e2ed9 100644 --- a/src/modm/platform/gpio/stm32/pin.hpp.in +++ b/src/modm/platform/gpio/stm32/pin.hpp.in @@ -209,6 +209,8 @@ public: private: template< Peripheral peripheral > static constexpr int8_t AdcChannel = -1; + template< Peripheral peripheral > + static constexpr int8_t DacChannel = -1; }; /// @cond @@ -245,6 +247,13 @@ template<> constexpr int8_t Gpio{{ port ~ pin }}::AdcChannel = {{ signal.name | to_adc_channel }}; %% endif + + %% if signal.driver.startswith("Dac") and signal.name.startswith("Out") +template<> +constexpr int8_t +Gpio{{ port ~ pin }}::DacChannel = {{ signal.name | to_adc_channel }}; + %% endif + %% endfor %% endfor