@@ -302,6 +302,17 @@ modm::platform::Adc{{ id }}::isConversionSequenceFinished()
302302 return static_cast<bool>(getInterruptFlags() & InterruptFlag::EndOfRegularSequenceOfConversions);
303303}
304304
305+ void
306+ modm::platform::Adc{{ id }}::enableRegularConversionExternalTrigger(
307+ ExternalTriggerPolarity externalTriggerPolarity,
308+ RegularConversionExternalTrigger regularConversionExternalTrigger)
309+ {
310+ const auto polarity = (static_cast<uint32_t>(externalTriggerPolarity) << ADC_CFGR_EXTEN_Pos);
311+ const auto externalTrigger = (static_cast<uint32_t>(regularConversionExternalTrigger) << ADC_CFGR_EXTSEL_Pos);
312+ const auto mask = ADC_CFGR_EXTEN_Msk | ADC_CFGR_EXTSEL_Msk;
313+ ADC{{ id }}->CFGR = (ADC{{ id }}->CFGR & ~mask) | polarity | externalTrigger;
314+ }
315+
305316void
306317modm::platform::Adc{{ id }}::startInjectedConversionSequence()
307318{
@@ -351,6 +362,19 @@ modm::platform::Adc{{ id }}::setInjectedConversionSequenceLength(uint8_t length)
351362 return true;
352363}
353364
365+ void
366+ modm::platform::Adc{{ id }}::enableInjectedConversionExternalTrigger(
367+ ExternalTriggerPolarity externalTriggerPolarity,
368+ RegularConversionExternalTrigger regularConversionExternalTrigger)
369+ {
370+ const auto polarity = (static_cast<uint32_t>(externalTriggerPolarity) << ADC_JSQR_JEXTEN_Pos);
371+ const auto externalTrigger =
372+ (static_cast<uint32_t>(regularConversionExternalTrigger) << ADC_JSQR_JEXTSEL_Pos);
373+ const auto mask = ADC_JSQR_JEXTEN_Msk | ADC_JSQR_JEXTSEL_Msk;
374+ ADC{{ id }}->JSQR = (ADC{{ id }}->JSQR & ~mask) | polarity | externalTrigger;
375+ }
376+
377+
354378bool
355379modm::platform::Adc{{ id }}::isInjectedConversionFinished()
356380{
@@ -410,3 +434,70 @@ modm::platform::Adc{{ id }}::acknowledgeInterruptFlags(const InterruptFlag_t fla
410434 // Writing a zero is ignored.
411435 ADC{{ id }}->ISR = flags.value;
412436}
437+
438+ /**
439+ * @arg slot for the offset register (0..3)
440+ * @arg channel channel to which the offset is applied
441+ * @arg offset offset value to be applied to the channel
442+ * @return true if configuration is successful, false if the ADC is currently converting
443+ */
444+ bool
445+ modm::platform::Adc{{ id }}::setChannelOffset(const OffsetSlot slot, const Channel channel, const int16_t offset,
446+ const bool saturate, const bool enable)
447+ {
448+ if ( (ADC{{ id }}->CR & ADC_CR_JADSTART) || (ADC{{ id }}->CR & ADC_CR_ADSTART) ) {
449+ // ADC is currently converting, cannot set offset
450+ return false;
451+ }
452+
453+ %% if target["family"] in["f3", "l4", "l5"] or (target["family"] in["h7"] and target["name"][0] in["4", "5", "a", "b"]):
454+ // F3 or H74x/H75x does not support signed offsets, so signMask is always 0
455+ if (offset < 0) {
456+ return false; // F3 ADC offsets must be positive
457+ }
458+ const uint32_t signMask = 0u;
459+
460+ // F3 or H74x/H75x does not support saturation, so saturateMask is always 0
461+ if (saturate) {
462+ return false; // F3 ADC does not support saturation
463+ }
464+ const uint32_t saturateMask = 0u;
465+
466+ %% elif target["family"] in["h7"]
467+ // H7 names the bits differently, but the logic is the same
468+ const uint32_t signMask = (offset > 0) ? ADC3_OFR1_OFFSETPOS : 0u;
469+ const uint32_t saturateMask = saturate ? ADC3_OFR1_SATEN : 0u;
470+ %% else
471+ const uint32_t signMask = (offset > 0) ? ADC_OFR1_OFFSETPOS : 0u;
472+ const uint32_t saturateMask = saturate ? ADC_OFR1_SATEN : 0u;
473+ %% endif
474+
475+ %% if target["family"] in ["h7"]
476+ %% if target["name"][0] in ["4" , "5", "a", "b"]
477+ (void)enable; // H74x does not have an enable bit for the offset register
478+ const uint32_t enableMask = 0u;
479+ %% else
480+ // H7 uses a different register bit names
481+ const uint32_t enableMask = enable ? ADC3_OFR1_OFFSET1_EN : 0u;
482+ %% endif
483+ %% else
484+ const uint32_t enableMask = enable ? ADC_OFR1_OFFSET1_EN : 0u;
485+ %% endif
486+
487+ const uint32_t channelMask = (static_cast<uint32_t>(channel) << ADC_OFR1_OFFSET1_CH_Pos) & ADC_OFR1_OFFSET1_CH_Msk;
488+ const uint32_t offsetMask = (std::abs(offset) << ADC_OFR1_OFFSET1_Pos) & ADC_OFR1_OFFSET1_Msk;
489+
490+ const uint32_t offsetValue = channelMask | offsetMask | saturateMask | enableMask | signMask;
491+
492+ switch (slot)
493+ {
494+ case OffsetSlot::Slot0: ADC{{id}}->OFR1 = offsetValue; break;
495+ case OffsetSlot::Slot1: ADC{{id}}->OFR2 = offsetValue; break;
496+ case OffsetSlot::Slot2: ADC{{id}}->OFR3 = offsetValue; break;
497+ case OffsetSlot::Slot3: ADC{{id}}->OFR4 = offsetValue; break;
498+ default:
499+ return false; // invalid slot
500+ }
501+
502+ return true;
503+ }
0 commit comments