Skip to content

Commit

Permalink
[gpio] Add basic SAMD connect implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
henrikssn authored and salkinium committed Jul 8, 2020
1 parent 7b6f342 commit 2ed785d
Show file tree
Hide file tree
Showing 6 changed files with 144 additions and 7 deletions.
22 changes: 21 additions & 1 deletion src/modm/platform/gpio/sam/base.hpp.in
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2020, Niklas Hauser
* Copyright (c) 2020, Erik Henriksson
*
* This file is part of the modm project.
*
Expand Down Expand Up @@ -60,7 +61,7 @@ struct Gpio

/// The Port a Gpio Pin is connected to.
enum class
Port
PortName
{
%% for port in ports
{{ port | upper }} = {{ port | modm.ord }},
Expand All @@ -72,9 +73,28 @@ struct Gpio
Signal
{
BitBang,
%% for signal in all_signals
{{ signal }},
%% endfor
};
/// @endcond

enum class
SercomRxPad
{
Pad0 = 0x0,
Pad1 = 0x1,
Pad2 = 0x2,
Pad3 = 0x3,
};

enum class
SercomTxPad
{
Pad0 = 0x0,
Pad2 = 0x1,
};

protected:
/// @cond
/// I/O Direction Mode values for this specific pin.
Expand Down
56 changes: 54 additions & 2 deletions src/modm/platform/gpio/sam/module.lb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#
# Copyright (c) 2016-2018, Niklas Hauser
# Copyright (c) 2017, Fabian Greif
# Copyright (c) 2020, Erik Henriksson
#
# This file is part of the modm project.
#
Expand All @@ -25,6 +26,30 @@ def port_ranges(gpios):
ports.sort(key=lambda p: p["name"])
return ports

def translate(s):
name = ""
for part in s.split("_"):
name += part.capitalize()
return name

def get_driver(s):
name = "None"
if "driver" in s: name = translate(s["driver"]);
if "instance" in s: name += translate(s["instance"]);
return name

def get_name(s):
return translate(s["name"])

def extract_signals(signals):
afs = {}
for s in signals:
driver = get_driver(s)
name = get_name(s)
key = driver + name
afs[key] = {"driver": driver, "name": name, "af": s["af"]}
return afs

bprops = {}

# -----------------------------------------------------------------------------
Expand All @@ -43,6 +68,34 @@ def prepare(module, options):
":math:utils")
return True

def validate(env):
device = env[":target"]
driver = device.get_driver("gpio")

all_signals = {}
for gpio in driver["gpio"]:
key = gpio["port"] + gpio["pin"]
raw_signals = gpio["signal"] if "signal" in gpio else []
for signal in raw_signals:
if "af" in signal:
signal["af"] = [signal["af"]]
else:
signal["af"] = []
gpio["signal"] = raw_signals
extracted_signals = extract_signals(raw_signals)
all_signals.update(extracted_signals)
signal_names = sorted(list(set(s["name"] for s in extracted_signals.values())))
extracted_signals = OrderedDict([(name, sorted([s for s in extracted_signals.values() if s["name"] == name], key=lambda si:si["name"])) for name in signal_names])
bprops[key] = {
"gpio": gpio,
"signals": extracted_signals
}

all_peripherals = [s["driver"] for s in all_signals.values()]

bprops["all_peripherals"] = sorted(list(set(all_peripherals)))
bprops["all_signals"] = sorted(list(set(s["name"] for s in all_signals.values())))

def build(env):
device = env[":target"]
driver = device.get_driver("gpio")
Expand All @@ -57,9 +110,8 @@ def build(env):

for gpio in driver["gpio"]:
po, pi = gpio["port"], gpio["pin"]
properties["gpio"] = gpio
properties.update(bprops[po + pi])
env.template("pin.hpp.in", "gpio_{}{}.hpp".format(po.upper(), pi))

# env.template("port.hpp.in")
# env.template("software_port.hpp.in")
env.template("set.hpp.in")
Expand Down
4 changes: 4 additions & 0 deletions src/modm/platform/gpio/sam/peripherals.hpp.in
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2019, Niklas Hauser
* Copyright (c) 2020, Erik Henriksson
*
* This file is part of the modm project.
*
Expand All @@ -18,6 +19,9 @@ enum class
Peripheral
{
BitBang,
%% for per in all_peripherals
{{ per }},
%% endfor
};

}
63 changes: 62 additions & 1 deletion src/modm/platform/gpio/sam/pin.hpp.in
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2017-2018, Niklas Hauser
* Copyright (c) 2020, Erik Henriksson
*
* This file is part of the modm project.
*
Expand Down Expand Up @@ -45,7 +46,7 @@ public:
using IO = Gpio{{ port ~ pin }};
using Type = Gpio{{ port ~ pin }};
static constexpr bool isInverted = false;
static constexpr Port port = Port::{{port}}; ///< Port name
static constexpr PortName port = PortName::{{port}}; ///< Port name
static constexpr uint8_t pin = {{pin|int}}; ///< Pin number

protected:
Expand Down Expand Up @@ -107,6 +108,66 @@ public:
inline static void disconnect() {
setInput(InputType::Floating);
}
template< Peripheral peripheral >
struct BitBang { static void connect();
static_assert(
(peripheral == Peripheral::BitBang),
"Gpio{{ port ~ pin }}::BitBang only connects to software drivers!");
};
%% for signal_name, signal_group in signals.items()
template< Peripheral peripheral >
struct {{ signal_name }} { static void connect();
static_assert(
%% for signal in signal_group
(peripheral == Peripheral::{{ signal.driver }}){% if loop.last %},{% else %} ||{% endif %}
%% endfor
"Gpio{{ port ~ pin }}::{{ signal_name }} only connects to {% for signal in signal_group %}{{signal.driver}}{% if not loop.last %} or {% endif %}{% endfor %}!");
};
%% endfor
};

/// @cond
template<>
struct Gpio{{ port ~ pin }}::BitBang<Peripheral::BitBang>
{
using Gpio = Gpio{{ port ~ pin }};
static constexpr Gpio::Signal Signal = Gpio::Signal::BitBang;
static constexpr int af = -1;
inline static void connect() {}
};
%% for signal_group in signals.values()
%% for signal in signal_group
template<>
struct Gpio{{ port ~ pin }}::{{ signal.name }}<Peripheral::{{ signal.driver }}>
{
using Gpio = Gpio{{ port ~ pin }};
static constexpr Gpio::Signal Signal = Gpio::Signal::{{ signal.name }};
%% if signal.driver.startswith("Sercom")
static constexpr Gpio::SercomRxPad RxPad = Gpio::SercomRxPad::{{ signal.name }};
%% endif
%% if signal.driver.startswith("Sercom") and signal.name in ("Pad0", "Pad2")
static constexpr Gpio::SercomTxPad TxPad = Gpio::SercomTxPad::{{ signal.name }};
%% endif
inline static void
connect()
{
//## FIXME: Support using alternate function (see stm32).
%% if signal.driver.startswith("Sercom")
PORT->Group[uint32_t(Gpio::port)].PINCFG[uint32_t(Gpio::pin)].bit.PMUXEN = true;
if (Gpio::pin & 1u) {
PORT->Group[uint32_t(Gpio::port)].PMUX[uint32_t(Gpio::pin) >> 1].reg |= PORT_PMUX_PMUXO_C;
} else {
PORT->Group[uint32_t(Gpio::port)].PMUX[uint32_t(Gpio::pin) >> 1].reg |= PORT_PMUX_PMUXE_C;
}
%% endif
}
};

%% endfor

%% endfor


/// @endcond

} // namespace modm::platform
4 changes: 2 additions & 2 deletions src/modm/platform/gpio/sam/set.hpp.in
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,14 @@ class GpioSet : public Gpio
protected:
static constexpr uint32_t inverteds[{{ ports | length }}] = {
%% for port in ports
(((Gpios::port == Port::{{port}} and Gpios::isInverted) ? Gpios::mask : 0) | ...),
(((Gpios::port == PortName::{{port}} and Gpios::isInverted) ? Gpios::mask : 0) | ...),
%% endfor
};
static constexpr uint32_t inverted(uint8_t id) { return inverteds[id]; }

static constexpr uint32_t masks[{{ ports | length }}] = {
%% for port in ports
(((Gpios::port == Port::{{port}}) ? Gpios::mask : 0) | ...),
(((Gpios::port == PortName::{{port}}) ? Gpios::mask : 0) | ...),
%% endfor
};
static constexpr uint32_t mask(uint8_t id) { return masks[id]; }
Expand Down
2 changes: 1 addition & 1 deletion src/modm/platform/gpio/sam/unused.hpp.in
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public:
using IO = GpioUnused;
using Type = GpioUnused;
static constexpr bool isInverted = false;
static constexpr Port port = Port(-1);
static constexpr PortName port = PortName(-1);
static constexpr uint8_t pin = uint8_t(-1);
static constexpr uint32_t mask = 0;

Expand Down

0 comments on commit 2ed785d

Please sign in to comment.