diff --git a/README.md b/README.md
index 3869243ff7..821ff9d1a9 100644
--- a/README.md
+++ b/README.md
@@ -469,7 +469,7 @@ Please [discover modm's peripheral drivers for your specific device][discover].
✅ |
○ |
○ |
-○ |
+✅ |
✅ |
○ |
○ |
diff --git a/src/modm/platform/timer/samg/module.lb b/src/modm/platform/timer/samg/module.lb
index b6283d9272..127e75abdf 100644
--- a/src/modm/platform/timer/samg/module.lb
+++ b/src/modm/platform/timer/samg/module.lb
@@ -2,6 +2,7 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2021, Jeff McBride
+# Copyright (c) 2023, Christopher Durand
#
# This file is part of the modm project.
#
@@ -41,14 +42,15 @@ def init(module):
def prepare(module, options):
device = options[":target"]
- if not device.has_driver("tc:samg*"):
+ family = device.identifier.family
+ if not device.has_driver("tc:sam*") or family not in ["g5x", "e7x/s7x/v7x"]:
return False
module.depends(
":cmsis:device",
":platform:gpio")
- timers = device.get_all_drivers("tc:samg*")
+ timers = device.get_all_drivers("tc:sam*")
for driver in timers:
for instance in driver["instance"]:
instance = int(instance)
@@ -64,4 +66,5 @@ def prepare(module, options):
def build(env):
env.outbasepath = "modm/src/modm/platform/timer"
- env.copy("timer_channel_base.hpp")
\ No newline at end of file
+ env.substitutions = props
+ env.template("timer_channel_base.hpp.in", "timer_channel_base.hpp")
diff --git a/src/modm/platform/timer/samg/timer_channel.hpp.in b/src/modm/platform/timer/samg/timer_channel.hpp.in
index 4e0e6f45bc..188e7d23eb 100644
--- a/src/modm/platform/timer/samg/timer_channel.hpp.in
+++ b/src/modm/platform/timer/samg/timer_channel.hpp.in
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2021, Jeff McBride
+ * Copyright (c) 2023, Christopher Durand
*
* This file is part of the modm project.
*
@@ -18,6 +19,14 @@
namespace modm::platform
{
+%% if target.family == "g5x"
+%% set ch = "TC{}->TC_CHANNEL[{}]".format(module, channel)
+%% set cmr_wav = "TC_CMR"
+%% else
+%% set ch = "TC{}->TcChannel[{}]".format(module, channel)
+%% set cmr_wav = "TC_CMR_WAVEFORM"
+%% endif
+
/**
* @brief Timer Channel {{ id }}
*
@@ -47,6 +56,26 @@ namespace modm::platform
class TimerChannel{{ id }} : public TimerChannelBase
{
public:
+%% if target.family == "e7x/s7x/v7x"
+ /// Input clock selection values
+ enum class ClockSource : uint32_t
+ {
+%% if id | int == 0
+ Pck7 = 0,
+%% else
+ Pck6 = 0,
+%% endif
+ MckDiv8 = 1,
+ MckDiv32 = 2,
+ MckDiv128 = 3,
+ Slck = 4,
+ Xc0 = 5,
+ Xc1 = 6,
+ Xc2 = 7,
+ Mck = 0xFFFF'FFFF
+ };
+%% endif
+
template< class... Pins >
static void
connect()
@@ -86,9 +115,22 @@ public:
static inline void
setClockSource(ClockSource src)
{
- uint32_t tmp = TC{{ module }}->TC_CHANNEL[{{ channel }}].TC_CMR & ~(TC_CMR_TCCLKS_Msk);
+%% if target.family == "e7x/s7x/v7x"
+ if (src == ClockSource::Mck) {
+ {{ ch }}.TC_EMR |= TC_EMR_NODIVCLK;
+ return;
+ } else {
+ uint32_t tmp = {{ ch }}.TC_CMR & ~(TC_CMR_TCCLKS_Msk);
+ tmp |= (uint32_t)src << TC_CMR_TCCLKS_Pos;
+ {{ ch }}.TC_CMR = tmp;
+
+ {{ ch }}.TC_EMR &= ~TC_EMR_NODIVCLK;
+ }
+%% else
+ uint32_t tmp = {{ ch }}.TC_CMR & ~(TC_CMR_TCCLKS_Msk);
tmp |= (uint32_t)src << TC_CMR_TCCLKS_Pos;
- TC{{ module }}->TC_CHANNEL[{{ channel }}].TC_CMR = tmp;
+ {{ ch }}.TC_CMR = tmp;
+%% endif
}
/** Returns the currently selected clock source
@@ -96,29 +138,34 @@ public:
static inline ClockSource
getClockSource()
{
- uint32_t cmr = TC{{ module }}->TC_CHANNEL[{{ channel }}].TC_CMR;
+%% if target.family == "e7x/s7x/v7x"
+ if ({{ ch }}.TC_EMR & TC_EMR_NODIVCLK) {
+ return ClockSource::Mck;
+ }
+%% endif
+ const uint32_t cmr = {{ ch }}.TC_CMR;
return (ClockSource)((cmr & TC_CMR_TCCLKS_Msk) >> TC_CMR_TCCLKS_Pos);
}
static inline void
setWaveformSelection(WavSel ws)
{
- uint32_t cmr = TC{{ module }}->TC_CHANNEL[{{ channel }}].TC_CMR;
- cmr &= ~TC_CMR_WAVSEL_Msk;
- cmr |= (uint32_t)ws << TC_CMR_WAVSEL_Pos;
- TC{{ module }}->TC_CHANNEL[{{ channel }}].TC_CMR = cmr;
+ uint32_t cmr = {{ ch }}.TC_CMR;
+ cmr &= ~{{ cmr_wav }}_WAVSEL_Msk;
+ cmr |= (uint32_t)ws << {{ cmr_wav }}_WAVSEL_Pos;
+ {{ ch }}.TC_CMR = cmr;
}
static inline void
enable()
{
- TC{{ module }}->TC_CHANNEL[{{ channel }}].TC_CCR = TC_CCR_CLKEN;
+ {{ ch }}.TC_CCR = TC_CCR_CLKEN;
}
static inline void
disable()
{
- TC{{ module }}->TC_CHANNEL[{{ channel }}].TC_CCR = TC_CCR_CLKDIS;
+ {{ ch }}.TC_CCR = TC_CCR_CLKDIS;
}
static inline void
@@ -130,49 +177,49 @@ public:
static inline uint16_t
getValue()
{
- return TC{{ module }}->TC_CHANNEL[{{ channel }}].TC_CV;
+ return {{ ch }}.TC_CV;
}
static inline void
setValue(uint16_t value)
{
- TC{{ module }}->TC_CHANNEL[{{ channel }}].TC_CV = value;
+ {{ ch }}.TC_CV = value;
}
static inline uint16_t
getRegA()
{
- return TC{{ module }}->TC_CHANNEL[{{ channel }}].TC_RA;
+ return {{ ch }}.TC_RA;
}
static inline void
setRegA(uint16_t value)
{
- TC{{ module }}->TC_CHANNEL[{{ channel }}].TC_RA = value;
+ {{ ch }}.TC_RA = value;
}
static inline uint16_t
getRegB()
{
- return TC{{ module }}->TC_CHANNEL[{{ channel }}].TC_RB;
+ return {{ ch }}.TC_RB;
}
static inline void
setRegB(uint16_t value)
{
- TC{{ module }}->TC_CHANNEL[{{ channel }}].TC_RB = value;
+ {{ ch }}.TC_RB = value;
}
static inline uint16_t
getRegC()
{
- return TC{{ module }}->TC_CHANNEL[{{ channel }}].TC_RC;
+ return {{ ch }}.TC_RC;
}
static inline void
setRegC(uint16_t value)
{
- TC{{ module }}->TC_CHANNEL[{{ channel }}].TC_RC = value;
+ {{ ch }}.TC_RC = value;
}
/** Return the frequency of the counter based on current configuration
@@ -186,16 +233,35 @@ public:
{
switch(getClockSource())
{
+%% if target.family == "e7x/s7x/v7x"
+%% if id | int == 0
+ case ClockSource::Pck7:
+ return SystemClock::Pck7;
+%% else
+ case ClockSource::Pck6:
+ return SystemClock::Pck6;
+%% endif
+%% endif
+%% if target.family == "g5x"
case ClockSource::MckDiv2:
return SystemClock::Mck / 2;
+%% endif
case ClockSource::MckDiv8:
return SystemClock::Mck / 8;
case ClockSource::MckDiv32:
return SystemClock::Mck / 32;
case ClockSource::MckDiv128:
return SystemClock::Mck / 128;
+%% if target.family == "g5x"
case ClockSource::Pck3:
return SystemClock::Pck3;
+%% endif
+%% if target.family == "e7x/s7x/v7x"
+ case ClockSource::Slck:
+ return SystemClock::Slck;
+ case ClockSource::Mck:
+ return SystemClock::Mck;
+%% endif
default:
return 0; // Clocked externally, so we can't know the frequency
}
@@ -218,14 +284,14 @@ public:
*/
static inline void enableInterrupt(Interrupt_t interrupts)
{
- TC{{ module }}->TC_CHANNEL[{{ channel }}].TC_IER = interrupts.value;
+ {{ ch }}.TC_IER = interrupts.value;
}
/** Disable interrupt in peripheral interrupt mask register
*/
static inline void disableInterrupt(Interrupt_t interrupts)
{
- TC{{ module }}->TC_CHANNEL[{{ channel }}].TC_IDR = interrupts.value;
+ {{ ch }}.TC_IDR = interrupts.value;
}
/** Reads the currently pending interrupt flags
@@ -234,13 +300,17 @@ public:
*/
static inline Interrupt_t getInterruptFlags()
{
- return (Interrupt_t)(TC{{ module }}->TC_CHANNEL[{{ channel }}].TC_SR & 0x3f);
+%% if target.family == "g5x"
+ return static_cast({{ ch }}.TC_SR & 0x3f);
+%% else
+ return static_cast({{ ch }}.TC_SR & 0xf);
+%% endif
}
/** Generate a software trigger event */
static inline void softwareTrigger()
{
- TC{{ module }}->TC_CHANNEL[{{ channel }}].TC_CCR = TC_CCR_SWTRG;
+ {{ ch }}.TC_CCR = TC_CCR_SWTRG;
}
/** Enable or disable waveform mode
@@ -250,9 +320,9 @@ public:
static inline void setWaveformMode(bool enabled)
{
if(enabled) {
- TC{{ module }}->TC_CHANNEL[{{ channel }}].TC_CMR |= TC_CMR_WAVE;
+ {{ ch }}.TC_CMR |= TC_CMR_WAVE;
} else {
- TC{{ module }}->TC_CHANNEL[{{ channel }}].TC_CMR &= ~TC_CMR_WAVE;
+ {{ ch }}.TC_CMR &= ~TC_CMR_WAVE;
}
}
@@ -264,10 +334,10 @@ public:
*/
static inline void setExtEventSource(ExtEventSource src)
{
- uint32_t cmr = TC{{ module }}->TC_CHANNEL[{{ channel }}].TC_CMR;
+ uint32_t cmr = {{ ch }}.TC_CMR;
cmr &= ~TC_CMR_EEVT_Msk;
cmr |= (uint32_t)src << TC_CMR_EEVT_Pos;
- TC{{ module }}->TC_CHANNEL[{{ channel }}].TC_CMR = cmr;
+ {{ ch }}.TC_CMR = cmr;
}
/** Set the effect of events on the TIOA output in waveform mode
@@ -278,13 +348,13 @@ public:
TioEffect extEvent = TioEffect::None,
TioEffect swTrig = TioEffect::None)
{
- uint32_t tmp = TC{{ module }}->TC_CHANNEL[{{ channel }}].TC_CMR;
- tmp &= ~(TC_CMR_ACPA_Msk | TC_CMR_ACPC_Msk | TC_CMR_AEEVT_Msk | TC_CMR_ASWTRG_Msk);
- tmp |= ((uint32_t)raCompare << TC_CMR_ACPA_Pos) |
- ((uint32_t)rcCompare << TC_CMR_ACPC_Pos) |
- ((uint32_t)extEvent << TC_CMR_AEEVT_Pos) |
- ((uint32_t)swTrig << TC_CMR_ASWTRG_Pos);
- TC{{ module }}->TC_CHANNEL[{{ channel }}].TC_CMR = tmp;
+ uint32_t tmp = {{ ch }}.TC_CMR;
+ tmp &= ~({{ cmr_wav }}_ACPA_Msk | {{ cmr_wav }}_ACPC_Msk | {{ cmr_wav }}_AEEVT_Msk | {{ cmr_wav }}_ASWTRG_Msk);
+ tmp |= ((uint32_t)raCompare << {{ cmr_wav }}_ACPA_Pos) |
+ ((uint32_t)rcCompare << {{ cmr_wav }}_ACPC_Pos) |
+ ((uint32_t)extEvent << {{ cmr_wav }}_AEEVT_Pos) |
+ ((uint32_t)swTrig << {{ cmr_wav }}_ASWTRG_Pos);
+ {{ ch }}.TC_CMR = tmp;
}
/** Set the effect of events on the TIOB output in waveform mode
@@ -299,13 +369,13 @@ public:
TioEffect extEvent = TioEffect::None,
TioEffect swTrig = TioEffect::None)
{
- uint32_t tmp = TC{{ module }}->TC_CHANNEL[{{ channel }}].TC_CMR;
- tmp &= ~(TC_CMR_BCPB_Msk | TC_CMR_BCPC_Msk | TC_CMR_BEEVT_Msk | TC_CMR_BSWTRG_Msk);
- tmp |= ((uint32_t)rbCompare << TC_CMR_BCPB_Pos) |
- ((uint32_t)rcCompare << TC_CMR_BCPC_Pos) |
- ((uint32_t)extEvent << TC_CMR_BEEVT_Pos) |
- ((uint32_t)swTrig << TC_CMR_BSWTRG_Pos);
- TC{{ module }}->TC_CHANNEL[{{ channel }}].TC_CMR = tmp;
+ uint32_t tmp = {{ ch }}.TC_CMR;
+ tmp &= ~({{ cmr_wav }}_BCPB_Msk | {{ cmr_wav }}_BCPC_Msk | {{ cmr_wav }}_BEEVT_Msk | {{ cmr_wav }}_BSWTRG_Msk);
+ tmp |= ((uint32_t)rbCompare << {{ cmr_wav }}_BCPB_Pos) |
+ ((uint32_t)rcCompare << {{ cmr_wav }}_BCPC_Pos) |
+ ((uint32_t)extEvent << {{ cmr_wav }}_BEEVT_Pos) |
+ ((uint32_t)swTrig << {{ cmr_wav }}_BSWTRG_Pos);
+ {{ ch }}.TC_CMR = tmp;
}
};
diff --git a/src/modm/platform/timer/samg/timer_channel_base.hpp b/src/modm/platform/timer/samg/timer_channel_base.hpp.in
similarity index 94%
rename from src/modm/platform/timer/samg/timer_channel_base.hpp
rename to src/modm/platform/timer/samg/timer_channel_base.hpp.in
index 5325fbf08e..1fcabf66f4 100644
--- a/src/modm/platform/timer/samg/timer_channel_base.hpp
+++ b/src/modm/platform/timer/samg/timer_channel_base.hpp.in
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2021, Jeff McBride
+ * Copyright (c) 2023, Christopher Durand
*
* This file is part of the modm project.
*
@@ -46,6 +47,7 @@ class TimerChannelBase
UpDown_Rc = 3 // UPDOWN mode with automatic trigger on RC compare
};
+%% if target.family == "g5x"
/// Input clock selection values
enum class ClockSource : uint32_t
{
@@ -58,6 +60,7 @@ class TimerChannelBase
Xc1 = 6,
Xc2 = 7
};
+%% endif
/// Interrupt flags
enum class Interrupt : uint32_t
@@ -70,11 +73,14 @@ class TimerChannelBase
RaLoading = TC_IER_LDRAS,
RbLoading = TC_IER_LDRBS,
ExternalTrigger = TC_IER_ETRGS,
+%% if target.family == "g5x"
EndOfRxTransfer = TC_IER_ENDRX,
- RxBufferFull = TC_IER_RXBUFF,
+ RxBufferFull = TC_IER_RXBUFF
+%% endif
};
MODM_FLAGS32(Interrupt);
+%% if target.family == "g5x"
// The CMR register has dual definitions: one for capture mode and one for
// waveform mode. However it seems that only the capture mode bit definitions
// made it into the CMSIS device header. Here, the missing waveform mode
@@ -99,6 +105,7 @@ class TimerChannelBase
static const uint32_t TC_CMR_BEEVT_Msk = (0x3) << TC_CMR_BEEVT_Pos;
static const uint32_t TC_CMR_BSWTRG_Pos = 30;
static const uint32_t TC_CMR_BSWTRG_Msk = (0x3) << TC_CMR_BSWTRG_Pos;
+%% endif
};
} // namespace modm::platform