From 4c8f2b2fec0b2f1a2195c28a134b45254ce711d1 Mon Sep 17 00:00:00 2001 From: Christopher Durand Date: Sun, 5 Feb 2023 15:17:36 +0100 Subject: [PATCH] [sam] Add support for SAMx7x devices in SAMG55 Timer / Counter driver --- README.md | 2 +- src/modm/platform/timer/samg/module.lb | 9 +- .../platform/timer/samg/timer_channel.hpp.in | 148 +++++++++++++----- ...nel_base.hpp => timer_channel_base.hpp.in} | 9 +- 4 files changed, 124 insertions(+), 44 deletions(-) rename src/modm/platform/timer/samg/{timer_channel_base.hpp => timer_channel_base.hpp.in} (94%) 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