Skip to content

Commit d771a5c

Browse files
committed
[STM32F3/G4/L4/H7] add ext. trigger and offset api
1 parent 7d9070d commit d771a5c

File tree

2 files changed

+264
-0
lines changed

2 files changed

+264
-0
lines changed

src/modm/platform/adc/stm32f3/adc.hpp.in

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,14 @@ public:
309309
%% endif
310310
};
311311

312+
enum class ExternalTriggerPolarity
313+
{
314+
NoTriggerDetection = 0x0u,
315+
RisingEdge = 0x1u,
316+
FallingEdge = 0x2u,
317+
RisingAndFallingEdge = 0x3u,
318+
};
319+
312320
enum class Interrupt : uint32_t
313321
{
314322
Ready = ADC_IER_ADRDYIE,
@@ -342,6 +350,57 @@ public:
342350
};
343351
MODM_FLAGS32(InterruptFlag);
344352

353+
/**
354+
* Enum mapping all events on a external trigger converter.
355+
* The source mapped to each event varies on controller family,
356+
* refer to the ADC external trigger section on reference manual
357+
* of your controller for more information
358+
*/
359+
enum class RegularConversionExternalTrigger
360+
{
361+
Event0 = 0x00u,
362+
Event1 = 0x01u,
363+
Event2 = 0x02u,
364+
Event3 = 0x03u,
365+
Event4 = 0x04u,
366+
Event5 = 0x05u,
367+
Event6 = 0x06u,
368+
Event7 = 0x07u,
369+
Event9 = 0x09u,
370+
Event10 = 0x0Au,
371+
Event11 = 0x0Bu,
372+
Event12 = 0x0Cu,
373+
Event13 = 0x0Du,
374+
Event14 = 0x0Eu,
375+
Event15 = 0x0Fu,
376+
%% if target["family"] in ["g4"]
377+
Event16 = 0x10u,
378+
Event17 = 0x11u,
379+
Event18 = 0x12u,
380+
Event19 = 0x13u,
381+
Event20 = 0x14u,
382+
Event21 = 0x15u,
383+
Event22 = 0x16u,
384+
Event23 = 0x17u,
385+
Event24 = 0x18u,
386+
Event25 = 0x19u,
387+
Event26 = 0x1Au,
388+
Event27 = 0x1Bu,
389+
Event28 = 0x1Cu,
390+
Event29 = 0x1Du,
391+
Event30 = 0x1Eu,
392+
Event31 = 0x1Fu,
393+
%% endif
394+
};
395+
396+
enum class OffsetSlot : uint8_t
397+
{
398+
Slot0 = 0,
399+
Slot1 = 1,
400+
Slot2 = 2,
401+
Slot3 = 3,
402+
};
403+
345404
public:
346405
template< class... Signals >
347406
static void
@@ -499,6 +558,23 @@ public:
499558
static inline void
500559
stopConversion();
501560

561+
/**
562+
* enable regular conversions on external trigger.
563+
*
564+
* @param externalTriggerPolarity
565+
* Polarity of the external trigger signal.
566+
* @param regularConversionExternalTrigger
567+
* Regular conversion external trigger source.
568+
*/
569+
static inline void enableRegularConversionExternalTrigger(
570+
ExternalTriggerPolarity externalTriggerPolarity,
571+
RegularConversionExternalTrigger regularConversionExternalTrigger);
572+
573+
/**
574+
* Disable regular conversions external trigger.
575+
*/
576+
static inline void disableRegularConversionExternalTrigger( void );
577+
502578
/**
503579
* @return If the conversion is finished.
504580
* @pre A conversion should have been started with startConversion()
@@ -539,6 +615,23 @@ public:
539615
static inline bool
540616
setInjectedConversionSequenceLength(uint8_t length);
541617

618+
/**
619+
* enable injected conversions on external trigger.
620+
*
621+
* @param externalTriggerPolarity
622+
* Polarity of the external trigger signal.
623+
* @param regularConversionExternalTrigger
624+
* Regular conversion external trigger source.
625+
*/
626+
static inline void enableInjectedConversionExternalTrigger(
627+
ExternalTriggerPolarity externalTriggerPolarity,
628+
RegularConversionExternalTrigger regularConversionExternalTrigger);
629+
630+
/**
631+
* Disable injected conversions external trigger.
632+
*/
633+
static inline void disableInjectedConversionExternalTrigger();
634+
542635
/**
543636
* @return If the injected conversion sequence is finished.
544637
* @pre An injected conversion should have been started with startInjectedConversionSequence()
@@ -585,6 +678,46 @@ public:
585678
}
586679
}
587680

681+
/**
682+
* @arg slot for the offset register (0..3)
683+
* @arg channel channel to which the offset is applied
684+
* @arg offset offset value to be applied to the channel
685+
* @arg saturate if true, the adc result value is saturated to the range of the ADC
686+
* @return true if the offset was successfully enabled, false if the slot is invalid
687+
*/
688+
static inline bool
689+
enableChannelOffset(OffsetSlot slot, Channel channel, int16_t offset, bool saturate = false);
690+
691+
/**
692+
* @arg slot for the offset register (0..3)
693+
* @arg saturate if true, the adc result value is saturated to the range of the ADC
694+
* @arg offset value applied to the channel
695+
* @return true if the offset was successfully enabled, false if the slot is invalid
696+
* @note The channel is determined by the GPIO pin type.
697+
*/
698+
template<class Gpio>
699+
static inline bool
700+
enableChannelOffset(OffsetSlot slot, int16_t offset, bool saturate = false)
701+
{
702+
return enableChannelOffset(slot, getPinChannel<Gpio>(), offset, saturate);
703+
}
704+
705+
/**
706+
* @arg slot for the offset register (0..3)
707+
* @return true if the offset was successfully disabled, false if the slot is invalid
708+
*/
709+
static inline bool disableChannelOffset(OffsetSlot slot);
710+
711+
/**
712+
* @arg slot for the offset register (0..3)
713+
* @return true if the offset was successfully disabled, false if the slot is invalid
714+
*/
715+
template<class Gpio>
716+
static inline bool disableChannelOffset(OffsetSlot slot)
717+
{
718+
return disableChannelOffset(slot);
719+
}
720+
588721
static inline void
589722
enableInterruptVector(const uint32_t priority, const bool enable = true);
590723

src/modm/platform/adc/stm32f3/adc_impl.hpp.in

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,25 @@ 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+
316+
void
317+
modm::platform::Adc{{ id }}::disableRegularConversionExternalTrigger()
318+
{
319+
// Disable regular conversions external trigger by clearing the bits
320+
// for polarity and external trigger source.
321+
ADC{{ id }}->CFGR &= ~(ADC_CFGR_EXTEN_Msk | ADC_CFGR_EXTSEL_Msk);
322+
}
323+
305324
void
306325
modm::platform::Adc{{ id }}::startInjectedConversionSequence()
307326
{
@@ -351,6 +370,26 @@ modm::platform::Adc{{ id }}::setInjectedConversionSequenceLength(uint8_t length)
351370
return true;
352371
}
353372

373+
void
374+
modm::platform::Adc{{ id }}::enableInjectedConversionExternalTrigger(
375+
ExternalTriggerPolarity externalTriggerPolarity,
376+
RegularConversionExternalTrigger regularConversionExternalTrigger)
377+
{
378+
const auto polarity = (static_cast<uint32_t>(externalTriggerPolarity) << ADC_JSQR_JEXTEN_Pos);
379+
const auto externalTrigger =
380+
(static_cast<uint32_t>(regularConversionExternalTrigger) << ADC_JSQR_JEXTSEL_Pos);
381+
const auto mask = ADC_JSQR_JEXTEN_Msk | ADC_JSQR_JEXTSEL_Msk;
382+
ADC{{ id }}->JSQR = (ADC{{ id }}->JSQR & ~mask) | polarity | externalTrigger;
383+
}
384+
385+
void
386+
modm::platform::Adc{{ id }}::disableInjectedConversionExternalTrigger()
387+
{
388+
// Disable injected conversions external trigger by clearing the bits
389+
// for polarity and external trigger source.
390+
ADC{{id}}->JSQR &= ~(ADC_JSQR_JEXTEN_Msk | ADC_JSQR_JEXTSEL_Msk);
391+
}
392+
354393
bool
355394
modm::platform::Adc{{ id }}::isInjectedConversionFinished()
356395
{
@@ -410,3 +449,95 @@ modm::platform::Adc{{ id }}::acknowledgeInterruptFlags(const InterruptFlag_t fla
410449
// Writing a zero is ignored.
411450
ADC{{ id }}->ISR = flags.value;
412451
}
452+
453+
bool
454+
modm::platform::Adc{{ id }}::enableChannelOffset(const OffsetSlot slot, const Channel channel, const int16_t offset,
455+
const bool saturate)
456+
{
457+
if ( (ADC{{ id }}->CR & ADC_CR_JADSTART) || (ADC{{ id }}->CR & ADC_CR_ADSTART) ) {
458+
// ADC is currently converting, cannot set offset
459+
return false;
460+
}
461+
462+
%% if target["family"] in ["f3", "l4", "l5"] or (target["family"] in ["h7"] and target["name"][0] in ["4", "5", "a", "b"]):
463+
// F3 or H74x/H75x does not support signed offsets, so signMask is always 0
464+
if (offset < 0) {
465+
return false; // F3 ADC offsets must be positive
466+
}
467+
const uint32_t signMask = 0u;
468+
469+
// F3 or H74x/H75x does not support saturation, so saturateMask is always 0
470+
if (saturate) {
471+
return false; // F3 ADC does not support saturation
472+
}
473+
const uint32_t saturateMask = 0u;
474+
475+
%% elif target["family"] in["h7"]
476+
%# H7 names the bits differently, but the logic is the same
477+
const uint32_t signMask = (offset > 0) ? ADC3_OFR1_OFFSETPOS : 0u;
478+
const uint32_t saturateMask = saturate ? ADC3_OFR1_SATEN : 0u;
479+
%% else
480+
const uint32_t signMask = (offset > 0) ? ADC_OFR1_OFFSETPOS : 0u;
481+
const uint32_t saturateMask = saturate ? ADC_OFR1_SATEN : 0u;
482+
%% endif
483+
484+
%% if target["family"] in ["h7"]
485+
%% if target["name"][0] in ["4" , "5", "a", "b"]
486+
%# no specific enable bit for H74x/H75x, so always 0
487+
const uint32_t enableMask = 0u;
488+
%% else
489+
%# H7 uses a different register bit names
490+
const uint32_t enableMask = ADC3_OFR1_OFFSET1_EN;
491+
%% endif
492+
%% else
493+
const uint32_t enableMask = ADC_OFR1_OFFSET1_EN;
494+
%% endif
495+
const uint32_t channelMask = (static_cast<uint32_t>(channel) << ADC_OFR1_OFFSET1_CH_Pos) & ADC_OFR1_OFFSET1_CH_Msk;
496+
const uint32_t offsetMask = (std::abs(offset) << ADC_OFR1_OFFSET1_Pos) & ADC_OFR1_OFFSET1_Msk;
497+
498+
const uint32_t offsetValue = channelMask | offsetMask | saturateMask | enableMask | signMask;
499+
500+
switch (slot)
501+
{
502+
case OffsetSlot::Slot0: ADC{{id}}->OFR1 = offsetValue; break;
503+
case OffsetSlot::Slot1: ADC{{id}}->OFR2 = offsetValue; break;
504+
case OffsetSlot::Slot2: ADC{{id}}->OFR3 = offsetValue; break;
505+
case OffsetSlot::Slot3: ADC{{id}}->OFR4 = offsetValue; break;
506+
default:
507+
return false; // invalid slot
508+
}
509+
510+
return true;
511+
}
512+
513+
bool
514+
modm::platform::Adc{{ id }}::disableChannelOffset(const OffsetSlot slot)
515+
{
516+
if ( (ADC{{ id }}->CR & ADC_CR_JADSTART) || (ADC{{ id }}->CR & ADC_CR_ADSTART) ) {
517+
// ADC is currently converting, cannot disable offset
518+
return false;
519+
}
520+
521+
%% if target["family"] in ["h7"]
522+
%% if target["name"][0] in ["4" , "5", "a", "b"]
523+
%# no specific enable bit for H74x/H75x, so always 0
524+
const uint32_t enableMask = ADC_OFR1_OFFSET1_Msk;
525+
%% else
526+
%#H7 uses a different register bit names
527+
const uint32_t enableMask = ADC3_OFR1_OFFSET1_EN;
528+
%% endif
529+
%% else
530+
const uint32_t enableMask = ADC_OFR1_OFFSET1_EN;
531+
%%endif
532+
533+
switch (slot)
534+
{
535+
case OffsetSlot::Slot0: ADC{{id}}->OFR1 &= ~enableMask; break;
536+
case OffsetSlot::Slot1: ADC{{id}}->OFR2 &= ~enableMask; break;
537+
case OffsetSlot::Slot2: ADC{{id}}->OFR3 &= ~enableMask; break;
538+
case OffsetSlot::Slot3: ADC{{id}}->OFR4 &= ~enableMask; break;
539+
default:
540+
return false; // invalid slot
541+
}
542+
return true;
543+
}

0 commit comments

Comments
 (0)