Skip to content

Commit

Permalink
[sam] Add driver for SAMG timer channels
Browse files Browse the repository at this point in the history
  • Loading branch information
mcbridejc authored and salkinium committed Feb 9, 2022
1 parent c868f59 commit f5cdf6a
Show file tree
Hide file tree
Showing 8 changed files with 600 additions and 2 deletions.
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -449,7 +449,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
86 changes: 86 additions & 0 deletions examples/samg55_xplained_pro/timer/main.cpp
@@ -0,0 +1,86 @@
/*
* Copyright (c) 2021, Jeff McBride
*
* This file is part of the modm project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

#include <modm/board.hpp>
#include <modm/io/iostream.hpp>
#include <modm/platform.hpp>

using namespace modm::platform;
using namespace modm::literals;

MODM_ISR(TC3)
{
// Clear pending interrupts by reading them
(void)TimerChannel3::getInterruptFlags();

static bool flag = false;
if (flag)
{
TimerChannel0::setTiobEffects(TimerChannel0::TioEffect::Clear,
TimerChannel0::TioEffect::Set);
} else
{
TimerChannel0::setTiobEffects(TimerChannel0::TioEffect::Set,
TimerChannel0::TioEffect::Clear);
}
flag = !flag;
}

int
main()
{
/*
* This example uses channel 0 to generate two output waveforms, and channel3
* to create a periodic IRQ which swaps the polarity on the TIOB output.
*
* Note:
* On the SAMG55, the waveform outputs on the second module (TC1, TimerChannel[3-5])
* are not connected to external pins.
*/
Board::initialize();

TimerChannel0::initialize();
TimerChannel0::connect<GpioA0::Tioa, GpioA1::Tiob>();

TimerChannel0::setClockSource(TimerChannel0::ClockSource::MckDiv2);
TimerChannel0::setWaveformMode(true);
// Setup timer to count up, and trigger reset on Rc match
TimerChannel0::setWaveformSelection(TimerChannel0::WavSel::Up_Rc);

// Setup TioA to set on RA match, and clear on RC match
TimerChannel0::setTioaEffects(TimerChannel0::TioEffect::Set, TimerChannel0::TioEffect::Clear);
// Setup TioB to clear on RB match, and set on RC match
TimerChannel0::setTiobEffects(TimerChannel0::TioEffect::Clear, TimerChannel0::TioEffect::Set);

// Change external event source, so that TIOB can be used as an output
TimerChannel0::setExtEventSource(TimerChannel0::ExtEventSource::Xc0);

TimerChannel0::setRegA(10000);
TimerChannel0::setRegB(5000);
TimerChannel0::setRegC(15000);

TimerChannel0::enable();
TimerChannel0::start();

// Setup TC3 irq to swap TIOB polarity periodically
// Period = 128 * 10000 / 120MHz = ~10.6ms
TimerChannel3::initialize();
TimerChannel3::setClockSource(TimerChannel0::ClockSource::MckDiv128);
TimerChannel3::setRegC(10000);
TimerChannel3::setWaveformMode(true);
TimerChannel3::setWaveformSelection(TimerChannel0::WavSel::Up_Rc);
TimerChannel3::enableInterruptVector(true);
TimerChannel3::enableInterrupt(TimerChannel3::Interrupt::RcCompare);
TimerChannel3::enable();
TimerChannel3::start();

while (true)
;
}
6 changes: 6 additions & 0 deletions examples/samg55_xplained_pro/timer/openocd.cfg
@@ -0,0 +1,6 @@

# Configure for ATSAMG55-XPRO dev board
source [find interface/cmsis-dap.cfg]

set CHIPNAME ATSAMG55J19
source [find target/at91samg5x.cfg]
14 changes: 14 additions & 0 deletions examples/samg55_xplained_pro/timer/project.xml
@@ -0,0 +1,14 @@
<library>
<extends>modm:samg55-xplained-pro</extends>
<options>
<option name="modm:build:build.path">../../../build/samg55_xplained_pro/timer</option>
<option name="modm:build:openocd.cfg">openocd.cfg</option>
</options>
<modules>
<module>modm:build:scons</module>
<module>modm:platform:timer:0</module>
<module>modm:platform:timer:1</module>
<module>modm:platform:timer:2</module>
<module>modm:platform:timer:3</module>
</modules>
</library>
11 changes: 10 additions & 1 deletion src/modm/board/samg55_xplained_pro/board.hpp
Expand Up @@ -27,7 +27,16 @@ struct SystemClock

static constexpr uint32_t Frequency = PllAMult * SlowClkFreqHz; // CPU core frequency
static constexpr uint32_t Usb = PllBMult * SlowClkFreqHz;
static constexpr uint32_t Mck = Frequency; // Master clock, used by most peripherals
static constexpr uint32_t Mck = Frequency; // Master clock: default used by most peripherals
// Programmable clocks: optionally used by certain peripherals
static constexpr uint32_t Pck0 = Mck;
static constexpr uint32_t Pck1 = Mck;
static constexpr uint32_t Pck2 = Mck;
static constexpr uint32_t Pck3 = Mck;
static constexpr uint32_t Pck4 = Mck;
static constexpr uint32_t Pck5 = Mck;
static constexpr uint32_t Pck6 = Mck;
static constexpr uint32_t Pck7 = Mck;

static bool inline
enable()
Expand Down
67 changes: 67 additions & 0 deletions src/modm/platform/timer/samg/module.lb
@@ -0,0 +1,67 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Copyright (c) 2021, Jeff McBride
#
# This file is part of the modm project.
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
# -----------------------------------------------------------------------------

props = {}
class Instance(Module):
def __init__(self, driver, instance, channel):
self.driver = driver
self.instance = int(instance)
self.channel = channel
self.vectors = None

def init(self, module):
module.name = str(self.instance)
module.description = "Instance {}".format(self.instance)

def prepare(self, module, options):
return True

def build(self, env):
global props
props["id"] = self.instance
props["module"] = int(self.instance / 3)
props["channel"] = self.channel

env.substitutions = props
env.outbasepath = "modm/src/modm/platform/timer"
env.template("timer_channel.hpp.in", "timer_channel_{}.hpp".format(self.instance))

def init(module):
module.name = ":platform:timer"
module.description = "Timers (TC)"

def prepare(module, options):
device = options[":target"]
if not device.has_driver("tc:samg*"):
return False

module.depends(
":cmsis:device",
":platform:gpio")

timers = device.get_all_drivers("tc:samg*")
for driver in timers:
for instance in driver["instance"]:
instance = int(instance)
# Each TC instance has 3 channels, and we create an independent driver for each
for channel in range(3):
module.add_submodule(Instance(driver, instance*3+channel, channel))

global props
device = options[":target"]
props["target"] = device.identifier

return True

def build(env):
env.outbasepath = "modm/src/modm/platform/timer"
env.copy("timer_channel_base.hpp")

0 comments on commit f5cdf6a

Please sign in to comment.