Skip to content

Commit

Permalink
[sam] Add support for SAMx7x devices in SAMG55 Timer / Counter driver
Browse files Browse the repository at this point in the history
  • Loading branch information
chris-durand committed Feb 5, 2023
1 parent afdb5ba commit 4c8f2b2
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 44 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,7 @@ Please [discover modm's peripheral drivers for your specific device][discover].
<td align="center">✅</td>
<td align="center">○</td>
<td align="center">○</td>
<td align="center"></td>
<td align="center"></td>
<td align="center">✅</td>
<td align="center">○</td>
<td align="center">○</td>
Expand Down
9 changes: 6 additions & 3 deletions src/modm/platform/timer/samg/module.lb
Original file line number Diff line number Diff line change
Expand Up @@ -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.
#
Expand Down Expand Up @@ -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)
Expand All @@ -64,4 +66,5 @@ def prepare(module, options):

def build(env):
env.outbasepath = "modm/src/modm/platform/timer"
env.copy("timer_channel_base.hpp")
env.substitutions = props
env.template("timer_channel_base.hpp.in", "timer_channel_base.hpp")
148 changes: 109 additions & 39 deletions src/modm/platform/timer/samg/timer_channel.hpp.in
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2021, Jeff McBride
* Copyright (c) 2023, Christopher Durand
*
* This file is part of the modm project.
*
Expand All @@ -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 }}
*
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -86,39 +115,57 @@ 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
*/
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
Expand All @@ -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
Expand All @@ -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
}
Expand All @@ -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
Expand All @@ -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<Interrupt_t>({{ ch }}.TC_SR & 0x3f);
%% else
return static_cast<Interrupt_t>({{ 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
Expand All @@ -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;
}
}

Expand All @@ -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
Expand All @@ -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
Expand All @@ -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;
}

};
Expand Down

0 comments on commit 4c8f2b2

Please sign in to comment.