From dc56af2830b5108069841025eac2d65756e4fa35 Mon Sep 17 00:00:00 2001 From: Erik Henriksson Date: Wed, 7 Oct 2020 01:58:57 +0200 Subject: [PATCH] [gpio] Refactor SAM signals API --- examples/samd/interrupt/main.cpp | 38 +- examples/samd/usbserial/main.cpp | 3 +- ext/modm-devices | 2 +- src/modm/board/feather_m0/board.hpp | 17 +- src/modm/platform/extint/sam/extint.hpp | 46 ++- src/modm/platform/extint/sam/extint_impl.hpp | 23 +- src/modm/platform/gpio/sam/base.hpp.in | 125 ------ src/modm/platform/gpio/sam/config.hpp.in | 120 ++++++ src/modm/platform/gpio/sam/connector.hpp | 38 ++ src/modm/platform/gpio/sam/module.lb | 130 ++----- src/modm/platform/gpio/sam/module.md | 76 ++++ src/modm/platform/gpio/sam/peripherals.hpp.in | 27 -- src/modm/platform/gpio/sam/pin.hpp | 362 ++++++++++++++++++ src/modm/platform/gpio/sam/pin.hpp.in | 175 --------- src/modm/platform/gpio/sam/set.hpp.in | 141 ------- .../platform/gpio/sam/software_port.hpp.in | 90 ----- .../gpio/sam/{unused.hpp.in => unused.hpp} | 16 +- .../i2c/bitbang/bitbang_i2c_master_impl.hpp | 5 +- .../spi/bitbang/bitbang_spi_master_impl.hpp | 7 +- src/modm/platform/uart/sam/uart.hpp.in | 32 +- src/modm/platform/uart/sam/uart_hal.hpp.in | 1 - src/modm/platform/usb/sam/usb.hpp | 18 +- 22 files changed, 753 insertions(+), 739 deletions(-) delete mode 100644 src/modm/platform/gpio/sam/base.hpp.in create mode 100644 src/modm/platform/gpio/sam/config.hpp.in create mode 100644 src/modm/platform/gpio/sam/connector.hpp create mode 100644 src/modm/platform/gpio/sam/module.md delete mode 100644 src/modm/platform/gpio/sam/peripherals.hpp.in create mode 100644 src/modm/platform/gpio/sam/pin.hpp delete mode 100644 src/modm/platform/gpio/sam/pin.hpp.in delete mode 100644 src/modm/platform/gpio/sam/set.hpp.in delete mode 100644 src/modm/platform/gpio/sam/software_port.hpp.in rename src/modm/platform/gpio/sam/{unused.hpp.in => unused.hpp} (76%) diff --git a/examples/samd/interrupt/main.cpp b/examples/samd/interrupt/main.cpp index 481f0afd50..0e3a9aceb3 100644 --- a/examples/samd/interrupt/main.cpp +++ b/examples/samd/interrupt/main.cpp @@ -16,26 +16,30 @@ using namespace std::chrono_literals; static volatile bool blink = true; void -isr() { - blink = !blink; - // Kids, please don't do serial logging in ISRs... - MODM_LOG_DEBUG << "blink: " << (blink ? "true" : "false") << modm::endl; +isr() +{ + blink = !blink; + // Kids, please don't do serial logging in ISRs... + MODM_LOG_DEBUG << "blink: " << (blink ? "true" : "false") << modm::endl; } int main() { - Board::initialize(); - ExternalInterrupt::initialize(); - ExtInt<3>::initialize(&isr); - ExtInt<3>::connectPin(); - while (1) { - if (blink) { - Led::toggle(); - } else { - Led::set(0); - } - modm::delay(100ms); - } - return 0; + Board::initialize(); + ExternalInterrupt::initialize(); + ExtInt<3>::initialize(&isr); + ExtInt<3>::connect(); + while (1) + { + if (blink) + { + Led::toggle(); + } else + { + Led::set(0); + } + modm::delay(100ms); + } + return 0; } diff --git a/examples/samd/usbserial/main.cpp b/examples/samd/usbserial/main.cpp index f70cce4e08..c0a2226137 100644 --- a/examples/samd/usbserial/main.cpp +++ b/examples/samd/usbserial/main.cpp @@ -62,7 +62,8 @@ int main() TCC0->PER.bit.PER = SystemClock::Frequency / 1000; TCC0->CC[3].bit.CC = SystemClock::Frequency / 2000; TCC0->CTRLA.bit.ENABLE = true; - D12::Wo3::connect(); + using Tcc = Peripherals::Tcc<0>; + D12::As::Connector>::connect(); GenericClockController::connect(ClockGenerator::System); tusb_init(); diff --git a/ext/modm-devices b/ext/modm-devices index 80dbcb658e..462b3ed9ab 160000 --- a/ext/modm-devices +++ b/ext/modm-devices @@ -1 +1 @@ -Subproject commit 80dbcb658e006c9e39b9a0b992013b8cbece90fe +Subproject commit 462b3ed9ab25a6113f050f8cb6f467ed9b8a0e76 diff --git a/src/modm/board/feather_m0/board.hpp b/src/modm/board/feather_m0/board.hpp index d4a7936f11..f002b5ff3a 100644 --- a/src/modm/board/feather_m0/board.hpp +++ b/src/modm/board/feather_m0/board.hpp @@ -13,14 +13,13 @@ #pragma once +#include #include #include -#include #define MODM_BOARD_HAS_LOGGER using namespace modm::platform; - /// @ingroup modm_board_feather_m0 namespace Board { @@ -54,9 +53,9 @@ using Sda = GpioA23; using Scl = GpioA22; // For RFM69 / LoRa boards -using RadioRst = GpioA08; -using RadioIrq = GpioA09; -using RadioCs = GpioA06; +using RadioRst = GpioA08; +using RadioIrq = GpioA09; +using RadioCs = GpioA06; // This is the red LED by the USB jack. using Led = D13; @@ -101,15 +100,15 @@ struct SystemClock } }; -using LoggerDevice = modm::IODeviceWrapper< Uart0, modm::IOBuffer::BlockIfFull >; -using Leds = SoftwareGpioPort< Led >; +using LoggerDevice = modm::IODeviceWrapper; +using Leds = Led; inline void initialize() { SystemClock::enable(); SysTickTimer::initialize(); - Uart0::connect(); + Uart0::connect(); Uart0::initialize(); Led::setOutput(modm::Gpio::Low); @@ -122,4 +121,4 @@ initializeUsbFs() modm::platform::Usb::connect(); } -} // Board namespace +} // namespace Board diff --git a/src/modm/platform/extint/sam/extint.hpp b/src/modm/platform/extint/sam/extint.hpp index 8e5e36b371..a1ff5bf627 100644 --- a/src/modm/platform/extint/sam/extint.hpp +++ b/src/modm/platform/extint/sam/extint.hpp @@ -13,7 +13,7 @@ #include #include #include -#include +#include #pragma once @@ -25,14 +25,25 @@ namespace platform MODM_ISR_DECL(EIC); +enum class InputTrigger +{ + RisingEdge = EIC_CONFIG_SENSE0_RISE_Val, + FallingEdge = EIC_CONFIG_SENSE0_FALL_Val, + BothEdges = EIC_CONFIG_SENSE0_BOTH_Val, + High = EIC_CONFIG_SENSE0_HIGH_Val, + Low = EIC_CONFIG_SENSE0_LOW_Val, +}; + /** * External Interrupt handler for SAMD devices. * * @author Erik Henriksson * @ingroup modm_platform_extint */ -class ExternalInterrupt { +class ExternalInterrupt +{ friend void EIC_IRQHandler(void); + public: /** * Initializes the External Interrupt handler. @@ -42,11 +53,11 @@ class ExternalInterrupt { * be used to akeup the CPU from standby mode, make sure this clock is * actually running in standby. Defaults to external 32.768kHz crystal osc. */ - static void initialize( - ClockGenerator clockGen = ClockGenerator::ExternalCrystal32K, - int priority = (1ul << __NVIC_PRIO_BITS) - 1ul); + static void + initialize(ClockGenerator clockGen = ClockGenerator::ExternalCrystal32K, + int priority = (1ul << __NVIC_PRIO_BITS) - 1ul); - protected: +protected: static std::array, 16> handlers_; }; @@ -56,7 +67,8 @@ class ExternalInterrupt { * @author Erik Henriksson * @ingroup modm_platform_extint */ -template class ExtInt : private ExternalInterrupt +template +class ExtInt : private ExternalInterrupt { public: /** @@ -70,10 +82,9 @@ template class ExtInt : private ExternalInterrupt * If true (default), allows the CPU to wakeup from interrupt * from this instance. */ - static void initialize( - std::function handler, - Gpio::InputTrigger trigger = Gpio::InputTrigger::RisingEdge, - bool wakeupEnabled = true); + static void + initialize(std::function handler, InputTrigger trigger = InputTrigger::RisingEdge, + bool wakeupEnabled = true); /** * Connects a GPIO pin to this External Interrupt instance. @@ -81,15 +92,18 @@ template class ExtInt : private ExternalInterrupt * @tparam Pin * The GPIO pin to connect this instance to. */ - template + template static void - connectPin() { - Pin::template connectInterrupt(); + connect() + { + using Eic = Peripherals::Eic; + using Pin = typename GpioPin::template As; + Pin::template Connector>::connect(); } }; -} // namespace platform +} // namespace platform -} // namespace modm +} // namespace modm #include "extint_impl.hpp" \ No newline at end of file diff --git a/src/modm/platform/extint/sam/extint_impl.hpp b/src/modm/platform/extint/sam/extint_impl.hpp index c9ccd0a35d..0542b12c6d 100644 --- a/src/modm/platform/extint/sam/extint_impl.hpp +++ b/src/modm/platform/extint/sam/extint_impl.hpp @@ -11,29 +11,26 @@ #pragma once -namespace modm -{ -namespace platform +namespace modm::platform { template void -ExtInt::initialize( - std::function handler, - Gpio::InputTrigger trigger, - bool wakeupEnabled) { +ExtInt::initialize(std::function handler, InputTrigger trigger, + bool wakeupEnabled) +{ handlers_[instance] = handler; - if (wakeupEnabled) { + if (wakeupEnabled) + { EIC->WAKEUP.reg |= EIC_WAKEUP_WAKEUPEN(1u << instance); - } else { + } else + { EIC->WAKEUP.reg &= ~EIC_WAKEUP_WAKEUPEN(1u << instance); } - constexpr int sensePos = instance*EIC_CONFIG_SENSE1_Pos; + constexpr int sensePos = instance * EIC_CONFIG_SENSE1_Pos; EIC->CONFIG[instance & 0x8].reg &= EIC_CONFIG_SENSE0_Msk << sensePos; EIC->CONFIG[instance & 0x8].reg |= uint32_t(trigger) << sensePos; EIC->INTENSET.vec.EXTINT |= 1u << instance; } - -} // namespace platform -} // namespace modm +} // namespace modm::platform diff --git a/src/modm/platform/gpio/sam/base.hpp.in b/src/modm/platform/gpio/sam/base.hpp.in deleted file mode 100644 index 83c5baffe1..0000000000 --- a/src/modm/platform/gpio/sam/base.hpp.in +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (c) 2020, Niklas Hauser - * Copyright (c) 2020, Erik Henriksson - * - * 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/. - */ -// ---------------------------------------------------------------------------- - -#pragma once - -#include "../device.hpp" -#include -#include -#include - -namespace modm::platform -{ - -/// @ingroup modm_platform_gpio -struct Gpio -{ - enum class - InputType - { - Floating = 0x0, ///< floating on input - PullUp = 0x1, ///< pull-up on input - PullDown = 0x2, ///< pull-down on input - }; - - enum class - OutputType - { - PushPull = 0x0, ///< push-pull on output - OpenDrain = 0x1, ///< open-drain on output - }; - - enum class - OutputSpeed - { - Low = 0, - Medium = 0x1, - High = 0x2, - VeryHigh = 0x3, ///< 30 pF (80 MHz Output max speed on 15 pF) - MHz2 = Low, - MHz25 = Medium, - MHz50 = High, - MHz100 = VeryHigh, - }; - - enum class - InputTrigger - { - RisingEdge = EIC_CONFIG_SENSE0_RISE_Val, - FallingEdge = EIC_CONFIG_SENSE0_FALL_Val, - BothEdges = EIC_CONFIG_SENSE0_BOTH_Val, - High = EIC_CONFIG_SENSE0_HIGH_Val, - Low = EIC_CONFIG_SENSE0_LOW_Val, - }; - - /// The Port a Gpio Pin is connected to. - enum class - PortName - { -%% for port in ports - {{ port | upper }} = {{ port | modm.ord }}, -%% endfor - }; - - /// @cond - enum class - 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. - enum class - Mode - { - Input = 0x0, - Output = 0x1, - AlternateFunction = 0x2, - Analog = 0x3, - Mask = 0x3, - }; - - static constexpr uint32_t - i(Mode mode) { return uint32_t(mode); } - // Enum Class To Integer helper functions. - static constexpr uint32_t - i(InputType pull) { return uint32_t(pull); } - static constexpr uint32_t - i(OutputType out) { return uint32_t(out); } - static constexpr uint32_t - i(OutputSpeed speed) { return uint32_t(speed); } - /// @endcond -}; - -} // namespace modm::platform diff --git a/src/modm/platform/gpio/sam/config.hpp.in b/src/modm/platform/gpio/sam/config.hpp.in new file mode 100644 index 0000000000..ca55ca328e --- /dev/null +++ b/src/modm/platform/gpio/sam/config.hpp.in @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2020, Erik Henriksson + * + * 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/. + */ +// ---------------------------------------------------------------------------- + +#pragma once + +#include +#include + +namespace modm::platform +{ + +typedef uint32_t Instance; + +enum class PinFunction +{ +%% for function in functions + {{ function }}, +%% endfor +}; + +struct Peripherals +{ +%% for name, peripheral in peripherals.items() +%% if "instances" in peripheral + template +%% endif + struct {{ name }} + { +%% for signal, index_list in peripheral["signals"].items() +%% if not index_list + struct {{ signal }} {}; +%% else + template + struct {{ signal }}; +%% endif +%% endfor + }; + +%% endfor +}; + +%% for name, peripheral in peripherals.items() +%% if "instances" in peripheral +%% for instance in peripheral["instances"] +%% for signal, index_list in peripheral["signals"].items() +%% if index_list +%% for index in index_list +template<> template<> +struct Peripherals::{{ name }}<{{ instance }}>::{{ signal }}<{{ index }}> {}; +%% endfor +%% else +template<> +struct Peripherals::{{ name }}<{{ instance }}>::{{ signal }} {}; +%% endif +%% endfor +%% endfor +%% else +%% for signal, index_list in peripheral["signals"].items() +%% for index in index_list +template<> +struct Peripherals::{{ name }}::{{ signal }}<{{ index }}> {}; +%% endfor +%% endfor +%% endif +%% endfor + + +enum class PortName +{ + A, + B, +}; + +template +class Gpio; + +%% for gpio in gpios +namespace gpio { +struct {{ gpio["port"] ~ gpio["pin"] }} +{ + static constexpr PortName port = PortName::{{ gpio["port"] }}; + static constexpr uint32_t pin = {{ gpio["pin"] | int }}; + +%% for signal in gpio["signal"] + struct {{ signal["full_name"] }} + { + static constexpr PinFunction function{PinFunction::{{ signal["function"] }}}; + %% if "instance" in signal + using peripheral = Peripherals::{{ signal["peripheral"] }}<{{ signal["instance"] }}>; + %% else + using peripheral = Peripherals::{{ signal["peripheral"] }}; + %% endif + %% if "index" in signal + using signal = peripheral::{{ signal["name"] }}<{{ signal["index"] }}>; + %% else + using signal = peripheral::{{ signal["name"] }}; + %% endif + }; +%% endfor + + using Signals = + std::tuple< +%% for signal in gpio["signal"] + {{ signal["full_name"] }}{{ ">;" if loop.last else ","}} +%% endfor +}; +} // namespace gpio +using Gpio{{ gpio["port"] ~ gpio["pin"] }} = Gpio; + +%% endfor + +} // namespace modm::platform diff --git a/src/modm/platform/gpio/sam/connector.hpp b/src/modm/platform/gpio/sam/connector.hpp new file mode 100644 index 0000000000..89400f7c2e --- /dev/null +++ b/src/modm/platform/gpio/sam/connector.hpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2020, Erik Henriksson + * + * 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/. + */ +// ---------------------------------------------------------------------------- + +#pragma once + +#include "pin.hpp" + +namespace modm +{ + +namespace platform +{ + +// For backwards compability. +using Peripheral = PeripheralPin; + +// GpioConnector only exists for backwards compability with bitbang API. +template class... Signals> +struct GpioConnector +{ + template + static constexpr bool Contains = true; + + inline static void connect() {} + inline static void disconnect() {} +}; + +} // namespace platform + +} // namespace modm \ No newline at end of file diff --git a/src/modm/platform/gpio/sam/module.lb b/src/modm/platform/gpio/sam/module.lb index 15e2ab7e06..35d5650f0f 100644 --- a/src/modm/platform/gpio/sam/module.lb +++ b/src/modm/platform/gpio/sam/module.lb @@ -15,48 +15,6 @@ import copy from collections import defaultdict, OrderedDict -def port_ranges(gpios): - ports = {p: (32, 0) for p in set(p["port"] for p in gpios)} - for gpio in gpios: - pin = int(gpio["pin"]) - pmin, pmax = ports[gpio["port"]] - ports[gpio["port"]] = (min(pin, pmin), max(pin, pmax)) - - ports = [{"name": k.upper(), "start": v[0], "width": v[1] - v[0] + 1} for k,v in ports.items()] - 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, - "function": s["function"] if len(s["function"]) == 1 else None - } - return afs - -bprops = {} - -# ----------------------------------------------------------------------------- def init(module): module.name = ":platform:gpio" module.description = "General Purpose I/O (GPIO)" @@ -76,55 +34,51 @@ 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 [] - gpio["signal"] = raw_signals - extracted_signals = extract_signals(raw_signals) - gpio["pmux"] = "PMUXO" if int(gpio["pin"]) % 2 else "PMUXE" - 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]) - extints = sorted({"pin": signal["name"][6:], "function": signal["function"]} for signal in raw_signals if signal["name"].startswith("extint")) - bprops[key] = { - "gpio": gpio, - "signals": extracted_signals, - "extints": extints - } - - 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): + bprops = env.substitutions device = env[":target"] driver = device.get_driver("gpio") - bprops["ranges"] = port_ranges(driver["gpio"]) - bprops["ports"] = OrderedDict([(k, i) for i, k in enumerate([p["name"] for p in bprops["ranges"]])]) - - properties = {"target": device.identifier} - properties.update(bprops) - - env.substitutions = properties - env.outbasepath = "modm/src/modm/platform/gpio" + peripherals = OrderedDict() for gpio in driver["gpio"]: - po, pi = gpio["port"], gpio["pin"] - 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") - env.template("base.hpp.in") - env.template("software_port.hpp.in") - env.template("unused.hpp.in") - - env.copy("../common/inverted.hpp", "inverted.hpp") - env.copy("../common/connector.hpp", "connector.hpp") - env.template("../common/connector_detail.hpp.in", "connector_detail.hpp") + signals = [] + for signal in gpio["signal"]: + signal.update({ + "peripheral": signal["driver"].capitalize(), + "function": signal["function"].capitalize(), + "name": signal["name"].capitalize(), + }) + # This is a hack for L variant devices, which have a Ac without instance *and* + # a Ac with instance 1. Why??? + if (device.identifier.get("variant") == "l" + and signal["peripheral"] == "Ac" + and (not "instance" in signal or signal["instance"] == "")): + signal["instance"] = "0" + signal["full_name"] = signal["peripheral"] + peripheral = peripherals.setdefault(signal["peripheral"], dict()) + if "instance" in signal: + signal["full_name"] += signal["instance"] + signal["instance"] = int(signal["instance"]) + peripheral.setdefault("instances", set()).add(signal["instance"]) + signal["full_name"] += signal["name"] + p_signal = peripheral.setdefault("signals", dict()).setdefault(signal["name"], set()) + if "index" in signal: + signal["full_name"] += signal["index"] + signal["index"] = int(signal["index"]) + p_signal.add(signal["index"]) + signals.append(signal) + gpio["signal"] = signals + + bprops["peripherals"] = OrderedDict(sorted(peripherals.items())) + bprops["functions"] = sorted(list(set(s["function"] for gpio in driver["gpio"] for s in gpio["signal"]))) + + bprops["target"] = device.identifier + + env.substitutions = bprops + env.outbasepath = "modm/src/modm/platform/gpio" - # FIXME: Move to modm:platform:core! - env.outbasepath = "modm/src/modm/platform/core" - env.template("peripherals.hpp.in") + bprops["gpios"] = driver["gpio"] + env.template("config.hpp.in") + env.copy("connector.hpp") + env.copy("pin.hpp") + env.copy("unused.hpp") diff --git a/src/modm/platform/gpio/sam/module.md b/src/modm/platform/gpio/sam/module.md new file mode 100644 index 0000000000..c120c074bf --- /dev/null +++ b/src/modm/platform/gpio/sam/module.md @@ -0,0 +1,76 @@ +# SAM Signals API + +This module provides a way to use the GPIO pins of the SAM device. The raw +GPIO API is defined with the following goals: + +- Zero-cost compared to assembly +- Statically type checked +- Aligned (to the extent possible) with other modm platforms + +Additionally, it also provides the Connection API which sets up the wiring +between GPIO pins and peripherals. Given how flexible SAM is, it is a challenge +to make this completely statically type checked. + +The Connection API was designed with the following goals: + +- Compilaton errors are understandable (contain necessary information about the context that lead to the error). +- Completely in C++ templates, allows peripherals to perform further validation. +- Allows the user to select the intended peripheral signal (e.g. TX, SCK, MOSI, SDA). +- Deduces the pin function at compile time +- Deduces the Peripheral pad at compile time (e.g. Sercom Pad) + +As a few examples, the following situations will crash compilation: + +- Usage of drivers which don't exist on the pin +- Passing a pin which has a connection to the driver but not the correct instance +- Passing a pin which connects to the driver/instance but not the correct Peripheral signal +- Using multiple signals from the same pin in a *single* Peripheral +- Using the same signal from multiple pins in a *single* Peripheral + +!!! warning "The Connection API cannot check whether signals between multiple Peripherals overlap or not. + This will be the case if you e.g. try to instantiate Sercom0 as both UART and SPI bus, or use a single + pin for multiple different peripherals at the same time." + +## Usage examples + +### Toggle the A01 pin + +```cpp +Gpio::toggle(); +``` + +This compiles to the following on SAMD21 (4 clock cycles): + +```asm +2232: 2580 movs r5, #128 ; 0x80 +2238: 4c03 ldr r4, [pc, #12] ; (2248 ) +223a: 02ad lsls r5, r5, #10 +223e: 6025 str r5, [r4, #0] +2248: 41005200 .word 0x41005200 +``` + +### Toggle the A01 and A02 pins together + +```cpp +GpioSet::toggle(); +``` + +The assembly will look similar to the single pin example above. If you look carefully, you will +find that `Gpio` is actually using the `toggle()` method from `GpioSet`! + +### Connect A01 pin to the UART1 TX pin + +!!! note "Should normally be done by the UART peripheral!" + +```cpp +using Sercom = Peripherals::Sercom<1>; +using Conn = Gpio::Tx::Connector, Sercom::Pad<2>>; +Conn::::connect(); +``` + +Validate the signal name used for the connection: + +```cpp +static_assert(std::is_same_v, Conn::Signal>>, "wrong!"); +``` + diff --git a/src/modm/platform/gpio/sam/peripherals.hpp.in b/src/modm/platform/gpio/sam/peripherals.hpp.in deleted file mode 100644 index 6afb0f00dd..0000000000 --- a/src/modm/platform/gpio/sam/peripherals.hpp.in +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2019, Niklas Hauser - * Copyright (c) 2020, Erik Henriksson - * - * 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/. - */ -// ---------------------------------------------------------------------------- - -#pragma once - -namespace modm::platform -{ - -enum class -Peripheral -{ - BitBang, -%% for per in all_peripherals - {{ per }}, -%% endfor -}; - -} diff --git a/src/modm/platform/gpio/sam/pin.hpp b/src/modm/platform/gpio/sam/pin.hpp new file mode 100644 index 0000000000..4f31895cc2 --- /dev/null +++ b/src/modm/platform/gpio/sam/pin.hpp @@ -0,0 +1,362 @@ +/* + * Copyright (c) 2017-2018, Niklas Hauser + * Copyright (c) 2020, Erik Henriksson + * + * 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/. + */ +// ---------------------------------------------------------------------------- + +#pragma once + +#include + +#include "../device.hpp" +#include "config.hpp" +#include "modm/architecture/interface.hpp" + +namespace modm::platform +{ + +enum class InputType +{ + Floating = 0x0, ///< floating on input + PullUp = 0x1, ///< pull-up on input + PullDown = 0x2, ///< pull-down on input +}; + +enum class OutputType +{ + PushPull = 0x0, ///< push-pull on output + OpenDrain = 0x1, ///< open-drain on output +}; + +enum class OutputSpeed +{ + Low = 0, + Medium = 0x1, + High = 0x2, + VeryHigh = 0x3, ///< 30 pF (80 MHz Output max speed on 15 pF) + MHz2 = Low, + MHz25 = Medium, + MHz50 = High, + MHz100 = VeryHigh, +}; + +enum class PeripheralPin +{ + BitBang, + Rx, + Tx, + ExtInt, + Dm, + Dp, + Wo, +}; + +template +using tuple_cat_t = decltype(std::tuple_cat(std::declval()...)); + +template +struct tuple_filter; + +template +using tuple_filter_t = typename tuple_filter::type; + +// Recursive case +template +struct tuple_filter> +{ + using type = + std::conditional_t, + tuple_cat_t, tuple_filter_t>>, + tuple_filter_t>>; +}; + +// Base case +template +struct tuple_filter> +{ + using type = std::tuple<>; +}; + +template +struct EqualsPeripheral +{ + template + static constexpr bool value = std::is_same_v; +}; + +template +struct EqualsSignal +{ + template + static constexpr bool value = std::is_same_v; +}; + +template +struct OneOfSignals +{ + template + static constexpr bool value = ((std::is_same_v) | ...); +}; + +template +struct PinCfgMixin +{ + inline static void set(uint8_t){}; +}; + +template +struct PinCfgMixin +{ + inline static void + set(uint8_t cfg) + { + if constexpr (PinConfig::port == PortName::A) + { + PORT->Group[0].PINCFG[PinConfig::pin].reg = cfg; + } else if constexpr (PinConfig::port == PortName::B) + { + PORT->Group[1].PINCFG[PinConfig::pin].reg = cfg; + } + PinCfgMixin::set(cfg); + } +}; + +template +class GpioSet : protected PinCfgMixin +{ +protected: + using PinCfg = PinCfgMixin; + + static constexpr uint32_t + mask(PortName port) + { + return (((PinConfigs::port == port) ? 1u << PinConfigs::pin : 0u) | ...); + } + + inline static constexpr uint32_t* + getPortReg(size_t offset) + { + return (uint32_t*)(&PORT->Group[0]) + offset / sizeof(uint32_t); + } + + inline static constexpr void + setPortReg(size_t offset) + { + if constexpr (mask(PortName::A) != 0) { *getPortReg(offset) = mask(PortName::A); } + if constexpr (mask(PortName::B) != 0) { *getPortReg(offset) = mask(PortName::B); } + } + + template + inline static constexpr uint32_t + readPortReg(size_t offset) + { + if constexpr (port == PortName::A) + { + static_assert(mask(PortName::A) != 0, + "Trying to read port which is not in the GpioSet!"); + return *getPortReg(offset) & mask(PortName::A); + } else if constexpr (port == PortName::B) + { + static_assert(mask(PortName::B) != 0, + "Trying to read port which is not in the GpioSet!"); + return *getPortReg(offset) & mask(PortName::A); + } + } + +public: + inline static void + setOutput() + { + setPortReg(PORT_DIRSET_OFFSET); + } + + inline static void + setOutput(bool status) + { + setOutput(); + set(status); + } + + static void setOutput(OutputType, OutputSpeed) { setOutput(); } + + static void configure(OutputType, OutputSpeed = OutputSpeed::MHz50) {} + + static void + setInput() + { + setPortReg(PORT_DIRCLR_OFFSET); + } + + static void + setInput(InputType type) + { + configure(type); + setInput(); + } + + static void + configure(InputType type) + { + set(type == InputType::PullUp); + PinCfg::set(PORT_PINCFG_INEN | (type != InputType::Floating) << PORT_PINCFG_PULLEN_Pos); + } + + static void + setAnalogInput() + {} + + static void + set() + { + setPortReg(PORT_OUTSET_OFFSET); + } + + static void + set(bool status) + { + if (status) + set(); + else + reset(); + } + + static void + reset() + { + setPortReg(PORT_OUTCLR_OFFSET); + } + + static void + toggle() + { + setPortReg(PORT_OUTTGL_OFFSET); + } + + static void + disconnect() + { + setInput(InputType::Floating); + } +}; + +template +class Gpio : public GpioSet, public ::modm::GpioIO +{ + using Base = GpioSet; + +public: + // For backwards compability with bitbang API + using InputType = ::modm::platform::InputType; + using OutputType = ::modm::platform::OutputType; + + template + struct As; + + using Rx = As; + using Tx = As; + using ExtInt = As; + using Dm = As; + using Dp = As; + + inline static bool + read() + { + return Base::readPortReg(PORT_IN_OFFSET); + } + + inline static void + write(bool status) + { + Base::set(status); + } +}; + +template +template +struct Gpio::As : public Gpio +{ + static constexpr PeripheralPin peripheral_pin = peripheral_pin_v; + using Base = Gpio; + + template + struct ValidatePeripheral + { + using type = tuple_filter_t, Signals>; + static_assert(!std::is_same_v>, + "Gpio pin does not connect to this peripheral! (see above)"); + }; + + template + struct ValidateSignal + { + using type = tuple_filter_t, Signals>; + static_assert(!std::is_same_v>, + "Gpio pin does not connect to any of the required signals! " + "(see above)"); + }; + + template + struct GetSingleSignal + { + using crash = typename Signals::errorPeripheralInstanceMatchedMoreThanOneSignal; + }; + + template + struct GetSingleSignal> + { + using type = Signal; + }; + + template + struct Connector + { + using ValidatedPeripheral = + typename ValidatePeripheral::type; + using ValidatedSignals = + typename ValidateSignal::type; + using PinSignal = typename GetSingleSignal::type; + using Signal = typename PinSignal::signal; + + inline static void + connect() + { + Base::PinCfg::set(PORT_PINCFG_PMUXEN); + if constexpr (PinConfig::pin & 1u) + { + PORT->Group[uint32_t(PinConfig::port)].PMUX[PinConfig::pin >> 1].bit.PMUXO = + uint32_t(PinSignal::function); + } else + { + PORT->Group[uint32_t(PinConfig::port)].PMUX[PinConfig::pin >> 1].bit.PMUXE = + uint32_t(PinSignal::function); + } + } + }; +}; + +template +struct GetPin; + +template +using GetPin_t = typename GetPin::type; + +template +struct GetPin +{ + using type = typename std::conditional_t>; +}; + +template +struct GetPin +{ + using type = void; +}; + +} // namespace modm::platform diff --git a/src/modm/platform/gpio/sam/pin.hpp.in b/src/modm/platform/gpio/sam/pin.hpp.in deleted file mode 100644 index 47ae68d3c3..0000000000 --- a/src/modm/platform/gpio/sam/pin.hpp.in +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright (c) 2017-2018, Niklas Hauser - * Copyright (c) 2020, Erik Henriksson - * - * 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/. - */ -// ---------------------------------------------------------------------------- - -%% set port = gpio.port | upper -%% set reg = "GPIO" ~ port -%% set pin = gpio.pin -%% set pnr = gpio.port | modm.ord - -#pragma once - -#include "../device.hpp" -#include "base.hpp" -#include "set.hpp" - -namespace modm::platform -{ - -/// @cond -class Gpio{{ port ~ pin }}; -using GpioOutput{{ port ~ pin }} = Gpio{{ port ~ pin }}; -using GpioInput{{ port ~ pin }} = Gpio{{ port ~ pin }}; -/// @endcond - -/// IO class for Pin {{port ~ pin}} -/// @ingroup modm_platform_gpio -class Gpio{{ port ~ pin }} : public Gpio, public ::modm::GpioIO -{ - template - friend class GpioSet; - using PinSet = GpioSet; - friend class Adc; - friend class Adc1; friend class Adc2; - friend class Adc3; friend class Adc4; - template friend class ExtInt; -public: - using Output = Gpio{{ port ~ pin }}; - using Input = Gpio{{ port ~ pin }}; - using IO = Gpio{{ port ~ pin }}; - using Type = Gpio{{ port ~ pin }}; - static constexpr bool isInverted = false; - static constexpr PortName port = PortName::{{port}}; ///< Port name - static constexpr uint8_t pin = {{pin|int}}; ///< Pin number - -protected: - /// Bitmask for registers that contain a 1bit value for every pin. - static constexpr uint32_t mask = 1ul << pin; - /// Bitmask for registers that contain a 2bit value for every pin. - // static constexpr uint32_t mask2 = 0x3 << (pin * 2); - /// Port Number. - static constexpr uint8_t port_nr = uint8_t(port); - /// Alternate Function register id. 0 for pin 0-7. 1 for pin 8-15. - // static constexpr uint8_t af_id = pin / 8; - /// Alternate Function offset. - // static constexpr uint8_t af_offset = (pin * 4) % 32; - /// Alternate Function register mask. - // static constexpr uint32_t af_mask = 0xf << af_offset; - -public: - /// @cond - inline static void setAlternateFunction(uint8_t) { - // {{reg}}->AFR[af_id] = ({{reg}}->AFR[af_id] & ~af_mask) | ((af & 0xf) << af_offset); - // {{reg}}->MODER = ({{reg}}->MODER & ~mask2) | (i(Mode::AlternateFunction) << (pin * 2)); - } - - /// Enable Analog Mode which is needed to use this pin as an ADC input. - inline static void setAnalogInput() { PinSet::setAnalogInput(); } - /// @endcond - -public: - // GpioOutput - // start documentation inherited - inline static void setOutput() { PinSet::setOutput(); } - inline static void setOutput(bool status) { PinSet::setOutput(status); } - inline static void set() { PinSet::set(); } - inline static void set(bool status) { PinSet::set(status); } - inline static void reset() { PinSet::reset(); } - inline static void toggle() { - if (isSet()) { reset(); } - else { set(); } - } - inline static bool isSet() { return (REG_PORT_OUT{{pnr}} & mask); } - // stop documentation inherited - inline static void configure(OutputType type, OutputSpeed speed = OutputSpeed::MHz50) { PinSet::configure(type, speed); } - inline static void setOutput(OutputType type, OutputSpeed speed = OutputSpeed::MHz50) { PinSet::setOutput(type, speed); } - // GpioInput - // start documentation inherited - inline static void setInput() { PinSet::setInput(); } - inline static bool read() { return (REG_PORT_IN{{pnr}} & mask); } - // end documentation inherited - inline static void configure(InputType type) { PinSet::configure(type); } - inline static void setInput(InputType type) { PinSet::setInput(type); } - // GpioIO - // start documentation inherited - inline static Direction getDirection() { - if (REG_PORT_DIR{{pnr}} & mask) - return Direction::In; - return Direction::Out; - } - // end documentation inherited - 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 - -protected: - %% for extint in extints - template< int instance > - inline static void connectInterrupt() { - static_assert( - instance == {{ extint.pin }}, - "Gpio{{ port ~ pin }} only connects to ExtInt<{{ extint.pin }}>"); - PORT->Group[uint32_t(port)].PINCFG[uint32_t(pin)].bit.PMUXEN = true; - PORT->Group[uint32_t(port)].PMUX[uint32_t(pin) >> 1].bit.{{ gpio.pmux }} = PORT_PMUX_{{ gpio.pmux }}_{{ extint.function | upper }}_Val; - } - %% endfor -}; - -/// @cond -template<> -struct Gpio{{ port ~ pin }}::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 }} -{ - using Gpio = Gpio{{ port ~ pin }}; - static constexpr Gpio::Signal Signal = Gpio::Signal::{{ signal.name }}; - inline static void - connect() - { - %% if signal.function - PORT->Group[uint32_t(port)].PINCFG[uint32_t(pin)].bit.PMUXEN = true; - PORT->Group[uint32_t(port)].PMUX[uint32_t(pin) >> 1].bit.{{ gpio.pmux }} = PORT_PMUX_{{ gpio.pmux }}_{{ signal.function | upper }}_Val; - %% endif - } -}; - - %% endfor - -%% endfor - - -/// @endcond - -} // namespace modm::platform diff --git a/src/modm/platform/gpio/sam/set.hpp.in b/src/modm/platform/gpio/sam/set.hpp.in deleted file mode 100644 index d763eb8b7d..0000000000 --- a/src/modm/platform/gpio/sam/set.hpp.in +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (c) 2018, Niklas Hauser - * - * 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/. - */ -// ---------------------------------------------------------------------------- - -#ifndef MODM_STM32_GPIO_SET_HPP -#define MODM_STM32_GPIO_SET_HPP - -#include "../device.hpp" -#include "base.hpp" - -namespace modm -{ - -namespace platform -{ - -/// @ingroup modm_platform_gpio -template< class... Gpios > -class GpioSet : public Gpio -{ -protected: - static constexpr uint32_t inverteds[{{ ports | length }}] = { -%% for port in ports - (((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 == PortName::{{port}}) ? Gpios::mask : 0) | ...), -%% endfor - }; - static constexpr uint32_t mask(uint8_t id) { return masks[id]; } - static constexpr uint8_t numberOfPorts() { - uint8_t r{0}; - for (const auto &m: masks) r += (m) ? 1 : 0; - return r; - } - static constexpr PORT_PINCFG_Type *configs[] = - {(PORT_PINCFG_Type*) &PORT->Group[uint32_t(Gpios::port)].PINCFG[uint32_t(Gpios::pin)] ...}; -public: - static constexpr uint8_t width = sizeof...(Gpios); - static constexpr uint8_t number_of_ports = numberOfPorts(); -public: - static void setOutput() - { - %% for port, id in ports.items() - if constexpr (mask({{id}})) REG_PORT_DIRSET{{id}} = mask({{id}}); - %% endfor - } - - static void setOutput(bool status) - { - set(status); - setOutput(); - } - - static void setOutput(OutputType, OutputSpeed) - { - setOutput(); - } - - static void configure(OutputType , OutputSpeed = OutputSpeed::MHz50) - { - } - - static void setInput() - { - %% for port, id in ports.items() - if constexpr (mask({{id}})) { - REG_PORT_DIRCLR{{id}} = mask({{id}}); - } - %% endfor - } - - static void setInput(InputType type) - { - configure(type); - setInput(); - } - - static void configure(InputType type) - { - for (PORT_PINCFG_Type* config : configs) { - set(type == InputType::PullUp); - config->reg = - PORT_PINCFG_INEN | - (type != InputType::Floating) << PORT_PINCFG_PULLEN_Pos; - } - } - - static void setAnalogInput() - { - } - - static void set() - { -%% for port, id in ports.items() - if constexpr (mask({{id}})) REG_PORT_OUTSET{{id}} = mask({{id}}); -%% endfor - } - - static void set(bool status) - { - if (status) set(); - else reset(); - } - - static void reset() - { -%% for port, id in ports.items() - if constexpr (mask({{id}})) REG_PORT_OUTCLR{{id}} = mask({{id}}); -%% endfor - } - - static void toggle() - { -%% for port, id in ports.items() - if constexpr (mask({{id}})) REG_PORT_OUTTGL{{id}} = mask({{id}}); -%% endfor - } - - static void disconnect() - { - // (Gpios::disconnect(), ...); - } -}; - -} // namespace platform - -} // namespace modm - -#endif // MODM_STM32_GPIO_SET_HPP diff --git a/src/modm/platform/gpio/sam/software_port.hpp.in b/src/modm/platform/gpio/sam/software_port.hpp.in deleted file mode 100644 index 6e1a06a985..0000000000 --- a/src/modm/platform/gpio/sam/software_port.hpp.in +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2018, Niklas Hauser - * - * 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/. - */ -// ---------------------------------------------------------------------------- - -#ifndef MODM_STM32_GPIO_SOFTWARE_PORT_HPP -#define MODM_STM32_GPIO_SOFTWARE_PORT_HPP - -#include "set.hpp" -#include - -namespace modm -{ - -namespace platform -{ - -/** - * Create an up to 32-bit port from arbitrary pins. - * - * This class optimizes the data type for the `read()` and `write()` methods. - * Supplying up to 8 Gpios will use `uint8_t`, up to 16 Gpios `uint16_t` and - * up to 32 Gpios `uint32_t`. - * - * @note Since the bit order is explicitly given by the order of template arguments, - * this class only supports `DataOrder::Normal`. - * If you need reverse bit order, reverse the order of `Gpios`! - * - * @tparam Gpios Up to 32 GpioIO classes, ordered MSB to LSB - * - * @author Niklas Hauser - * @ingroup modm_platform_gpio - */ -template< class... Gpios > -class SoftwareGpioPort : public ::modm::GpioPort, public GpioSet -{ - using Set = GpioSet; -public: - using Set::width; - static_assert(width <= 32, "Only a maximum of 32 pins are supported by this Port!"); - using PortType = std::conditional_t< (width > 8), - std::conditional_t< (width > 16), - uint32_t, - uint16_t >, - uint8_t >; - static constexpr DataOrder getDataOrder() - { return ::modm::GpioPort::DataOrder::Normal; } - -protected: - static constexpr int8_t shift_masks[{{ ports | length }}][width] = { -%% for port in ports - {(Gpios::port == Set::Port::{{port}} ? Gpios::pin : -1)...}, -%% endfor - }; - static constexpr int8_t shift_mask(uint8_t id, uint8_t pos) { return shift_masks[id][width - 1 - pos]; } - using Set::mask; - using Set::inverted; - -public: - static PortType isSet() - { - PortType r{0}; - // FIXME: Implement - return r; - } - - static void write(PortType data) - { - // FIXME: Implement - } - - static PortType read() - { - PortType r{0}; - // FIXME: Implement - return r; - } -}; - -} // namespace platform - -} // namespace modm - -#endif // MODM_STM32_GPIO_SOFTWARE_PORT_HPP diff --git a/src/modm/platform/gpio/sam/unused.hpp.in b/src/modm/platform/gpio/sam/unused.hpp similarity index 76% rename from src/modm/platform/gpio/sam/unused.hpp.in rename to src/modm/platform/gpio/sam/unused.hpp index d6acaacdcf..64011c5c55 100644 --- a/src/modm/platform/gpio/sam/unused.hpp.in +++ b/src/modm/platform/gpio/sam/unused.hpp @@ -11,9 +11,10 @@ #pragma once -#include "base.hpp" #include +#include "pin.hpp" + namespace modm::platform { @@ -21,7 +22,7 @@ namespace modm::platform * @author Niklas Hauser * @ingroup modm_platform_gpio */ -class GpioUnused : public Gpio, public ::modm::GpioIO +class GpioUnused : public ::modm::GpioIO { public: using Output = GpioUnused; @@ -60,15 +61,6 @@ class GpioUnused : public Gpio, public ::modm::GpioIO // end documentation inherited static void configure(InputType) {} static void setInput(InputType) {} - // External Interrupts - static void enableExternalInterrupt() {} - static void disableExternalInterrupt() {} - static void enableExternalInterruptVector(const uint32_t) {} - static void disableExternalInterruptVector() {} - static void setInputTrigger(const InputTrigger) {} - static bool getExternalInterruptFlag() { return false; } - /// Reset the interrupt flag in the interrupt routine. - static void acknowledgeExternalInterruptFlag() {} // GpioIO // start documentation inherited @@ -78,4 +70,4 @@ class GpioUnused : public Gpio, public ::modm::GpioIO static void disconnect() {} }; -} // namespace modm::platform +} // namespace modm::platform diff --git a/src/modm/platform/i2c/bitbang/bitbang_i2c_master_impl.hpp b/src/modm/platform/i2c/bitbang/bitbang_i2c_master_impl.hpp index 5b232d4c3e..ae89d68702 100644 --- a/src/modm/platform/i2c/bitbang/bitbang_i2c_master_impl.hpp +++ b/src/modm/platform/i2c/bitbang/bitbang_i2c_master_impl.hpp @@ -5,6 +5,7 @@ * Copyright (c) 2013, David Hebbeker * Copyright (c) 2013, Kevin Läufer * Copyright (c) 2014, Sascha Schade + * Copyright (c) 2020, Erik Henriksson * * This file is part of the modm project. * @@ -66,8 +67,8 @@ modm::platform::BitBangI2cMaster::connect(PullUps pullups) static_assert(sizeof...(Signals) == 2, "BitBangI2cMaster::connect() requires one Scl and one Sda signal!"); static_assert(Connector::template Contains and Connector::template Contains, "BitBangI2cMaster can only connect to the same Scl and Sda signals of the declaration!"); - const Gpio::InputType input = - (pullups == PullUps::Internal) ? Gpio::InputType::PullUp : Gpio::InputType::Floating; + const typename SCL::InputType input = + (pullups == PullUps::Internal) ? SCL::InputType::PullUp : SCL::InputType::Floating; Connector::disconnect(); SCL::configure(input); diff --git a/src/modm/platform/spi/bitbang/bitbang_spi_master_impl.hpp b/src/modm/platform/spi/bitbang/bitbang_spi_master_impl.hpp index b33ee5be7e..d0e77b3185 100644 --- a/src/modm/platform/spi/bitbang/bitbang_spi_master_impl.hpp +++ b/src/modm/platform/spi/bitbang/bitbang_spi_master_impl.hpp @@ -4,6 +4,7 @@ * Copyright (c) 2012-2017, Niklas Hauser * Copyright (c) 2014, Sascha Schade * Copyright (c) 2018, Raphael Lehmann + * Copyright (c) 2020, Erik Henriksson * * This file is part of the modm project. * @@ -53,9 +54,9 @@ modm::platform::BitBangSpiMaster::connect() "BitBangSpiMaster can only connect to the same Sck, Mosi and Miso signals of the declaration!"); // Connector::disconnect(); - Sck::setOutput(Gpio::OutputType::PushPull); - Mosi::setOutput(Gpio::OutputType::PushPull); - Miso::setInput(Gpio::InputType::Floating); + Sck::setOutput(Sck::OutputType::PushPull); + Mosi::setOutput(Mosi::OutputType::PushPull); + Miso::setInput(Miso::InputType::Floating); Connector::connect(); } diff --git a/src/modm/platform/uart/sam/uart.hpp.in b/src/modm/platform/uart/sam/uart.hpp.in index c57bf4fea9..1f7fbd7682 100644 --- a/src/modm/platform/uart/sam/uart.hpp.in +++ b/src/modm/platform/uart/sam/uart.hpp.in @@ -22,9 +22,9 @@ #pragma once #include -#include #include "uart_base.hpp" #include "uart_hal_{{ id }}.hpp" +#include namespace modm { @@ -41,19 +41,31 @@ namespace platform */ class {{ name }} : public UartBase, public ::modm::Uart { + + // Separate because that makes GCC print the template args. + template + struct ValidateNotSame { + static_assert( + !std::is_same_v, + "Rx and Tx cannot use the same signal!"); + }; + public: - template< template class RxPin, template class TxPin > + template< class... Pins > static void connect() { - using Connector = GpioConnector; - using Rx = typename Connector::template GetSignal< Gpio::Signal::Pad3 >; - using Tx = typename Connector::template GetSignal< Gpio::Signal::Pad2 >; - static_assert(Connector::template IsValid, - "{{ name }}::connect() requires Rx on {{ sercom }}Pad3"); - static_assert(Connector::template IsValid, - "{{ name }}::connect() requires Tx on {{ sercom }}Pad2"); - Connector::connect(); + using RxPin = GetPin_t; + using TxPin = GetPin_t; + static_assert( + !std::is_same_v, + "Rx and Tx cannot use the same pin!"); + using Sercom = Peripherals::Sercom<{{ id | int }}>; + using RxConnector = typename RxPin::template Connector, Sercom::Pad<1>, Sercom::Pad<2>, Sercom::Pad<3>>; + using TxConnector = typename TxPin::template Connector, Sercom::Pad<2>>; + ValidateNotSame {}; + RxConnector::connect(); + TxConnector::connect(); } template< class SystemClock, baudrate_t baudrate, percent_t tolerance=pct(1) > diff --git a/src/modm/platform/uart/sam/uart_hal.hpp.in b/src/modm/platform/uart/sam/uart_hal.hpp.in index b189ac89a7..243fc2a8b3 100644 --- a/src/modm/platform/uart/sam/uart_hal.hpp.in +++ b/src/modm/platform/uart/sam/uart_hal.hpp.in @@ -18,7 +18,6 @@ #include "../device.hpp" #include "uart_base.hpp" #include "modm/platform/clock/gclk.hpp" -#include "modm/platform/core/peripherals.hpp" namespace modm { diff --git a/src/modm/platform/usb/sam/usb.hpp b/src/modm/platform/usb/sam/usb.hpp index cadc08d422..d8f7dd9364 100644 --- a/src/modm/platform/usb/sam/usb.hpp +++ b/src/modm/platform/usb/sam/usb.hpp @@ -32,17 +32,19 @@ class Usb NVIC_SetPriority(USB_IRQn, priority); } - template< template class... Signals > + template static void connect() { - using Connector = GpioConnector; - using Dp = typename Connector::template GetSignal< Gpio::Signal::Dp >; - using Dm = typename Connector::template GetSignal< Gpio::Signal::Dm >; - static_assert(((Connector::template IsValid and Connector::template IsValid) and sizeof...(Signals) == 2), - "Usb::connect() requires one Dp and one Dm signal!"); - - Connector::connect(); + using DpPin = GetPin_t; + using DmPin = GetPin_t; + static_assert(!std::is_same_v, + "Dp and Dm cannot use the same pin!"); + using Usb = Peripherals::Usb; + using DpConnector = typename DpPin::template Connector; + using DmConnector = typename DmPin::template Connector; + DpConnector::connect(); + DmConnector::connect(); } };