From 69cb810738db1266345ac315ab56341c1b18d6e9 Mon Sep 17 00:00:00 2001 From: Alex E Date: Mon, 4 Aug 2025 00:51:23 +0200 Subject: [PATCH] [STM32F3/G4] add full api for settig edge and source of the trigger from regular and injected. [STM32F3/G4] added set offset api --- src/modm/platform/adc/stm32f3/adc.hpp.in | 102 ++++++++++++++++++ src/modm/platform/adc/stm32f3/adc_impl.hpp.in | 70 ++++++++++++ 2 files changed, 172 insertions(+) diff --git a/src/modm/platform/adc/stm32f3/adc.hpp.in b/src/modm/platform/adc/stm32f3/adc.hpp.in index 893a0f64a2..aa9f1268c2 100644 --- a/src/modm/platform/adc/stm32f3/adc.hpp.in +++ b/src/modm/platform/adc/stm32f3/adc.hpp.in @@ -309,6 +309,14 @@ public: %% endif }; + enum class ExternalTriggerPolarity + { + NoTriggerDetection = 0x0u, + RisingEdge = 0x1u, + FallingEdge = 0x2u, + RisingAndFallingEdge = 0x3u, + }; + enum class Interrupt : uint32_t { Ready = ADC_IER_ADRDYIE, @@ -342,6 +350,57 @@ public: }; MODM_FLAGS32(InterruptFlag); + /** + * Enum mapping all events on a external trigger converter. + * The source mapped to each event varies on controller family, + * refer to the ADC external trigger section on reference manual + * of your controller for more information + */ + enum class RegularConversionExternalTrigger + { + Event0 = 0x00u, + Event1 = 0x01u, + Event2 = 0x02u, + Event3 = 0x03u, + Event4 = 0x04u, + Event5 = 0x05u, + Event6 = 0x06u, + Event7 = 0x07u, + Event9 = 0x09u, + Event10 = 0x0Au, + Event11 = 0x0Bu, + Event12 = 0x0Cu, + Event13 = 0x0Du, + Event14 = 0x0Eu, + Event15 = 0x0Fu, +%% if target["family"] in ["g4"] + Event16 = 0x10u, + Event17 = 0x11u, + Event18 = 0x12u, + Event19 = 0x13u, + Event20 = 0x14u, + Event21 = 0x15u, + Event22 = 0x16u, + Event23 = 0x17u, + Event24 = 0x18u, + Event25 = 0x19u, + Event26 = 0x1Au, + Event27 = 0x1Bu, + Event28 = 0x1Cu, + Event29 = 0x1Du, + Event30 = 0x1Eu, + Event31 = 0x1Fu, +%% endif + }; + + enum class OffsetSlot : uint8_t + { + Slot0 = 0, + Slot1 = 1, + Slot2 = 2, + Slot3 = 3, + }; + public: template< class... Signals > static void @@ -499,6 +558,18 @@ public: static inline void stopConversion(); + /** + * enable regular conversions on external trigger. + * + * @param externalTriggerPolarity + * Polarity of the external trigger signal. + * @param regularConversionExternalTrigger + * Regular conversion external trigger source. + */ + static inline void enableRegularConversionExternalTrigger( + ExternalTriggerPolarity externalTriggerPolarity, + RegularConversionExternalTrigger regularConversionExternalTrigger); + /** * @return If the conversion is finished. * @pre A conversion should have been started with startConversion() @@ -539,6 +610,18 @@ public: static inline bool setInjectedConversionSequenceLength(uint8_t length); + /** + * enable injected conversions on external trigger. + * + * @param externalTriggerPolarity + * Polarity of the external trigger signal. + * @param regularConversionExternalTrigger + * Regular conversion external trigger source. + */ + static inline void enableInjectedConversionExternalTrigger( + ExternalTriggerPolarity externalTriggerPolarity, + RegularConversionExternalTrigger regularConversionExternalTrigger); + /** * @return If the injected conversion sequence is finished. * @pre An injected conversion should have been started with startInjectedConversionSequence() @@ -585,6 +668,25 @@ public: } } + /** + * @arg slot for the offset register (0..3) + * @arg channel channel to which the offset is applied + * @arg offset offset value to be applied to the channel + */ + static inline bool + setChannelOffset(OffsetSlot slot, Channel channel, int16_t offset, bool saturate = false, bool enable = true); + + /** + * @arg slot for the offset register (0..3) + * @return offset value applied to the channel + */ + template + static inline bool + setChannelOffset(OffsetSlot slot, int16_t offset, bool saturate = false, bool enable = true) + { + return setChannelOffset(slot, getPinChannel(), offset, saturate, enable); + } + static inline void enableInterruptVector(const uint32_t priority, const bool enable = true); diff --git a/src/modm/platform/adc/stm32f3/adc_impl.hpp.in b/src/modm/platform/adc/stm32f3/adc_impl.hpp.in index a8b59115bf..4cde747f2f 100644 --- a/src/modm/platform/adc/stm32f3/adc_impl.hpp.in +++ b/src/modm/platform/adc/stm32f3/adc_impl.hpp.in @@ -302,6 +302,17 @@ modm::platform::Adc{{ id }}::isConversionSequenceFinished() return static_cast(getInterruptFlags() & InterruptFlag::EndOfRegularSequenceOfConversions); } +void +modm::platform::Adc{{ id }}::enableRegularConversionExternalTrigger( + ExternalTriggerPolarity externalTriggerPolarity, + RegularConversionExternalTrigger regularConversionExternalTrigger) +{ + const auto polarity = (static_cast(externalTriggerPolarity) << ADC_CFGR_EXTEN_Pos); + const auto externalTrigger = (static_cast(regularConversionExternalTrigger) << ADC_CFGR_EXTSEL_Pos); + const auto mask = ADC_CFGR_EXTEN_Msk | ADC_CFGR_EXTSEL_Msk; + ADC{{ id }}->CFGR = (ADC{{ id }}->CFGR & ~mask) | polarity | externalTrigger; +} + void modm::platform::Adc{{ id }}::startInjectedConversionSequence() { @@ -351,6 +362,19 @@ modm::platform::Adc{{ id }}::setInjectedConversionSequenceLength(uint8_t length) return true; } +void +modm::platform::Adc{{ id }}::enableInjectedConversionExternalTrigger( + ExternalTriggerPolarity externalTriggerPolarity, + RegularConversionExternalTrigger regularConversionExternalTrigger) +{ + const auto polarity = (static_cast(externalTriggerPolarity) << ADC_JSQR_JEXTEN_Pos); + const auto externalTrigger = + (static_cast(regularConversionExternalTrigger) << ADC_JSQR_JEXTSEL_Pos); + const auto mask = ADC_JSQR_JEXTEN_Msk | ADC_JSQR_JEXTSEL_Msk; + ADC{{ id }}->JSQR = (ADC{{ id }}->JSQR & ~mask) | polarity | externalTrigger; +} + + bool modm::platform::Adc{{ id }}::isInjectedConversionFinished() { @@ -410,3 +434,49 @@ modm::platform::Adc{{ id }}::acknowledgeInterruptFlags(const InterruptFlag_t fla // Writing a zero is ignored. ADC{{ id }}->ISR = flags.value; } + +/** + * @arg slot for the offset register (0..3) + * @arg channel channel to which the offset is applied + * @arg offset offset value to be applied to the channel + * @return true if configuration is successful, false if the ADC is currently converting + */ +bool +modm::platform::Adc{{ id }}::setChannelOffset(OffsetSlot slot, Channel channel, int16_t offset, + bool saturate, bool enable) +{ + if ( (ADC{{ id }}->CR & ADC_CR_JADSTART) || (ADC{{ id }}->CR & ADC_CR_ADSTART) ) { + // ADC is currently converting, cannot set offset + return false; + } + +%% if target["family"] in["f3"] + // F3 does not support signed offsets, so signMask is always 0 + static_assert(offset >= 0, "F3 ADC offsets must be positive"); + const uint32_t signMask = 0u; + + // F3 does not support saturation, so saturateMask is always 0 + static_assert(!saturate, "F3 ADC does not support saturation"); + const uint32_t saturateMask = 0u; +%% else + const uint32_t signMask = (offset > 0) ? ADC_OFR1_OFFSETPOS : 0u; + const uint32_t saturateMask = saturate ? ADC_OFR1_SATEN : 0u; +%% endif + + const uint32_t channelMask = (static_cast(channel) << ADC_OFR1_OFFSET1_CH_Pos) & ADC_OFR1_OFFSET1_CH_Msk; + const uint32_t offsetMask = (std::abs(offset) << ADC_OFR1_OFFSET1_Pos) & ADC_OFR1_OFFSET1_Msk; + const uint32_t enableMask = enable ? ADC_OFR1_OFFSET1_EN : 0u; + const uint32_t offsetValue = channelMask | offsetMask | saturateMask | enableMask | signMask; + + switch (slot) + { + case OffsetSlot::Slot0: ADC{{id}}->OFR1 = offsetValue; break; + case OffsetSlot::Slot1: ADC{{id}}->OFR2 = offsetValue; break; + case OffsetSlot::Slot2: ADC{{id}}->OFR3 = offsetValue; break; + case OffsetSlot::Slot3: ADC{{id}}->OFR4 = offsetValue; break; + default: + return false; // invalid slot + } + + return true; +}